Merge branch 'master' into get-store
This commit is contained in:
@@ -102,7 +102,7 @@ func (c *OrderManager) SaveOrderFinancialInfo(order *model.OrderFinancial, opera
|
||||
}
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
@@ -120,7 +120,7 @@ func (c *OrderManager) SaveOrderFinancialInfo(order *model.OrderFinancial, opera
|
||||
sku.JxShopMoney = order.JxShopMoney - sku.JxShopMoney
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
|
||||
@@ -2,7 +2,6 @@ package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
"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/msghub"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
@@ -51,7 +49,8 @@ func (c *OrderManager) LoadPendingOrders() []*model.GoodsOrder {
|
||||
|
||||
// msgVendorStatus的意思是事件本身的类型,类似有时收到NewOrder事件去取,订单状态不一定就是New的
|
||||
// OnOrderAdjust也类似,而OrderStatus要记录的是消息,所以添加这个
|
||||
func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error) {
|
||||
func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
globals.SugarLogger.Debugf("OnOrderNew orderID:%s", order.VendorOrderID)
|
||||
if order.ConsigneeMobile2 == "" && !jxutils.IsMobileFake(order.ConsigneeMobile) {
|
||||
order.ConsigneeMobile2 = order.ConsigneeMobile
|
||||
}
|
||||
@@ -59,6 +58,7 @@ func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, msgVendorStatus strin
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
globals.SugarLogger.Debugf("OnOrderNew exit orderID:%s", order.VendorOrderID)
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
@@ -67,12 +67,7 @@ func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, msgVendorStatus strin
|
||||
if order.Status == model.OrderStatusUnknown {
|
||||
order.Status = model.OrderStatusNew
|
||||
}
|
||||
status := model.Order2Status(order)
|
||||
if status.Status > model.OrderStatusNew {
|
||||
status.Status = model.OrderStatusNew
|
||||
}
|
||||
status.VendorStatus = msgVendorStatus
|
||||
isDuplicated, err := addOrderOrWaybillStatus(status, db)
|
||||
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
|
||||
if err == nil && !isDuplicated {
|
||||
isDuplicated, err = c.SaveOrder(order, false, db)
|
||||
}
|
||||
@@ -88,7 +83,7 @@ func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, msgVendorStatus strin
|
||||
}
|
||||
|
||||
// todo 调整单的处理可能还需要再细化一点,当前只是简单的删除重建
|
||||
func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error) {
|
||||
func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
if order.ConsigneeMobile2 == "" && !jxutils.IsMobileFake(order.ConsigneeMobile) {
|
||||
order.ConsigneeMobile2 = order.ConsigneeMobile
|
||||
}
|
||||
@@ -101,13 +96,12 @@ func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus st
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if order.Status == model.OrderStatusUnknown {
|
||||
// 出现过调整单后,状态回到新订单状态,比如:911350836000622
|
||||
// 不完全确定,加一个处理
|
||||
if order.Status < model.OrderStatusAccepted {
|
||||
order.Status = model.OrderStatusAccepted
|
||||
}
|
||||
status := model.Order2Status(order)
|
||||
status.Status = model.OrderStatusAdjust
|
||||
status.VendorStatus = msgVendorStatus
|
||||
isDuplicated, err := addOrderOrWaybillStatus(status, db)
|
||||
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
|
||||
if err == nil && !isDuplicated {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Raw("DELETE FROM order_sku WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec()
|
||||
@@ -128,10 +122,9 @@ func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus st
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
if !isDuplicated {
|
||||
msghub.OnNewOrder(order)
|
||||
// 因为订单调度器需要的是真实状态,所以用order的状态
|
||||
_ = scheduler.CurrentScheduler.OnOrderNew(order, false)
|
||||
_ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, model.Order2Status(order), false)
|
||||
_ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false)
|
||||
}
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
@@ -171,7 +164,7 @@ func (c *OrderManager) OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark
|
||||
VendorStatus: vendorStatus,
|
||||
Status: model.OrderStatusMsg,
|
||||
StatusTime: time.Now(),
|
||||
Remark: remark,
|
||||
Remark: utils.LimitUTF8StringLen(remark, 255),
|
||||
}, nil)
|
||||
return err
|
||||
}
|
||||
@@ -207,11 +200,12 @@ func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao
|
||||
order.Status = orderStatus.Status
|
||||
order.VendorStatus = orderStatus.VendorStatus
|
||||
order.StatusTime = orderStatus.StatusTime
|
||||
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
order.OrderCreatedAt = order.StatusTime
|
||||
// globals.SugarLogger.Debugf("saveOrder isAdjust:%t, order:%v", isAdjust, order)
|
||||
created, _, err2 := db.Db.ReadOrCreate(order, "VendorOrderID", "VendorID")
|
||||
if err = err2; err == nil {
|
||||
@@ -223,22 +217,8 @@ func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao
|
||||
}
|
||||
if _, _, err = db.Db.ReadOrCreate(originalOrder, "VendorOrderID", "VendorID"); err == nil {
|
||||
if created {
|
||||
sql := `INSERT INTO order_sku(vendor_order_id, vendor_id, count, vendor_sku_id, sku_id, jx_sku_id, sku_name,
|
||||
shop_price, sale_price, weight, sku_type, promotion_type, order_created_at) VALUES`
|
||||
params := []interface{}{}
|
||||
for _, sku := range order.Skus {
|
||||
sql += "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?),"
|
||||
// 有时不是通过京西平台建立的SKU,不范围要超过
|
||||
skuID := 0
|
||||
if sku.SkuID < math.MaxInt32 {
|
||||
skuID = sku.SkuID
|
||||
}
|
||||
params = append(params, sku.VendorOrderID, sku.VendorID, sku.Count, sku.VendorSkuID, skuID, sku.JxSkuID, sku.SkuName,
|
||||
sku.ShopPrice, sku.SalePrice, sku.Weight, sku.SkuType, sku.PromotionType, order.OrderCreatedAt)
|
||||
}
|
||||
sql = sql[:len(sql)-1] + ";"
|
||||
if _, err = db.Db.Raw(sql, params...).Exec(); err != nil {
|
||||
baseapi.SugarLogger.Warnf("saveOrder insert order:%v, order_sku error:%v", order, err)
|
||||
if err = dao.CreateMultiEntities(db, order.Skus); err != nil {
|
||||
baseapi.SugarLogger.Warnf("saveOrder orderID:%s, save order_sku failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
} else {
|
||||
isDuplicated = true
|
||||
@@ -256,12 +236,35 @@ func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func getPromotionSkuPriceMap(db *dao.DaoDB, storeID int, skuIDs []int) (skuPriceMap map[int64]*model.PromotionSku, err error) {
|
||||
sql := `
|
||||
SELECT t3.*
|
||||
FROM promotion t1
|
||||
JOIN promotion_store t2 ON t2.promotion_id = t1.id AND t2.store_id = ?
|
||||
JOIN promotion_sku t3 ON t3.promotion_id = t1.id AND t3.sku_id IN (` + dao.GenQuestionMarks(len(skuIDs)) + `) AND t3.earning_price > 0
|
||||
WHERE t1.deleted_at = ? AND (t1.status = ? OR t1.status = ?) AND (t1.begin_at <= NOW() AND t1.end_at >= NOW()) AND t1.vendor_id = ?`
|
||||
var skuPriceList []*model.PromotionSku
|
||||
if err = dao.GetRows(db, &skuPriceList, sql, storeID, skuIDs, utils.DefaultTimeValue, model.PromotionStatusLocalCreated, model.PromotionStatusRemoteCreated, model.VendorIDJX); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
skuPriceMap = make(map[int64]*model.PromotionSku)
|
||||
for _, v := range skuPriceList {
|
||||
if v.EarningPrice > 0 {
|
||||
index := jxutils.Combine2Int(v.SkuID, v.Price)
|
||||
if skuPriceMap[index] == nil || v.EarningPrice < skuPriceMap[index].EarningPrice {
|
||||
skuPriceMap[index] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return skuPriceMap, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.DaoDB) (err error) {
|
||||
globals.SugarLogger.Debugf("updateOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
|
||||
jxStoreID := jxutils.GetShowStoreIDFromOrder(order)
|
||||
var opNumStr string
|
||||
if time.Now().Sub(order.OrderCreatedAt) < 48*time.Hour && order.VendorID != model.VendorIDJD {
|
||||
opNumStr = ""
|
||||
opNumStr = "2"
|
||||
} else {
|
||||
opNumStr = "2"
|
||||
}
|
||||
@@ -273,11 +276,16 @@ func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.
|
||||
orderSkus := order.Skus
|
||||
|
||||
vendorSkuIDs := make([]int64, 0)
|
||||
skuIDMap := make(map[int]int)
|
||||
for _, v := range orderSkus {
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 {
|
||||
vendorSkuIDs = append(vendorSkuIDs, intVendorSkuID)
|
||||
}
|
||||
|
||||
if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 {
|
||||
skuIDMap[skuID] = 1
|
||||
}
|
||||
}
|
||||
if len(vendorSkuIDs) > 0 {
|
||||
tableName := "t2"
|
||||
@@ -301,7 +309,16 @@ func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.
|
||||
skumapper[v.VendorSkuID] = v
|
||||
}
|
||||
|
||||
skuPriceMap, err2 := getPromotionSkuPriceMap(db, jxStoreID, jxutils.IntMap2List(skuIDMap))
|
||||
if err = err2; err != nil {
|
||||
globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku promotion info for orderID:%s, error:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, v := range orderSkus {
|
||||
v.VendorOrderID = order.VendorOrderID
|
||||
v.VendorID = order.VendorID
|
||||
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
|
||||
skuBindInfo := skumapper[intVendorSkuID]
|
||||
@@ -317,6 +334,13 @@ func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 && v.StoreSubName != "" {
|
||||
index := jxutils.Combine2Int(jxStoreID, int(v.SalePrice))
|
||||
if skuPriceMap[index] != nil {
|
||||
v.EarningPrice = int64(skuPriceMap[index].EarningPrice)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -336,11 +360,7 @@ func (c *OrderManager) updateOrderOtherInfo(order *model.GoodsOrder, db *dao.Dao
|
||||
}
|
||||
order.JxStoreID = storeMap.StoreID
|
||||
if err = c.updateOrderSkuOtherInfo(order, db); err == nil {
|
||||
if order.Weight == 0 {
|
||||
for _, v := range order.Skus {
|
||||
order.Weight += v.Weight
|
||||
}
|
||||
}
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -369,20 +389,21 @@ func (c *OrderManager) addOrderStatus(orderStatus *model.OrderStatus, db *dao.Da
|
||||
updateFields = append(updateFields, "Status", "StatusTime")
|
||||
if order.LockStatus != model.OrderStatusUnknown {
|
||||
order.LockStatus = model.OrderStatusUnknown
|
||||
order.LockStatusTime = orderStatus.StatusTime
|
||||
updateFields = append(updateFields, "LockStatus", "LockStatusTime")
|
||||
updateFields = append(updateFields, "LockStatus")
|
||||
}
|
||||
} else {
|
||||
if model.IsOrderUnlockStatus(orderStatus.Status) {
|
||||
order.LockStatus = model.OrderStatusUnknown
|
||||
} else {
|
||||
updateFields = append(updateFields, "LockStatus")
|
||||
} else if !model.IsOrderFinalStatus(orderStatus.Status) {
|
||||
if order.LockStatus != model.OrderStatusUnknown {
|
||||
globals.SugarLogger.Warnf("addOrderStatus refOrderID:%s, orderID:%s, order.LockStatus:%d, status.LockStatus:%d", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, order.LockStatus, orderStatus.Status)
|
||||
}
|
||||
order.Flag &= ^model.OrderFlagMaskUserApplyCancel
|
||||
order.LockStatus = orderStatus.Status
|
||||
order.LockStatusTime = orderStatus.StatusTime
|
||||
updateFields = append(updateFields, "LockStatus", "LockStatusTime", "Flag")
|
||||
}
|
||||
order.LockStatusTime = orderStatus.StatusTime
|
||||
updateFields = append(updateFields, "LockStatus", "LockStatusTime")
|
||||
}
|
||||
if model.IsOrderFinalStatus(orderStatus.Status) {
|
||||
order.OrderFinishedAt = orderStatus.StatusTime
|
||||
@@ -430,6 +451,7 @@ func (c *OrderManager) loadOrder(vendorOrderID, vendorOrderID2 string, vendorID
|
||||
}, "LoadOrder orderID:%s", vendorOrderID)
|
||||
}
|
||||
if err != nil {
|
||||
order = nil
|
||||
if err == orm.ErrNoRows {
|
||||
err = ErrCanNotFindOrder
|
||||
}
|
||||
@@ -475,11 +497,12 @@ func (c *OrderManager) loadOrderFinancial(vendorOrderID, vendorOrderID2 string,
|
||||
if err = db.Read(order, keyFields...); err == nil {
|
||||
vendorOrderID = order.VendorOrderID
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.QueryTable("order_sku_financial").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).All(&order.Skus)
|
||||
_, err = db.QueryTable("order_sku_financial").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).Filter("is_afs_order", 0).All(&order.Skus)
|
||||
return err
|
||||
}, "LoadOrder orderID:%s", vendorOrderID)
|
||||
}
|
||||
if err != nil {
|
||||
order = nil
|
||||
if err == orm.ErrNoRows {
|
||||
err = ErrCanNotFindOrder
|
||||
}
|
||||
@@ -488,30 +511,15 @@ func (c *OrderManager) loadOrderFinancial(vendorOrderID, vendorOrderID2 string,
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) UpdateOrderStatusAndFlag(order *model.GoodsOrder) (err error) {
|
||||
db := orm.NewOrm()
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Update(order, "Status", "DeliveryFlag")
|
||||
return err
|
||||
}, "UpdateOrderStatusAndFlag orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
func (c *OrderManager) UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error) {
|
||||
return c.UpdateOrderFields(order, []string{"Status", "DeliveryFlag"})
|
||||
}
|
||||
|
||||
//Waybill
|
||||
func (c *OrderManager) UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error) {
|
||||
globals.SugarLogger.Debugf("UpdateWaybillVendorID bill:%v", bill)
|
||||
func (c *OrderManager) UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error) {
|
||||
db := orm.NewOrm()
|
||||
params := orm.Params{
|
||||
"vendor_waybill_id": bill.VendorWaybillID,
|
||||
"waybill_vendor_id": bill.WaybillVendorID,
|
||||
}
|
||||
// 如果运单被取消,则要保持在已拣货状态
|
||||
if revertStatus && bill.WaybillVendorID == model.VendorIDUnknown {
|
||||
params["status"] = model.OrderStatusFinishedPickup
|
||||
}
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.QueryTable("goods_order").Filter("vendor_order_id", bill.VendorOrderID).Filter("vendor_id", bill.OrderVendorID).Update(params)
|
||||
_, err = db.Update(order, fieldList...)
|
||||
return err
|
||||
}, "UpdateWaybillVendorID update order, bill:%v", bill)
|
||||
}, "UpdateOrderFields orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
351
business/jxcallback/orderman/order_afs.go
Normal file
351
business/jxcallback/orderman/order_afs.go
Normal file
@@ -0,0 +1,351 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"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/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
func (c *OrderManager) LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
return c.loadAfsOrder(dao.GetDB(), vendorAfsOrderID, vendorID)
|
||||
}
|
||||
|
||||
func (c *OrderManager) loadAfsOrder(db *dao.DaoDB, vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
AfsOrderID: vendorAfsOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
if err = dao.GetEntity(db, afsOrder, "AfsOrderID", "VendorID"); err != nil {
|
||||
afsOrder = nil
|
||||
}
|
||||
return afsOrder, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, true)
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, false)
|
||||
}
|
||||
|
||||
func (c *OrderManager) onAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus, isAdjust bool) (err error) {
|
||||
db := dao.GetDB()
|
||||
// globals.SugarLogger.Debugf("onAfsOrderNew1 afsOrder:%s", utils.Format4Output(afsOrder, true))
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
if afsOrder.AfsOrderID == "" {
|
||||
afsOrder.AfsOrderID = orderStatus.VendorOrderID
|
||||
}
|
||||
if afsOrder.VendorStatus == "" {
|
||||
afsOrder.VendorStatus = orderStatus.VendorStatus
|
||||
}
|
||||
if afsOrder.Status == model.OrderStatusUnknown {
|
||||
afsOrder.Status = orderStatus.Status
|
||||
}
|
||||
// globals.SugarLogger.Debugf("onAfsOrderNew2 afsOrder:%s", utils.Format4Output(afsOrder, true))
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew afsOrderID:%s, isDuplicated:%t", afsOrder.AfsOrderID, isDuplicated)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
var existAfsOrder *model.AfsOrder
|
||||
if existAfsOrder, err = c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID); err != nil {
|
||||
if !dao.IsNoRowsError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if existAfsOrder != nil {
|
||||
existAfsOrder.Status = afsOrder.Status
|
||||
existAfsOrder.VendorStatus = afsOrder.VendorStatus
|
||||
if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 外退都要先全删除再建
|
||||
if afsOrder.RefundType == model.AfsTypeFullRefund {
|
||||
isAdjust = true
|
||||
}
|
||||
if err = c.SaveAfsOrder(db, afsOrder, isAdjust); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
scheduler.CurrentScheduler.OnAfsOrderNew(afsOrder, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) SaveAfsOrder(db *dao.DaoDB, afsOrder *model.AfsOrder, isDeleteFirst bool) (err error) {
|
||||
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
|
||||
return err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if isDeleteFirst {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, afsOrder, "VendorOrderID", "VendorID")
|
||||
return err
|
||||
}, "SaveAfsOrder delete AfsOrder, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, &model.OrderSkuFinancial{
|
||||
VendorOrderID: afsOrder.VendorOrderID,
|
||||
VendorID: afsOrder.VendorID,
|
||||
IsAfsOrder: 1,
|
||||
}, "VendorOrderID", "VendorID", "IsAfsOrder")
|
||||
return err
|
||||
}, "SaveAfsOrder delete OrderSkuFinancial, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v", afsOrder.AfsOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
|
||||
db := dao.GetDB()
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, afsOrder, err := c.addAfsOrderStatus(db, orderStatus)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
scheduler.CurrentScheduler.OnAfsOrderStatusChanged(afsOrder, orderStatus, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) addAfsOrderStatus(db *dao.DaoDB, orderStatus *model.OrderStatus) (isDuplicated bool, order *model.AfsOrder, err error) {
|
||||
globals.SugarLogger.Debugf("addAfsOrderStatus refOrderID:%s, orderID:%s", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
|
||||
if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
|
||||
order = &model.AfsOrder{
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorID: orderStatus.VendorID,
|
||||
}
|
||||
if err = db.Db.ReadForUpdate(order, "AfsOrderID", "VendorID"); err == nil {
|
||||
if orderStatus.Status > model.OrderStatusUnknown { // todo 要求status不能回绕
|
||||
order.VendorStatus = orderStatus.VendorStatus
|
||||
order.Status = orderStatus.Status
|
||||
updateFields := []string{
|
||||
"VendorStatus",
|
||||
"Status",
|
||||
}
|
||||
if model.IsAfsOrderFinalStatus(orderStatus.Status) {
|
||||
order.AfsFinishedAt = orderStatus.StatusTime
|
||||
updateFields = append(updateFields, "AfsFinishedAt")
|
||||
}
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntity(db, order, updateFields...)
|
||||
return err
|
||||
}, "addAfsOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
|
||||
} else {
|
||||
isDuplicated = true
|
||||
}
|
||||
} else {
|
||||
if dao.IsNoRowsError(err) { // todo 消息错序
|
||||
err = nil
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("addAfsOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return isDuplicated, order, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debugf("updateAfsOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
|
||||
jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
|
||||
opNumStr := "2"
|
||||
if jxStoreID == 0 {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]订单在京西与平台都找不到京西门店信息orderID:%s, VendorStoreID:%s", opNumStr, order.VendorOrderID, order.VendorStoreID)
|
||||
return nil
|
||||
}
|
||||
orderSkus := order.Skus
|
||||
vendorSkuIDs := make([]int64, 0)
|
||||
for _, v := range orderSkus {
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 {
|
||||
vendorSkuIDs = append(vendorSkuIDs, intVendorSkuID)
|
||||
}
|
||||
}
|
||||
if len(vendorSkuIDs) > 0 {
|
||||
tableName := "t2"
|
||||
if model.MultiStoresVendorMap[order.VendorID] == 1 {
|
||||
tableName = "t1"
|
||||
}
|
||||
fieldPrefix := dao.ConvertDBFieldPrefix(model.VendorNames[order.VendorID])
|
||||
sql := `
|
||||
SELECT %s.%s_id vendor_sku_id, t1.id sku_id, t2.price, t1.weight
|
||||
FROM sku t1
|
||||
LEFT JOIN store_sku_bind t2 ON t1.id = t2.sku_id AND t2.deleted_at = ? AND t2.store_id = ?
|
||||
WHERE t1.deleted_at = ? AND %s.%s_id IN (-1, ` + dao.GenQuestionMarks(len(vendorSkuIDs)) + ")"
|
||||
sql = fmt.Sprintf(sql, tableName, fieldPrefix, tableName, fieldPrefix)
|
||||
var skuInfos []*tStoreSkuBindAndVendorSkuID
|
||||
if err = dao.GetRows(db, &skuInfos, sql, utils.DefaultTimeValue, jxStoreID, utils.DefaultTimeValue, vendorSkuIDs); err != nil {
|
||||
globals.SugarLogger.Errorf("updateAfsOrderSkuOtherInfo can not get sku info for orderID:%s, error:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
skumapper := make(map[int64]*tStoreSkuBindAndVendorSkuID)
|
||||
for _, v := range skuInfos {
|
||||
skumapper[v.VendorSkuID] = v
|
||||
}
|
||||
for _, v := range orderSkus {
|
||||
v.AfsOrderID = order.AfsOrderID
|
||||
v.VendorID = order.VendorID
|
||||
v.VendorOrderID = order.VendorOrderID
|
||||
v.IsAfsOrder = 1
|
||||
v.VendorStoreID = order.VendorStoreID
|
||||
v.StoreID = order.StoreID
|
||||
v.JxStoreID = jxStoreID
|
||||
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
|
||||
skuBindInfo := skumapper[intVendorSkuID]
|
||||
if skuBindInfo == nil {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格(或商品映射),orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
|
||||
} else {
|
||||
v.JxSkuID = skuBindInfo.SkuID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderOtherInfo(db *dao.DaoDB, afsOrder *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debugf("updateAfsOrderOtherInfo orderID:%s, VendorStoreID:%s", afsOrder.VendorOrderID, afsOrder.VendorStoreID)
|
||||
if afsOrder.VendorStoreID != "" {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0); err == nil {
|
||||
afsOrder.JxStoreID = storeDetail.Store.ID
|
||||
}
|
||||
}
|
||||
if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
|
||||
if order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); err2 == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
if afsOrder.StoreID == 0 {
|
||||
afsOrder.StoreID = order.StoreID
|
||||
}
|
||||
if afsOrder.VendorStoreID == "" {
|
||||
afsOrder.VendorStoreID = order.VendorStoreID
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err = c.updateAfsOrderSkuOtherInfo(db, afsOrder); err == nil {
|
||||
jxutils.RefreshAfsOrderSkuRelated(afsOrder)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error) {
|
||||
db := orm.NewOrm()
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Update(afsOrder, fieldList...)
|
||||
return err
|
||||
}, "UpdateAfsOrderFields orderID:%s failed with error:%v", afsOrder.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) setAfsOrderID(db *dao.DaoDB, orderStatus *model.OrderStatus) {
|
||||
// globals.SugarLogger.Debugf("setAfsOrderID1 orderStatus:%v", utils.Format4Output(orderStatus, true))
|
||||
if dao.IsVendorThingIDEmpty(orderStatus.VendorOrderID) {
|
||||
index := 1
|
||||
if afsOrderList, err2 := dao.GetAfsOrders(db, orderStatus.RefVendorID, orderStatus.RefVendorOrderID, ""); err2 == nil {
|
||||
if len(afsOrderList) > 0 {
|
||||
list := strings.Split(afsOrderList[0].AfsOrderID, "-")
|
||||
if len(list) > 1 {
|
||||
index = int(utils.Str2Int64WithDefault(list[1], 0))
|
||||
if afsOrderList[0].Status >= model.AfsOrderStatusFinished {
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("setAfsOrderID err2:%v", err2)
|
||||
}
|
||||
orderStatus.VendorOrderID = composeAfsOrderID(orderStatus.RefVendorOrderID, index)
|
||||
}
|
||||
// globals.SugarLogger.Debugf("setAfsOrderID2 orderStatus:%v", utils.Format4Output(orderStatus, true))
|
||||
}
|
||||
|
||||
func composeAfsOrderID(vendorOrderID string, index int) (afsOrderID string) {
|
||||
return strings.Join([]string{
|
||||
vendorOrderID,
|
||||
utils.Int2Str(index),
|
||||
}, "-")
|
||||
}
|
||||
@@ -102,12 +102,16 @@ func (c *OrderManager) OnOrderComments(orderCommentList []*model.OrderComment) (
|
||||
comment2.Maxmodifytime = int(orderComment.ModifyDuration)
|
||||
if orderComment.VendorID != model.VendorIDELM {
|
||||
var order *model.GoodsOrder
|
||||
if orderComment.VendorID != model.VendorIDEBAI {
|
||||
order, err = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
if true /*orderComment.VendorID != model.VendorIDEBAI*/ {
|
||||
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
}
|
||||
if order != nil {
|
||||
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile
|
||||
if order.ConsigneeMobile2 != "" {
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile2
|
||||
} else {
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile
|
||||
}
|
||||
}
|
||||
if orderComment.StoreID > 0 {
|
||||
comment2.Jxstoreid = utils.Int2Str(orderComment.StoreID)
|
||||
@@ -65,8 +65,10 @@ func init() {
|
||||
func addOrderOrWaybillStatus(status *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
if status.OrderType == model.OrderTypeOrder {
|
||||
globals.SugarLogger.Debugf("addOrderStatus order:%v", status)
|
||||
} else {
|
||||
} else if status.OrderType == model.OrderTypeWaybill {
|
||||
globals.SugarLogger.Debugf("addOrderStatus waybill:%v", status)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("addOrderStatus afsOrder:%v", status)
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
@@ -100,6 +102,17 @@ func addOrderOrWaybillStatus(status *model.OrderStatus, db *dao.DaoDB) (isDuplic
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int) {
|
||||
if status == nil {
|
||||
return 0
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err := dao.GetEntity(db, status, "VendorOrderID", "VendorID", "OrderType", "VendorStatus", "StatusTime"); err == nil {
|
||||
return status.DuplicatedCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// todo 最好还是改成全事件回放算了
|
||||
func LoadPendingOrders() {
|
||||
orders := FixedOrderManager.LoadPendingOrders()
|
||||
@@ -140,17 +153,17 @@ func LoadPendingOrders() {
|
||||
if order, ok := item.(*model.GoodsOrder); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnOrderNew(order, true)
|
||||
}, order.VendorOrderID)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
} else if status, ok := item.(*model.OrderStatus); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
order := orderMap[jxutils.ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)]
|
||||
scheduler.CurrentScheduler.OnOrderStatusChanged(order, status, true)
|
||||
}, status.VendorOrderID)
|
||||
}, jxutils.ComposeUniversalOrderID(status.RefVendorOrderID, status.RefVendorID))
|
||||
} else {
|
||||
bill := item.(*model.Waybill)
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, true)
|
||||
}, bill.VendorOrderID)
|
||||
}, jxutils.ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID))
|
||||
}
|
||||
curTime := time.Now()
|
||||
timeout := sleepGap - curTime.Sub(lastTime)
|
||||
|
||||
@@ -3,8 +3,11 @@ package orderman
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
|
||||
@@ -27,33 +30,21 @@ type tWaybillExt struct {
|
||||
StoreID int `json:"storeID" orm:"column(store_id)"`
|
||||
}
|
||||
|
||||
//此函数会被GetStoreOrderCountInfo2取代
|
||||
func (c *OrderManager) GetStoreOrderCountInfo(ctx *jxcontext.Context, storeID string, lastHours int) (countInfo []*model.GoodsOrderCountInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetStoreOrderCountInfo storeID:%s", storeID)
|
||||
if lastHours > maxLastHours {
|
||||
lastHours = maxLastHours
|
||||
} else if lastHours == 0 {
|
||||
lastHours = defLastHours
|
||||
}
|
||||
type StoresOrderSaleInfo struct {
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"`
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
Status int `json:"status"`
|
||||
Count int `json:"count"`
|
||||
ShopPrice int64 `json:"shopPrice"`
|
||||
VendorPrice int64 `json:"vendorPrice"`
|
||||
SalePrice int64 `json:"salePrice"`
|
||||
ActualPayPrice int64 `json:"actualPayPrice"`
|
||||
|
||||
db := orm.NewOrm()
|
||||
_, err = db.Raw(`
|
||||
SELECT t1.status, COUNT(*) count
|
||||
FROM goods_order t1
|
||||
WHERE t1.vendor_id <> 2 AND IF(t1.vendor_id = ?, t1.store_id, IF(t1.jx_store_id != 0, t1.jx_store_id, t1.store_id) ) = ?
|
||||
AND t1.order_created_at >= ? AND t1.lock_status = ?
|
||||
GROUP BY 1
|
||||
ORDER BY 1
|
||||
`, model.VendorIDWSC, storeID, time.Now().Add(-time.Duration(lastHours)*time.Hour), model.OrderStatusUnknown).QueryRows(&countInfo)
|
||||
if err == nil {
|
||||
return countInfo, nil
|
||||
}
|
||||
globals.SugarLogger.Infof("GetStoreOrderCountInfo storeID:%s failed with error:%v", storeID, err)
|
||||
return nil, err
|
||||
EarningPrice int64 `json:"earningPrice"` // 预估结算给门店老板的钱
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStoreOrderCountInfo2(ctx *jxcontext.Context, storeID, lastHours int) (countInfo []*model.GoodsOrderCountInfo2, err error) {
|
||||
globals.SugarLogger.Debugf("GetStoreOrderCountInfo2 storeID:%s", storeID)
|
||||
func (c *OrderManager) GetStoreOrderCountInfo(ctx *jxcontext.Context, storeID, lastHours int) (countInfo []*model.GoodsOrderCountInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetStoreOrderCountInfo storeID:%d", storeID)
|
||||
if lastHours > maxLastHours {
|
||||
lastHours = maxLastHours
|
||||
} else if lastHours == 0 {
|
||||
@@ -72,7 +63,7 @@ func (c *OrderManager) GetStoreOrderCountInfo2(ctx *jxcontext.Context, storeID,
|
||||
if err == nil {
|
||||
return countInfo, nil
|
||||
}
|
||||
globals.SugarLogger.Infof("GetStoreOrderCountInfo2 storeID:%s failed with error:%v", storeID, err)
|
||||
globals.SugarLogger.Infof("GetStoreOrderCountInfo storeID:%d failed with error:%v", storeID, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -86,7 +77,26 @@ func (c *OrderManager) GetOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID str
|
||||
db := dao.GetDB()
|
||||
if vendorID == model.VendorIDELM {
|
||||
err = dao.GetRows(db, &skus, fmt.Sprintf(`
|
||||
SELECT t1.*, IF(t3.img IS NULL OR t3.img = '', t4.col_imageUrl, t3.img) image, %s full_sku_name
|
||||
SELECT
|
||||
t1.id,
|
||||
t1.vendor_order_id,
|
||||
t1.vendor_id,
|
||||
t1.count,
|
||||
t1.vendor_sku_id,
|
||||
t1.sku_id,
|
||||
t1.jx_sku_id,
|
||||
t1.sku_name,
|
||||
IF(t1.shop_price = 0, t1.sale_price, t1.shop_price) shop_price,
|
||||
t1.sale_price,
|
||||
t1.earning_price,
|
||||
t1.weight,
|
||||
t1.sku_type,
|
||||
t1.promotion_type,
|
||||
t1.order_created_at,
|
||||
t1.store_sub_id,
|
||||
t1.store_sub_name,
|
||||
t1.vendor_price,
|
||||
IF(t3.img IS NULL OR t3.img = '', t4.col_imageUrl, t3.img) image, %s full_sku_name
|
||||
FROM order_sku t1
|
||||
LEFT JOIN sku t2 ON IF(t1.jx_sku_id != 0, t1.jx_sku_id, t1.sku_id) = t2.id/* AND t2.deleted_at = ?*/
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id/* AND t3.deleted_at = ?*/
|
||||
@@ -96,7 +106,26 @@ func (c *OrderManager) GetOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID str
|
||||
`, fullSkuNameSQL), /*, utils.DefaultTimeValue, utils.DefaultTimeValue*/ vendorOrderID, vendorID)
|
||||
} else if vendorID == model.VendorIDJD {
|
||||
err = dao.GetRows(db, &skus, fmt.Sprintf(`
|
||||
SELECT t1.*, IF(t3.img IS NULL OR t3.img = '', t4.image, t3.img) image, %s full_sku_name
|
||||
SELECT
|
||||
t1.id,
|
||||
t1.vendor_order_id,
|
||||
t1.vendor_id,
|
||||
t1.count,
|
||||
t1.vendor_sku_id,
|
||||
t1.sku_id,
|
||||
t1.jx_sku_id,
|
||||
t1.sku_name,
|
||||
IF(t1.shop_price = 0, t1.sale_price, t1.shop_price) shop_price,
|
||||
t1.sale_price,
|
||||
t1.earning_price,
|
||||
t1.weight,
|
||||
t1.sku_type,
|
||||
t1.promotion_type,
|
||||
t1.order_created_at,
|
||||
t1.store_sub_id,
|
||||
t1.store_sub_name,
|
||||
t1.vendor_price,
|
||||
IF(t3.img IS NULL OR t3.img = '', t4.image, t3.img) image, %s full_sku_name
|
||||
FROM order_sku t1
|
||||
LEFT JOIN sku t2 ON IF(t1.jx_sku_id != 0, t1.jx_sku_id, t1.sku_id) = t2.id/* AND t2.deleted_at = ?*/
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id/* AND t3.deleted_at = ?*/
|
||||
@@ -107,7 +136,26 @@ func (c *OrderManager) GetOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID str
|
||||
}
|
||||
if err != nil || len(skus) == 0 {
|
||||
err = dao.GetRows(db, &skus, fmt.Sprintf(`
|
||||
SELECT t1.*, t3.img image, %s full_sku_name
|
||||
SELECT
|
||||
t1.id,
|
||||
t1.vendor_order_id,
|
||||
t1.vendor_id,
|
||||
t1.count,
|
||||
t1.vendor_sku_id,
|
||||
t1.sku_id,
|
||||
t1.jx_sku_id,
|
||||
t1.sku_name,
|
||||
IF(t1.shop_price = 0, t1.sale_price, t1.shop_price) shop_price,
|
||||
t1.sale_price,
|
||||
t1.earning_price,
|
||||
t1.weight,
|
||||
t1.sku_type,
|
||||
t1.promotion_type,
|
||||
t1.order_created_at,
|
||||
t1.store_sub_id,
|
||||
t1.store_sub_name,
|
||||
t1.vendor_price,
|
||||
t3.img image, %s full_sku_name
|
||||
FROM order_sku t1
|
||||
LEFT JOIN sku t2 ON IF(t1.jx_sku_id != 0, t1.jx_sku_id, t1.sku_id) = t2.id/* AND t2.deleted_at = ?*/
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id/* AND t3.deleted_at = ?*/
|
||||
@@ -157,19 +205,25 @@ func (c *OrderManager) GetOrderInfo(ctx *jxcontext.Context, vendorOrderID string
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (bills []*model.Waybill, err error) {
|
||||
func (c *OrderManager) GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded bool) (bills []*model.Waybill, err error) {
|
||||
globals.SugarLogger.Debugf("GetOrderWaybillInfo orderID:%s", vendorOrderID)
|
||||
db := orm.NewOrm()
|
||||
_, err = db.Raw(`
|
||||
db := dao.GetDB()
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM waybill t1
|
||||
WHERE t1.vendor_order_id = ? AND order_vendor_id = ?
|
||||
`, vendorOrderID, vendorID).QueryRows(&bills)
|
||||
if err == nil {
|
||||
return bills, nil
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorOrderID,
|
||||
vendorID,
|
||||
}
|
||||
if isNotEnded {
|
||||
sql += " AND t1.status < ?"
|
||||
sqlParams = append(sqlParams, model.OrderStatusEndBegin)
|
||||
}
|
||||
err = dao.GetRows(db, &bills, sql, sqlParams...)
|
||||
globals.SugarLogger.Infof("GetOrderWaybillInfo orderID:%s failed with error:%v", vendorOrderID, err)
|
||||
return nil, err
|
||||
return bills, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) ExportMTWaybills(ctx *jxcontext.Context, fromDateStr, toDateStr string) (excelContent []byte, err error) {
|
||||
@@ -220,8 +274,8 @@ func (c *OrderManager) ExportMTWaybills(ctx *jxcontext.Context, fromDateStr, toD
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr string, params map[string]interface{}, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetOrders from:%s to:%s", fromDateStr, toDateStr)
|
||||
func (c *OrderManager) getOrders(ctx *jxcontext.Context, isIncludeSku bool, fromDateStr, toDateStr string, params map[string]interface{}, offset, pageSize int) (orders []*model.GoodsOrderExt, totalCount int, err error) {
|
||||
globals.SugarLogger.Debugf("getOrders from:%s to:%s", fromDateStr, toDateStr)
|
||||
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
if offset < 0 {
|
||||
@@ -229,11 +283,21 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
}
|
||||
sql := `
|
||||
SELECT SQL_CALC_FOUND_ROWS t1.*,
|
||||
CAST(IF(t1.shop_price <= t1.vendor_price, IF(t1.shop_price = 0, t1.sale_price, t1.shop_price), IF(t1.vendor_price = 0, t1.sale_price, t1.vendor_price))*IF(t5.pay_percentage IS NULL OR t5.pay_percentage <= 0, 70, t5.pay_percentage)/100 AS SIGNED) earning_price,
|
||||
t2.status waybill_status, t2.courier_name, t2.courier_mobile,
|
||||
t2.actual_fee, t2.desired_fee, t2.waybill_created_at, t2.waybill_finished_at
|
||||
t2.actual_fee, t2.desired_fee, t2.waybill_created_at, t2.waybill_finished_at`
|
||||
if isIncludeSku {
|
||||
sql += `,
|
||||
t3.sku_id, t3.count sku_count2, t3.shop_price sku_shop_price, IF(t3.earning_price <> 0, t3.earning_price, t3.sale_price) sku_sale_price`
|
||||
}
|
||||
sql += `
|
||||
FROM goods_order t1
|
||||
LEFT JOIN waybill t2 ON t1.vendor_waybill_id = t2.vendor_waybill_id AND t1.waybill_vendor_id = t2.waybill_vendor_id
|
||||
`
|
||||
LEFT JOIN store t5 ON t5.id = IF(t1.jx_store_id <> 0, t1.jx_store_id, t1.store_id)`
|
||||
if isIncludeSku {
|
||||
sql += `
|
||||
JOIN order_sku t3 ON t3.vendor_order_id = t1.vendor_order_id AND t3.vendor_id = t1.vendor_id`
|
||||
}
|
||||
var (
|
||||
sqlWhere string
|
||||
sqlParams []interface{}
|
||||
@@ -257,14 +321,14 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
} else {
|
||||
fromDate, err2 := utils.TryStr2Time(fromDateStr)
|
||||
if err = err2; err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if toDateStr == "" {
|
||||
toDateStr = fromDateStr
|
||||
}
|
||||
toDate, err2 := utils.TryStr2Time(toDateStr)
|
||||
if err = err2; err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
toDate = toDate.Add(24 * time.Hour)
|
||||
|
||||
@@ -279,7 +343,7 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
keyword := params["keyword"].(string)
|
||||
keywordLike := "%" + keyword + "%"
|
||||
sqlWhere += `
|
||||
AND (t1.store_name LIKE ? OR t1.vendor_order_id LIKE ? OR t1.vendor_store_id LIKE ?
|
||||
AND (t1.store_name LIKE ? OR t1.vendor_order_id LIKE ? OR t1.vendor_store_id LIKE ?
|
||||
OR t1.consignee_name LIKE ? OR t1.consignee_mobile LIKE ? OR t1.consignee_mobile2 LIKE ? OR t1.consignee_address LIKE ?
|
||||
OR t2.vendor_waybill_id LIKE ? OR t2.courier_name LIKE ? OR t2.courier_mobile LIKE ?
|
||||
`
|
||||
@@ -293,17 +357,17 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
if params["waybillVendorIDs"] != nil {
|
||||
var waybillVendorIDs []int
|
||||
if err = utils.UnmarshalUseNumber([]byte(params["waybillVendorIDs"].(string)), &waybillVendorIDs); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(waybillVendorIDs) > 0 {
|
||||
sqlWhere += " AND t2.waybill_vendor_id IN (" + dao.GenQuestionMarks(len(waybillVendorIDs)) + ")"
|
||||
sqlWhere += " AND t1.waybill_vendor_id IN (" + dao.GenQuestionMarks(len(waybillVendorIDs)) + ")"
|
||||
sqlParams = append(sqlParams, waybillVendorIDs)
|
||||
}
|
||||
}
|
||||
if params["storeIDs"] != nil {
|
||||
var storeIDs []int
|
||||
if err = utils.UnmarshalUseNumber([]byte(params["storeIDs"].(string)), &storeIDs); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sqlWhere += " AND IF(t1.vendor_id = ?, t1.store_id, IF(t1.jx_store_id != 0, t1.jx_store_id, t1.store_id) ) IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
|
||||
@@ -313,7 +377,7 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
if params["statuss"] != nil {
|
||||
var statuss []int
|
||||
if err = utils.UnmarshalUseNumber([]byte(params["statuss"].(string)), &statuss); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(statuss) > 0 {
|
||||
sqlWhere += " AND t1.status IN (" + dao.GenQuestionMarks(len(statuss)) + ")"
|
||||
@@ -323,7 +387,7 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
if params["lockStatuss"] != nil {
|
||||
var lockStatuss []int
|
||||
if err = utils.UnmarshalUseNumber([]byte(params["lockStatuss"].(string)), &lockStatuss); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(lockStatuss) > 0 {
|
||||
sqlWhere += " AND t1.lock_status IN (" + dao.GenQuestionMarks(len(lockStatuss)) + ")"
|
||||
@@ -333,7 +397,7 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
if params["cities"] != nil {
|
||||
var cities []int
|
||||
if err = utils.UnmarshalUseNumber([]byte(params["cities"].(string)), &cities); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(cities) > 0 {
|
||||
sql += " JOIN store st ON t1.store_id = st.id"
|
||||
@@ -345,39 +409,147 @@ func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr
|
||||
if params["vendorIDs"] != nil {
|
||||
var vendorIDs []int
|
||||
if err = utils.UnmarshalUseNumber([]byte(params["vendorIDs"].(string)), &vendorIDs); err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if len(vendorIDs) > 0 {
|
||||
sqlWhere += " AND t1.vendor_id IN (" + dao.GenQuestionMarks(len(vendorIDs)) + ")"
|
||||
sqlParams = append(sqlParams, vendorIDs)
|
||||
}
|
||||
}
|
||||
sql += sqlWhere
|
||||
sql += `
|
||||
ORDER BY t1.order_created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
|
||||
var orders []*model.GoodsOrderExt
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
sql += sqlWhere
|
||||
if isIncludeSku {
|
||||
sql += `
|
||||
ORDER BY t1.id`
|
||||
} else {
|
||||
sql += `
|
||||
ORDER BY t1.order_created_at DESC
|
||||
LIMIT ? OFFSET ?`
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
}
|
||||
if err = dao.GetRows(db, &orders, sql, sqlParams...); err == nil {
|
||||
totalCount = dao.GetLastTotalRowCount(db)
|
||||
}
|
||||
if !isIncludeSku {
|
||||
dao.Commit(db)
|
||||
}
|
||||
return orders, totalCount, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetOrders(ctx *jxcontext.Context, fromDateStr, toDateStr string, params map[string]interface{}, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetOrders from:%s to:%s", fromDateStr, toDateStr)
|
||||
orders, totalCount, err := c.getOrders(ctx, false, fromDateStr, toDateStr, params, offset, pageSize)
|
||||
if err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
TotalCount: totalCount,
|
||||
Data: orders,
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
return pagedInfo, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) ExportOrders(ctx *jxcontext.Context, fromDateStr, toDateStr string, mapParams map[string]interface{}) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("ExportOrders from:%s to:%s", fromDateStr, toDateStr)
|
||||
var (
|
||||
orders, orders2 []*model.GoodsOrderExt
|
||||
order *model.GoodsOrderExt
|
||||
excelBin []byte
|
||||
)
|
||||
task := tasksch.NewSeqTask("导出订单SKU信息", ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
orders, _, err = c.getOrders(ctx, true, fromDateStr, toDateStr, mapParams, 0, -1)
|
||||
case 1:
|
||||
for _, v := range orders {
|
||||
skuStr := strings.Join([]string{
|
||||
utils.Int2Str(v.SkuID),
|
||||
utils.Int2Str(v.SkuCount2),
|
||||
utils.Int2Str(v.SkuShopPrice),
|
||||
utils.Int2Str(v.SkuSalePrice),
|
||||
}, ",")
|
||||
if order == nil || v.ID != order.ID {
|
||||
order = v
|
||||
v.CourierVendorName = model.VendorChineseNames[v.WaybillVendorID]
|
||||
v.Status2 = model.OrderStatusName[v.Status]
|
||||
v.SkuInfo = skuStr
|
||||
orders2 = append(orders2, v)
|
||||
} else {
|
||||
order.SkuInfo += ";" + skuStr
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||||
Title: "订单导出",
|
||||
Data: orders2,
|
||||
CaptionList: []string{
|
||||
"vendorOrderID",
|
||||
"vendorID",
|
||||
"vendorStoreID",
|
||||
"jxStoreID",
|
||||
"storeName",
|
||||
"salePrice",
|
||||
"shopPrice",
|
||||
"weight",
|
||||
"consigneeName",
|
||||
"consigneeMobile",
|
||||
"consigneeMobile2",
|
||||
"consigneeAddress",
|
||||
"skuCount",
|
||||
"status",
|
||||
"orderSeq",
|
||||
"buyerComment",
|
||||
"businessType",
|
||||
"expectedDeliveredTime",
|
||||
"vendorWaybillID",
|
||||
"waybillVendorID",
|
||||
"orderCreatedAt",
|
||||
"orderFinishedAt",
|
||||
"courierVendorName",
|
||||
"courierName",
|
||||
"courierMobile",
|
||||
"courierMobile",
|
||||
"desiredFee",
|
||||
"waybillCreatedAt",
|
||||
"waybillFinishedAt",
|
||||
"status2",
|
||||
"skuInfo",
|
||||
},
|
||||
}
|
||||
excelBin = excel.Obj2Excel([]*excel.Obj2ExcelSheetConfig{excelConf})
|
||||
case 3:
|
||||
keyPart := []string{
|
||||
ctx.GetUserName(),
|
||||
}
|
||||
if fromDateStr != "" {
|
||||
keyPart = append(keyPart, fromDateStr)
|
||||
}
|
||||
if toDateStr != "" {
|
||||
keyPart = append(keyPart, toDateStr)
|
||||
}
|
||||
keyPart = append(keyPart, time.Now().Format("20060102T150405")+".xlsx")
|
||||
key := "export/" + strings.Join(keyPart, "_")
|
||||
excelURL, err2 := jxutils.UploadExportContent(excelBin, key)
|
||||
if err = err2; err == nil {
|
||||
task.SetNoticeMsg(excelURL)
|
||||
}
|
||||
globals.SugarLogger.Debugf("导出订单SKU信息excelURL:%s, err:%v", excelURL, err)
|
||||
}
|
||||
return nil, err
|
||||
}, 4)
|
||||
tasksch.ManageTask(task).Run()
|
||||
hint = task.GetID()
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetWaybills(ctx *jxcontext.Context, fromDateStr, toDateStr string, params map[string]interface{}, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetWaybills from:%s to:%s", fromDateStr, toDateStr)
|
||||
|
||||
@@ -472,16 +644,14 @@ func (c *OrderManager) GetOrderStatusList(ctx *jxcontext.Context, vendorOrderID
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM order_status t1
|
||||
WHERE 1 = 1
|
||||
WHERE t1.ref_vendor_order_id = ? AND t1.ref_vendor_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorOrderID,
|
||||
vendorID,
|
||||
}
|
||||
if orderType == -1 {
|
||||
sql += " AND t1.ref_vendor_order_id = ? AND t1.ref_vendor_id = ?"
|
||||
} else {
|
||||
sql += " AND t1.vendor_order_id = ? AND t1.vendor_id = ? AND t1.order_type = ?"
|
||||
if orderType > 0 {
|
||||
sql += " AND t1.order_type = ?"
|
||||
sqlParams = append(sqlParams, orderType)
|
||||
}
|
||||
sql += " ORDER BY t1.status_time, t1.order_type DESC"
|
||||
@@ -604,3 +774,184 @@ func (c *OrderManager) GetOrdersFinancial(ctx *jxcontext.Context, fromDateStr, t
|
||||
|
||||
return pagedInfo, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStoresOrderSaleInfo(ctx *jxcontext.Context, storeIDList []int, fromTime time.Time, toTime time.Time, statusList []int) (saleInfoList []*StoresOrderSaleInfo, err error) {
|
||||
if toTime.Sub(fromTime) > time.Hour*24*60 {
|
||||
return nil, fmt.Errorf("查询时间范围不能超过60天")
|
||||
}
|
||||
// 用int64类型去取float型的数据库返回值,会取不到
|
||||
sql := `
|
||||
SELECT IF(t1.jx_store_id > 0, t1.jx_store_id, t1.store_id) store_id, t1.vendor_id, IF(t1.status < ?, 0, t1.status) status,
|
||||
COUNT(*) count, SUM(t1.shop_price) shop_price, SUM(t1.vendor_price) vendor_price, SUM(t1.sale_price) sale_price, SUM(t1.actual_pay_price) actual_pay_price,
|
||||
CAST(SUM(IF(t1.shop_price <= t1.vendor_price, IF(t1.shop_price = 0, t1.sale_price, t1.shop_price), IF(t1.vendor_price = 0, t1.sale_price, t1.vendor_price))*IF(t5.pay_percentage IS NULL OR t5.pay_percentage <= 0, 70, t5.pay_percentage)/100) AS SIGNED) earning_price
|
||||
FROM goods_order t1
|
||||
LEFT JOIN store t5 ON t5.id = IF(t1.jx_store_id <> 0, t1.jx_store_id, t1.store_id)
|
||||
WHERE t1.order_created_at >= ? AND t1.order_created_at <= ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
model.OrderStatusEndBegin,
|
||||
fromTime,
|
||||
toTime,
|
||||
}
|
||||
if len(storeIDList) > 0 {
|
||||
sql += " AND IF(t1.jx_store_id > 0, t1.jx_store_id, t1.store_id) IN (" + dao.GenQuestionMarks(len(storeIDList)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDList)
|
||||
}
|
||||
if len(statusList) > 0 {
|
||||
sql += " AND t1.status IN (" + dao.GenQuestionMarks(len(statusList)) + ")"
|
||||
sqlParams = append(sqlParams, statusList)
|
||||
}
|
||||
sql += `
|
||||
GROUP BY 1,2,3
|
||||
ORDER BY 1,2,3`
|
||||
err = dao.GetRows(dao.GetDB(), &saleInfoList, sql, sqlParams...)
|
||||
return saleInfoList, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetAfsOrders(ctx *jxcontext.Context, keyword, afsOrderID, vendorOrderID string, vendorIDList, appealTypeList, storeIDList, statusList []int, fromTime, toTime time.Time, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetAfsOrders")
|
||||
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
sql := `
|
||||
SELECT SQL_CALC_FOUND_ROWS t1.*
|
||||
FROM afs_order t1
|
||||
`
|
||||
var (
|
||||
sqlWhere string
|
||||
sqlParams []interface{}
|
||||
)
|
||||
// 如果搜索关键字可能为订单或售后单号,则当成订单或售后单查询
|
||||
if keyword != "" {
|
||||
if jxutils.GetPossibleVendorIDFromAfsOrderID(keyword) > model.VendorIDUnknown && afsOrderID == "" {
|
||||
afsOrderID = keyword
|
||||
keyword = ""
|
||||
} else if jxutils.GetPossibleVendorIDFromVendorOrderID(keyword) > model.VendorIDUnknown && vendorOrderID == "" {
|
||||
vendorOrderID = keyword
|
||||
keyword = ""
|
||||
}
|
||||
}
|
||||
if vendorOrderID != "" || afsOrderID != "" {
|
||||
if vendorOrderID != "" {
|
||||
sqlWhere = " WHERE (t1.vendor_order_id = ? OR t1.vendor_order_id2 = ?)"
|
||||
sqlParams = []interface{}{
|
||||
vendorOrderID,
|
||||
vendorOrderID,
|
||||
}
|
||||
} else {
|
||||
sqlWhere = " WHERE (t1.afs_order_id = ?)"
|
||||
sqlParams = []interface{}{
|
||||
afsOrderID,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if toTime.Sub(fromTime) > 24*time.Hour*60 {
|
||||
return nil, fmt.Errorf("售后单查询时间不能超过60天")
|
||||
}
|
||||
sqlWhere = `
|
||||
WHERE t1.afs_created_at >= ? AND t1.afs_created_at <= ?
|
||||
`
|
||||
sqlParams = []interface{}{
|
||||
fromTime,
|
||||
toTime,
|
||||
}
|
||||
if keyword != "" {
|
||||
keywordLike := "%" + keyword + "%"
|
||||
sqlWhere += `
|
||||
AND (t1.vendor_order_id2 LIKE ? OR t1.vendor_order_id LIKE ? OR t1.afs_order_id LIKE ?
|
||||
OR t1.vendor_store_id LIKE ? OR t1.reason_desc LIKE ?
|
||||
`
|
||||
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike)
|
||||
if keywordInt64 := utils.Str2Int64WithDefault(keyword, 0); keywordInt64 > 0 {
|
||||
sqlWhere += " OR t1.store_id = ? OR t1.jx_store_id = ?"
|
||||
sqlParams = append(sqlParams, keywordInt64, keywordInt64)
|
||||
}
|
||||
sqlWhere += ")"
|
||||
}
|
||||
if len(storeIDList) > 0 {
|
||||
sqlWhere += " AND IF(t1.jx_store_id != 0, t1.jx_store_id, t1.store_id) IN (" + dao.GenQuestionMarks(len(storeIDList)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDList)
|
||||
}
|
||||
if len(statusList) > 0 {
|
||||
sqlWhere += " AND t1.status IN (" + dao.GenQuestionMarks(len(statusList)) + ")"
|
||||
sqlParams = append(sqlParams, statusList)
|
||||
}
|
||||
if len(appealTypeList) > 0 {
|
||||
sqlWhere += " AND t1.appeal_type IN (" + dao.GenQuestionMarks(len(appealTypeList)) + ")"
|
||||
sqlParams = append(sqlParams, appealTypeList)
|
||||
}
|
||||
}
|
||||
if len(vendorIDList) > 0 {
|
||||
sqlWhere += " AND t1.vendor_id IN (" + dao.GenQuestionMarks(len(vendorIDList)) + ")"
|
||||
sqlParams = append(sqlParams, vendorIDList)
|
||||
}
|
||||
|
||||
sql += sqlWhere
|
||||
sql += `
|
||||
ORDER BY t1.afs_created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
`
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
|
||||
var orders []*model.AfsOrder
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err = dao.GetRows(db, &orders, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
Data: orders,
|
||||
}
|
||||
dao.Commit(db)
|
||||
}
|
||||
return pagedInfo, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetAfsOrderSkuInfo(ctx *jxcontext.Context, afsOrderID string, vendorID int) (skus []*model.OrderFinancialSkuExt, err error) {
|
||||
sql := `
|
||||
SELECT t1.*, t3.img image
|
||||
FROM order_sku_financial t1
|
||||
JOIN sku t2 ON t2.id = IF(t1.jx_sku_id <> 0, t1.jx_sku_id, t1.sku_id)
|
||||
JOIN sku_name t3 ON t3.id = t2.name_id
|
||||
WHERE t1.afs_order_id = ? AND t1.vendor_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
afsOrderID,
|
||||
vendorID,
|
||||
}
|
||||
err = dao.GetRows(dao.GetDB(), &skus, sql, sqlParams...)
|
||||
return skus, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStoreAfsOrderCountInfo(ctx *jxcontext.Context, storeID, lastHours int) (countInfo []*model.GoodsOrderCountInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetStoreAfsOrderCountInfo storeID:%d", storeID)
|
||||
if lastHours > maxLastHours {
|
||||
lastHours = maxLastHours
|
||||
} else if lastHours == 0 {
|
||||
lastHours = defLastHours
|
||||
}
|
||||
|
||||
db := dao.GetDB()
|
||||
err = dao.GetRows(db, &countInfo, `
|
||||
SELECT 0 lock_status, t1.status, COUNT(*) count
|
||||
FROM afs_order t1
|
||||
WHERE t1.vendor_id <> 2 AND IF(t1.vendor_id = ?, t1.store_id, IF(t1.jx_store_id != 0, t1.jx_store_id, t1.store_id) ) = ?
|
||||
AND t1.afs_created_at >= ?
|
||||
GROUP BY 1,2
|
||||
ORDER BY 1,2
|
||||
`, model.VendorIDWSC, storeID, time.Now().Add(-time.Duration(lastHours)*time.Hour))
|
||||
if err == nil {
|
||||
return countInfo, nil
|
||||
}
|
||||
globals.SugarLogger.Infof("GetStoreAfsOrderCountInfo storeID:%d failed with error:%v", storeID, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
|
||||
var (
|
||||
waybillOrderStatusMap = map[int]int{
|
||||
model.WaybillStatusApplyFailedGetGoods: model.WaybillStatusApplyFailedGetGoods,
|
||||
model.WaybillStatusAgreeFailedGetGoods: model.WaybillStatusAgreeFailedGetGoods,
|
||||
model.WaybillStatusRefuseFailedGetGoods: model.WaybillStatusRefuseFailedGetGoods,
|
||||
model.WaybillStatusDeliverFailed: model.WaybillStatusDeliverFailed,
|
||||
model.WaybillStatusApplyFailedGetGoods: model.OrderStatusApplyFailedGetGoods,
|
||||
model.WaybillStatusAgreeFailedGetGoods: model.OrderStatusAgreeFailedGetGoods,
|
||||
model.WaybillStatusRefuseFailedGetGoods: model.OrderStatusRefuseFailedGetGoods,
|
||||
model.WaybillStatusDeliverFailed: model.OrderStatusDeliverFailed,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -92,13 +92,48 @@ func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
duplicatedCount := 0
|
||||
if bill.Status == model.WaybillStatusNew {
|
||||
isDuplicated, err = w.onWaybillNew(bill, db)
|
||||
if isDuplicated {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
} else {
|
||||
if bill.Status == model.WaybillStatusAccepted { // 处理美团配送丢失新运单消息的情况
|
||||
existingBill, err2 := w.LoadWaybill(bill.VendorWaybillID, bill.WaybillVendorID)
|
||||
if err2 != nil {
|
||||
if dao.IsNoRowsError(err2) || err2 == ErrCanNotFindWaybill {
|
||||
if isDuplicated, err = w.onWaybillNew(bill, db); err != nil {
|
||||
dao.Rollback(db)
|
||||
return err
|
||||
}
|
||||
existingBill = bill
|
||||
billCopy := *bill
|
||||
billCopy.Status = model.WaybillStatusNew
|
||||
dao.Commit(db)
|
||||
// 进运单调度器OnWaybillStatusChanged之前要确保事务是提交了的,否则会导致死锁
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(&billCopy, false)
|
||||
dao.Begin(db)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
return err2
|
||||
}
|
||||
}
|
||||
// 运单消息错序,之前已经结束了,直接返回
|
||||
if existingBill.Status >= model.WaybillStatusEndBegin {
|
||||
dao.Commit(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
addParams := orm.Params{}
|
||||
if bill.Status >= model.WaybillStatusAccepted && bill.Status < model.WaybillStatusEndBegin {
|
||||
if bill.Status == model.WaybillStatusAccepted {
|
||||
addParams["desired_fee"] = bill.DesiredFee
|
||||
if bill.DesiredFee > 0 {
|
||||
addParams["desired_fee"] = bill.DesiredFee
|
||||
}
|
||||
if bill.ActualFee > 0 {
|
||||
addParams["actual_fee"] = bill.ActualFee
|
||||
}
|
||||
}
|
||||
if bill.CourierMobile != "" {
|
||||
addParams["courier_name"] = bill.CourierName
|
||||
@@ -107,11 +142,15 @@ func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||
} else if bill.Status >= model.WaybillStatusEndBegin {
|
||||
addParams["waybill_finished_at"] = bill.StatusTime
|
||||
}
|
||||
isDuplicated, err = w.addWaybillStatus(bill, db, addParams)
|
||||
duplicatedCount, err = w.addWaybillStatus(bill, db, addParams)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
if !isDuplicated {
|
||||
if duplicatedCount == 0 {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, false)
|
||||
}
|
||||
} else {
|
||||
@@ -136,21 +175,27 @@ func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db *dao.DaoDB, addParams orm.Params) (isDuplicated bool, err error) {
|
||||
func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db *dao.DaoDB, addParams orm.Params) (duplicatedCount int, err error) {
|
||||
waybillStatus := model.Waybill2Status(bill)
|
||||
isDuplicated, err = addOrderOrWaybillStatus(waybillStatus, db)
|
||||
if err == nil && !isDuplicated && waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法,状态不能回绕
|
||||
params := utils.MergeMaps(orm.Params{
|
||||
"status": bill.Status,
|
||||
"vendor_status": bill.VendorStatus,
|
||||
"status_time": bill.StatusTime,
|
||||
}, addParams)
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Filter("status__lte", bill.Status).Update(params)
|
||||
return err
|
||||
}, "addWaybillStatus update waybill status, bill:%v", bill)
|
||||
isDuplicated, err := addOrderOrWaybillStatus(waybillStatus, db)
|
||||
if err == nil && !isDuplicated {
|
||||
if waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法,状态不能回绕
|
||||
params := utils.MergeMaps(orm.Params{
|
||||
"status": bill.Status,
|
||||
"vendor_status": bill.VendorStatus,
|
||||
"status_time": bill.StatusTime,
|
||||
}, addParams)
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Filter("status__lte", bill.Status).Update(params)
|
||||
return err
|
||||
}, "addWaybillStatus update waybill status, bill:%v", bill)
|
||||
} else {
|
||||
duplicatedCount = -1
|
||||
}
|
||||
} else {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
return isDuplicated, err
|
||||
return duplicatedCount, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error) {
|
||||
@@ -160,6 +205,7 @@ func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int)
|
||||
WaybillVendorID: waybillVendorID,
|
||||
}
|
||||
if err = db.Read(bill, "VendorWaybillID", "WaybillVendorID"); err != nil {
|
||||
bill = nil
|
||||
if err == orm.ErrNoRows {
|
||||
err = ErrCanNotFindWaybill
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"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/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
@@ -54,16 +55,16 @@ func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusFinishedPickup {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
|
||||
if order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled == 0 && c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchasePlatformFromVendorID(order.VendorID).Swtich2SelfDeliver(order, userName)
|
||||
}, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order)
|
||||
}
|
||||
}
|
||||
if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup || order.VendorID == order.WaybillVendorID {
|
||||
@@ -106,7 +107,7 @@ func (c *BaseScheduler) SelfDeliverDelivering(order *model.GoodsOrder, userName
|
||||
}, "SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if err == nil { // 因为有些平台设置配送中后,不会发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order)
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -147,16 +148,28 @@ func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOr
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s, vendorID:%d is not solid!!!", order.VendorOrderID, platformVendorID)
|
||||
return nil, scheduler.ErrOrderIsNotSolid
|
||||
}
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
|
||||
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||||
// if order.DeliveryFlag&model.OrderDeliveryFlagMaskScheduleDisabled != 0 {
|
||||
// waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(jxcontext.AdminCtx, order.VendorOrderID, order.VendorID, true)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// if len(waybillList) > 0 {
|
||||
// return nil, fmt.Errorf("转商家自送的订单只允许有一个有效运单,当前已经有%s运单", jxutils.GetVendorName(waybillList[0].WaybillVendorID))
|
||||
// }
|
||||
// }
|
||||
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
|
||||
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
bill, err = handlerInfo.Handler.CreateWaybill(order, policy)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err)
|
||||
} else {
|
||||
order.DeliveryFlag |= model.WaybillVendorID2Mask(platformVendorID)
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrDeliverProviderWrong
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrDeliverProviderWrong
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
@@ -170,6 +183,8 @@ func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, c
|
||||
return handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
}, "CancelWaybill bill:%v", bill); err == nil {
|
||||
bill.Status = model.WaybillStatusCanceled
|
||||
bill.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
|
||||
_, err = dao.UpdateEntity(nil, bill, "Status", "DeliveryFlag")
|
||||
}
|
||||
globals.SugarLogger.Debugf("CancelWaybill bill:%v canceled by myself", bill)
|
||||
}
|
||||
|
||||
@@ -13,25 +13,38 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, policyHandler partner.CreateWaybillPolicy) (bills []*model.Waybill, err error) {
|
||||
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs []int, policyHandler partner.CreateWaybillPolicy, createOnlyOne bool) (bills []*model.Waybill, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s", order.VendorOrderID, userName)
|
||||
storeCourierList, err := dao.GetStoreCourierList(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), model.StoreStatusOpened)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var courierVendorIDMap map[int]bool
|
||||
if len(courierVendorIDs) > 0 {
|
||||
courierVendorIDMap = make(map[int]bool)
|
||||
for _, courierVendorID := range courierVendorIDs {
|
||||
courierVendorIDMap[courierVendorID] = true
|
||||
}
|
||||
}
|
||||
var errList []string
|
||||
for _, storeCourier := range storeCourierList {
|
||||
courierVendorID := storeCourier.VendorID
|
||||
if order.VendorID != model.VendorIDWSC || courierVendorID != model.VendorIDDada { // 达达作为微商城的自有配送,不参与配送竞争
|
||||
bill, err2 := c.CreateWaybill(courierVendorID, order, policyHandler)
|
||||
if err = err2; err == nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d bill:%v", order.VendorOrderID, userName, courierVendorID, bill)
|
||||
bills = append(bills, bill)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d failed with error:%v", order.VendorOrderID, userName, courierVendorID, err)
|
||||
errList = append(errList, fmt.Sprintf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
|
||||
if courierVendorIDMap == nil || courierVendorIDMap[storeCourier.VendorID] {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil && handler.Use4CreateWaybill {
|
||||
courierVendorID := storeCourier.VendorID
|
||||
if order.VendorID != model.VendorIDWSC || courierVendorID != model.VendorIDDada { // 达达作为微商城的自有配送,不参与配送竞争
|
||||
bill, err2 := c.CreateWaybill(courierVendorID, order, policyHandler)
|
||||
if err = err2; err == nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d bill:%v", order.VendorOrderID, userName, courierVendorID, bill)
|
||||
bills = append(bills, bill)
|
||||
if createOnlyOne {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d failed with error:%v", order.VendorOrderID, userName, courierVendorID, err)
|
||||
errList = append(errList, fmt.Sprintf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,8 +71,8 @@ func (c *BaseScheduler) SelfDeliveredAndUpdateStatus(ctx *jxcontext.Context, ven
|
||||
err = c.Swtich2SelfDelivered(order, userName)
|
||||
}
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusFinished
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order); err == nil {
|
||||
// order.Status = model.OrderStatusFinished // todo 是否需要强制设置完成状态?
|
||||
if err = dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskSetDelivered); err == nil {
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
@@ -81,7 +94,7 @@ func (c *BaseScheduler) PickupGoodsAndUpdateStatus(ctx *jxcontext.Context, vendo
|
||||
err = c.PickupGoods(order, c.GetStoreDeliveryType(order, nil) == scheduler.StoreDeliveryTypeByStore, userName)
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusFinishedPickup
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order); err == nil {
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
@@ -134,7 +147,7 @@ func (c *BaseScheduler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, ord
|
||||
err = partner.GetPurchasePlatformFromVendorID(order.VendorID).AcceptOrRefuseFailedGetOrder(ctx, order, isAcceptIt)
|
||||
}
|
||||
if err == nil {
|
||||
flag := int8(model.OrderFlagAgreeFailedGetGoods)
|
||||
flag := model.OrderFlagAgreeFailedGetGoods
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseFailedGetGoods
|
||||
}
|
||||
@@ -168,7 +181,7 @@ func (c *BaseScheduler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model
|
||||
err = partner.GetPurchasePlatformFromVendorID(order.VendorID).AgreeOrRefuseCancel(ctx, order, isAcceptIt, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := int8(model.OrderFlagAgreeUserApplyCancel)
|
||||
flag := model.OrderFlagAgreeUserApplyCancel
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseUserApplyCancel
|
||||
}
|
||||
@@ -176,3 +189,43 @@ func (c *BaseScheduler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybillByID(ctx *jxcontext.Context, vendorWaybillID string, waybillVendorID int, cancelReasonID int, cancelReason string) (err error) {
|
||||
bill, err := partner.CurOrderManager.LoadWaybill(vendorWaybillID, waybillVendorID)
|
||||
if err == nil {
|
||||
err = c.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrderID string, vendorID, approveType int, reason string) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchasePlatformFromVendorID(vendorID).AgreeOrRefuseRefund(ctx, afsOrder, approveType, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.AfsOrderFlagAgreeUserRefund
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
flag = model.AfsOrderFlagRefuseUserRefund
|
||||
afsOrder.RefuseReason = reason
|
||||
partner.CurOrderManager.UpdateAfsOrderFields(afsOrder, []string{"RefuseReason"})
|
||||
}
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, flag)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, afsOrderID string, vendorID int) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchasePlatformFromVendorID(vendorID).ConfirmReceivedReturnGoods(ctx, afsOrder)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, model.AfsOrderFlagMaskReturnGoods)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -25,9 +25,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
time2Delivered = 1 * time.Hour // 正常从下单到送达的时间。
|
||||
minute2Schedule3rdCarrier = 20 // 收到平台方自有配送的新运单消息后,等待创建三方配送运单的时间(分钟),如果是定时达,会再根据ExpectedDeliveredTime与dingShiDaAheadTime做调整
|
||||
minMinute2Schedule3rdCarrier = 5 // 转三方配送最少等待时间(分钟)
|
||||
time2Delivered = 1 * time.Hour // 正常从下单到送达的时间。
|
||||
minute2Schedule3rdCarrier = 20 // 收到平台方自有配送的新运单消息后,等待创建三方配送运单的时间(分钟),如果是定时达,会再根据ExpectedDeliveredTime与dingShiDaAheadTime做调整
|
||||
minute2Schedule3rdCarrier4Ebai = 30 // 饿百的最少转自配送需要的时间(分钟)
|
||||
minMinute2Schedule3rdCarrier = 5 // 转三方配送最少等待时间(分钟)
|
||||
|
||||
time2AutoPickupMin = 15 * time.Minute // 自动拣货等待时间,这个只有在没有PickDeadline信息才有用,否则会根据PickDeadline设置
|
||||
second2AutoPickupGap = 60 //随机60秒
|
||||
@@ -64,13 +65,22 @@ type WatchOrderInfo struct {
|
||||
timerStatusType int // 0表示订单,1表示运单
|
||||
timerStatus int
|
||||
timer *time.Timer
|
||||
timerTime time.Time
|
||||
|
||||
retryCount int // 失败后尝试的次数,调试阶段可能出现死循化,阻止这种情况发生
|
||||
}
|
||||
|
||||
type StatusActionConfig struct {
|
||||
partner.StatusActionParams
|
||||
TimeoutAction func(savedOrderInfo *WatchOrderInfo) (err error) // 超时后需要执行的动作,为nil表示此状态不需要执行监控, nil在GetStatusActionConfig返回时表示不修改缺省
|
||||
TimeoutAction func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (err error) // 超时后需要执行的动作,为nil表示此状态不需要执行监控, nil在GetStatusActionConfig返回时表示不修改缺省
|
||||
ShouldSetTimer func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool
|
||||
}
|
||||
|
||||
func (c *StatusActionConfig) CallShouldSetTimer(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
|
||||
if c.ShouldSetTimer != nil {
|
||||
return c.ShouldSetTimer(savedOrderInfo, bill)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 重要:此调度器要求同一定单的处理逻辑必须是序列化了的,不然会有并发问题
|
||||
@@ -114,11 +124,6 @@ func (s *WatchOrderInfo) updateOrderStoreFeature(order *model.GoodsOrder) (err e
|
||||
s.autoPickupTimeoutMinute = int(storeMap.AutoPickup)
|
||||
s.storeDeliveryType = FixedScheduler.GetStoreDeliveryType(order, storeMap)
|
||||
globals.SugarLogger.Debugf("updateOrderStoreFeature orderID:%s, s.storeDeliveryType:%d", order.VendorOrderID, s.storeDeliveryType)
|
||||
// if s.storeDeliveryType == scheduler.StoreDeliveryTypeByStore && (order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled) == 0 {
|
||||
// order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
// err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order)
|
||||
// }
|
||||
// globals.SugarLogger.Debugf("updateOrderStoreFeature orderID:%s, s.storeDeliveryType:%d, order.DeliveryFlag:%d", order.VendorOrderID, s.storeDeliveryType, order.DeliveryFlag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -136,7 +141,7 @@ func init() {
|
||||
TimerType: partner.TimerTypeBaseStatusTime,
|
||||
Timeout: 10 * time.Millisecond,
|
||||
},
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (err error) {
|
||||
order := savedOrderInfo.order
|
||||
mobile := order.ConsigneeMobile
|
||||
if order.ConsigneeMobile2 != "" {
|
||||
@@ -144,10 +149,14 @@ func init() {
|
||||
}
|
||||
_ = sch.handleAutoAcceptOrder(order.VendorOrderID, order.VendorID, mobile, jxutils.GetSaleStoreIDFromOrder(order), nil, func(isAcceptIt bool) error {
|
||||
if err = sch.AcceptOrRefuseOrder(order, isAcceptIt, ""); err != nil && err != scheduler.ErrOrderStatusAlreadySatisfyCurOperation {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "自动接单失败", err.Error())
|
||||
// 为了解决京东新消息与接单消息乱序的问题
|
||||
if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 && errWithCode.IntCode() == -1 {
|
||||
if order2, err2 := partner.GetPurchasePlatformFromVendorID(order.VendorID).GetOrder(order.VendorOrderID); err2 == nil && order2.Status > order.Status {
|
||||
sch.OnOrderStatusChanged(order, model.Order2Status(order2), false)
|
||||
order.Status = order2.Status
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
sch.OnOrderStatusChanged(order, model.Order2Status(order2), false)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
err = nil
|
||||
} else {
|
||||
err = err2
|
||||
@@ -165,6 +174,9 @@ func init() {
|
||||
})
|
||||
return nil
|
||||
},
|
||||
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
|
||||
return savedOrderInfo.order.Status == model.OrderStatusNew
|
||||
},
|
||||
},
|
||||
model.OrderStatusAccepted: &StatusActionConfig{ // 自动拣货
|
||||
StatusActionParams: partner.StatusActionParams{
|
||||
@@ -172,12 +184,17 @@ func init() {
|
||||
Timeout: time2AutoPickupMin,
|
||||
TimeoutGap: second2AutoPickupGap,
|
||||
},
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (err error) {
|
||||
if savedOrderInfo.autoPickupTimeoutMinute > 0 {
|
||||
return sch.autoPickupGood(savedOrderInfo)
|
||||
if err = sch.autoPickupGood(savedOrderInfo); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(savedOrderInfo.order, "自动拣货失败", err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
|
||||
return savedOrderInfo.autoPickupTimeoutMinute > 0
|
||||
},
|
||||
},
|
||||
model.OrderStatusFinishedPickup: &StatusActionConfig{
|
||||
StatusActionParams: partner.StatusActionParams{
|
||||
@@ -185,27 +202,62 @@ func init() {
|
||||
Timeout: 1 * time.Second,
|
||||
TimeoutGap: 0,
|
||||
},
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (err error) {
|
||||
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore { // 自配送商家使用
|
||||
return sch.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
|
||||
return savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore
|
||||
},
|
||||
},
|
||||
},
|
||||
map[int]*StatusActionConfig{
|
||||
// todo 平台物流二次创建运单的话,这个TIMER有问题
|
||||
model.WaybillStatusNew: &StatusActionConfig{
|
||||
StatusActionParams: partner.StatusActionParams{
|
||||
TimerType: partner.TimerTypeBaseStatusTime,
|
||||
Timeout: minute2Schedule3rdCarrier * time.Minute,
|
||||
},
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
if savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore { // 非自配送商家使用
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (err error) {
|
||||
// 饿百转自送的时机不太清楚,暂时禁用超时转自送,在饿百运单取消时还是会自动创建
|
||||
if savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore && savedOrderInfo.order.VendorID != model.VendorIDEBAI { // 非自配送商家使用
|
||||
return sch.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
|
||||
return savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore &&
|
||||
savedOrderInfo.order.VendorID == bill.WaybillVendorID &&
|
||||
savedOrderInfo.order.VendorID != model.VendorIDEBAI
|
||||
},
|
||||
},
|
||||
//*
|
||||
model.WaybillStatusCanceled: &StatusActionConfig{
|
||||
StatusActionParams: partner.StatusActionParams{
|
||||
TimerType: partner.TimerTypeBaseNow,
|
||||
Timeout: 5 * time.Second,
|
||||
},
|
||||
TimeoutAction: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (err error) {
|
||||
order := savedOrderInfo.order
|
||||
if (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) &&
|
||||
savedOrderInfo.order.VendorID == bill.WaybillVendorID &&
|
||||
savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore &&
|
||||
order.VendorID == model.VendorIDEBAI { // 非自配送商家使用
|
||||
return sch.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ShouldSetTimer: func(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) bool {
|
||||
order := savedOrderInfo.order
|
||||
return (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) &&
|
||||
savedOrderInfo.order.VendorID == bill.WaybillVendorID &&
|
||||
savedOrderInfo.storeDeliveryType != scheduler.StoreDeliveryTypeByStore &&
|
||||
order.VendorID == model.VendorIDEBAI
|
||||
},
|
||||
},
|
||||
//*/
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -243,10 +295,11 @@ func (s *DefScheduler) OnOrderStatusChanged(order *model.GoodsOrder, status *mod
|
||||
globals.SugarLogger.Debugf("OnOrderStatusChanged orderID:%s %s, status:%v", status.VendorOrderID, model.OrderStatusName[status.Status], status)
|
||||
if order == nil {
|
||||
globals.SugarLogger.Warnf("OnOrderStatusChanged order is nil, status:%s", utils.Format4Output(status, true))
|
||||
} else if order.Status > model.OrderStatusUnknown && status.Status > model.OrderStatusUnknown && order.Status != status.Status {
|
||||
globals.SugarLogger.Warnf("OnOrderStatusChanged strange order:%s, status:%s", utils.Format4Output(order, true), utils.Format4Output(status, true))
|
||||
}
|
||||
savedOrderInfo := s.loadSavedOrderFromMap(status, false)
|
||||
savedOrderInfo.SetOrder(order)
|
||||
// s.updateOrderByStatus(savedOrderInfo.order, status)
|
||||
|
||||
// if status.Status == model.OrderStatusNew {
|
||||
// if !isPending {
|
||||
@@ -259,7 +312,7 @@ func (s *DefScheduler) OnOrderStatusChanged(order *model.GoodsOrder, status *mod
|
||||
(order.LockStatus == model.OrderStatusUnknown && (status.Status > model.OrderStatusUnknown || status.Status == model.OrderStatusRefuseFailedGetGoods)) { // 只处理状态转换,一般消息不处理
|
||||
if status.Status == model.OrderStatusRefuseFailedGetGoods && order.Status != model.OrderStatusFinishedPickup && !model.IsOrderFinalStatus(order.Status) {
|
||||
order.Status = model.OrderStatusFinishedPickup
|
||||
partner.CurOrderManager.UpdateOrderStatusAndFlag(order)
|
||||
partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
s.resetTimer(savedOrderInfo, nil, isPending)
|
||||
if status.Status >= model.OrderStatusDelivering {
|
||||
@@ -271,12 +324,12 @@ func (s *DefScheduler) OnOrderStatusChanged(order *model.GoodsOrder, status *mod
|
||||
if !(status.Status == model.OrderStatusCanceled) { // 订单取消时,取消所有运单
|
||||
curWaybill = savedOrderInfo.waybills[savedOrderInfo.order.WaybillVendorID]
|
||||
if status.Status == model.OrderStatusFinished {
|
||||
if curWaybill != nil && curWaybill.WaybillVendorID != curWaybill.OrderVendorID {
|
||||
if curWaybill != nil && !model.IsWaybillPlatformOwn(curWaybill) {
|
||||
globals.SugarLogger.Infof("OnOrderStatusChanged [运营2]订单orderID:%s可能被手动点击送达,会对程序状态产生不利影响,请通知门店不要这样操作!", status.VendorOrderID)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.cancelOtherWaybills(savedOrderInfo, curWaybill, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrOrderAlreadyFinished)
|
||||
s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, curWaybill, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrOrderAlreadyFinished)
|
||||
if status.Status >= model.OrderStatusEndBegin {
|
||||
s.orderMap.Delete(jxutils.GetUniversalOrderIDFromOrderStatus(status))
|
||||
}
|
||||
@@ -285,12 +338,13 @@ func (s *DefScheduler) OnOrderStatusChanged(order *model.GoodsOrder, status *mod
|
||||
if order.LockStatus != model.OrderStatusUnknown {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
}
|
||||
if model.IsOrderLockStatus(status.Status) ||
|
||||
model.IsOrderUnlockStatus(status.Status) ||
|
||||
status.Status == model.OrderStatusApplyFailedGetGoods ||
|
||||
status.Status == model.OrderStatusAgreeFailedGetGoods ||
|
||||
status.Status == model.OrderStatusDeliverFailed {
|
||||
if isPending {
|
||||
if !isPending {
|
||||
if status.Status == model.OrderStatusFinishedPickup {
|
||||
msghub.OnFinishedPickup(savedOrderInfo.order)
|
||||
} else if status.Status == model.OrderStatusApplyCancel || //model.IsOrderLockStatus(status.Status) ||
|
||||
status.Status == model.OrderStatusApplyFailedGetGoods || //model.IsOrderUnlockStatus(status.Status) ||
|
||||
status.Status == model.OrderStatusAgreeFailedGetGoods ||
|
||||
status.Status == model.OrderStatusDeliverFailed {
|
||||
if status.Status == model.OrderStatusApplyCancel {
|
||||
utils.CallFuncAsync(func() {
|
||||
weixinmsg.NotifyUserApplyCancel(savedOrderInfo.order, status.Remark)
|
||||
@@ -323,10 +377,10 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
|
||||
if !isPending {
|
||||
if order.Status > model.OrderStatusEndBegin {
|
||||
s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
} else if s.IsOrderHasWaybill(order) {
|
||||
} else if model.IsOrderHaveWaybill(order) {
|
||||
globals.SugarLogger.Debugf("OnWaybillStatusChanged multiple waybill created, bill:%v", bill)
|
||||
if s.IsOrderPlatformWaybill(bill) { // 是购物平台运单
|
||||
if order.VendorID != order.WaybillVendorID { // 既有运单不是购物平台运单
|
||||
if model.IsWaybillPlatformOwn(bill) { // 是购物平台运单
|
||||
if !model.IsOrderHaveOwnWaybill(order) { // 既有运单不是购物平台运单
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged bill:%v purchase platform bill came later than others, strange!!!", bill)
|
||||
oldBill := savedOrderInfo.waybills[order.WaybillVendorID]
|
||||
if oldBill != nil {
|
||||
@@ -335,124 +389,146 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
|
||||
globals.SugarLogger.Warnf("OnWaybillStatusChanged bill:%v, oldBill is null, strange!!!", bill)
|
||||
}
|
||||
}
|
||||
bill.WaybillVendorID = model.VendorIDUnknown
|
||||
s.updateOrderByBill(order, bill, false)
|
||||
s.updateOrderByBill(order, nil, false)
|
||||
} else {
|
||||
s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
}
|
||||
}
|
||||
flag2Clear := model.WaybillVendorID2Mask(bill.WaybillVendorID)
|
||||
if order.DeliveryFlag&flag2Clear != 0 {
|
||||
order.DeliveryFlag &= ^flag2Clear
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
// 只有购物平台的新运单消息才会启动抢单TIMER
|
||||
if s.IsOrderPlatformWaybill(bill) {
|
||||
if model.IsWaybillPlatformOwn(bill) {
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
}
|
||||
} else {
|
||||
isBillExist := s.updateBillsInfo(savedOrderInfo, bill)
|
||||
if !isBillExist {
|
||||
// s.addWaybill2Map(savedOrderInfo, bill) // updateBillsInfo中会添加
|
||||
globals.SugarLogger.Debugf("OnWaybillStatusChanged bill not exist! orderID:%s, bill:%v", bill.VendorOrderID, bill)
|
||||
}
|
||||
switch bill.Status {
|
||||
case model.WaybillStatusAccepted:
|
||||
case model.WaybillStatusAccepted, model.WaybillStatusCourierArrived, model.WaybillStatusDelivering:
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
if (isBillExist || bill.WaybillVendorID != model.VendorIDDada) && !isPending { // todo 达达运单有错序的情况,临时看看
|
||||
isBillAlreadyCandidate := s.isBillCandidate(order, bill)
|
||||
// todo 购买平台的运单,优先级最高,但这样写也可能带来问题,即在这个时间,因为之前3方已经接单,已经发出了转自送请求(而且可能成功了),所以加个状态判断
|
||||
if order.WaybillVendorID == model.VendorIDUnknown ||
|
||||
(s.IsOrderPlatformWaybill(bill) && order.VendorID != order.WaybillVendorID && (order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled) == 0) {
|
||||
if s.IsOrderHasWaybill(order) {
|
||||
if !model.IsOrderHaveWaybill(order) ||
|
||||
(model.IsWaybillPlatformOwn(bill) && !model.IsOrderHaveOwnWaybill(order) && (order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled) == 0) {
|
||||
if model.IsOrderHaveWaybill(order) {
|
||||
// 进到这里的原因是,在这个时间点,购物平台物流已经抢单(但抢单消息还没有被收到)(比如:818810379000941)
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged orderID:%s purchase platform waybill arrvied later, may case problem", order.VendorOrderID)
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged orderID:%s purchase platform waybill arrvied later, may cause problem", order.VendorOrderID)
|
||||
}
|
||||
s.updateOrderByBill(order, bill, false)
|
||||
s.cancelOtherWaybills(savedOrderInfo, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
if !s.IsOrderPlatformWaybill(bill) {
|
||||
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore {
|
||||
s.SelfDeliverDelivering(savedOrderInfo.order, bill.CourierMobile)
|
||||
s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
|
||||
if model.IsWaybillPlatformOwn(bill) {
|
||||
if bill.Status == model.WaybillStatusDelivering {
|
||||
// 强制将订单状态置为配送中?
|
||||
order.Status = model.OrderStatusDelivering
|
||||
partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
} else {
|
||||
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore ||
|
||||
model.IsSpecialOrderPlatformWaybill(bill) {
|
||||
if err := s.SelfDeliverDelivering(savedOrderInfo.order, bill.CourierMobile); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "自送出设置失败", err.Error())
|
||||
}
|
||||
utils.CallFuncAsync(func() {
|
||||
weixinmsg.NotifyWaybillStatus(bill, order, isBillAlreadyCandidate)
|
||||
})
|
||||
} else {
|
||||
s.swtich2SelfDeliverWithRetry(savedOrderInfo, bill, 2, 10*time.Second)
|
||||
}
|
||||
} else if s.IsSpecialOrderPlatformWaybill(bill) {
|
||||
s.SelfDeliverDelivering(savedOrderInfo.order, bill.CourierMobile)
|
||||
}
|
||||
} else if !s.isBillCandidate(order, bill) && bill.WaybillVendorID != order.VendorID {
|
||||
// 发生这种情况的原因就是两个接单事件几乎同时到达(来不及取消),也算正常
|
||||
s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged Accepted orderID:%s got multiple bill:%v", order.VendorOrderID, bill)
|
||||
}
|
||||
if s.isBillCandidate(order, bill) && order.WaybillVendorID != order.VendorID {
|
||||
if !isBillAlreadyCandidate || !s.isWaybillCourierSame(savedOrderInfo, bill) {
|
||||
utils.CallFuncAsync(func() {
|
||||
weixinmsg.NotifyWaybillStatus(bill, order, isBillAlreadyCandidate)
|
||||
})
|
||||
}
|
||||
if isBillAlreadyCandidate && !s.isWaybillCourierSame(savedOrderInfo, bill) && !model.IsWaybillPlatformOwn(bill) {
|
||||
utils.CallFuncAsync(func() {
|
||||
weixinmsg.NotifyWaybillStatus(bill, order, isBillAlreadyCandidate)
|
||||
})
|
||||
}
|
||||
flag2Clear := model.WaybillVendorID2Mask(bill.WaybillVendorID)
|
||||
if order.DeliveryFlag&flag2Clear != 0 {
|
||||
order.DeliveryFlag &= ^flag2Clear
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
case model.WaybillStatusAcceptCanceled:
|
||||
if s.isBillCandidate(order, bill) {
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
if !isPending {
|
||||
bill.WaybillVendorID = model.VendorIDUnknown
|
||||
s.updateOrderByBill(order, bill, false)
|
||||
|
||||
// 取消抢单应该不需要发3方运单
|
||||
// s.createWaybillOn3rdProviders(savedOrderInfo, bill)
|
||||
s.updateOrderByBill(order, nil, true)
|
||||
}
|
||||
} else if s.IsOrderHasWaybill(order) {
|
||||
} else if model.IsOrderHaveWaybill(order) {
|
||||
s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
if !isPending {
|
||||
globals.SugarLogger.Warnf("OnWaybillStatusChanged AcceptCanceled orderID:%s got multiple bill:%v, order details:%v", order.VendorOrderID, bill, order)
|
||||
}
|
||||
}
|
||||
case model.WaybillStatusCourierArrived: // do nothing
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
if s.isBillCandidate(order, bill) {
|
||||
} else {
|
||||
// s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged CourierArrived order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
|
||||
}
|
||||
// case model.WaybillStatusCourierArrived: // do nothing
|
||||
// s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
// if s.isBillCandidate(order, bill) {
|
||||
// } else {
|
||||
// // s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
// globals.SugarLogger.Infof("OnWaybillStatusChanged CourierArrived order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
|
||||
// }
|
||||
case model.WaybillStatusCanceled, model.WaybillStatusFailed:
|
||||
s.removeWaybillFromMap(savedOrderInfo, bill.WaybillVendorID)
|
||||
if s.isBillCandidate(order, bill) || order.WaybillVendorID == model.VendorIDUnknown {
|
||||
s.resetTimer(savedOrderInfo, nil, isPending)
|
||||
if !isPending {
|
||||
if s.IsOrderHasWaybill(order) {
|
||||
bill.WaybillVendorID = model.VendorIDUnknown
|
||||
s.updateOrderByBill(order, bill, false)
|
||||
if model.IsOrderHaveWaybill(order) {
|
||||
s.updateOrderByBill(order, nil, true)
|
||||
}
|
||||
// 3方的运单取消才会重新发起创建3方订单,购物平台的运单取消后,它本身还会再创建新运单(NewWaybill事件有相应TIMER)),至少京东是这样的,暂时按京东的行为来
|
||||
// 现在发现饿百取消订单后不会再创建运单了,所以饿百运单取消也允许直接创建三方运单
|
||||
// 之前的条件是order.Status < model.OrderStatusDelivering,但像订单902322817000122确实有在配送中取消状态,改成非订单结束状态都可以
|
||||
// OrderStatusFinishedPickup状态的订单依赖于TIMER重新建运单
|
||||
if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin && (bill.WaybillVendorID != order.VendorID || order.VendorID == model.VendorIDEBAI) {
|
||||
s.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
if bill.DeliveryFlag&model.WaybillDeliveryFlagMaskActiveCancel == 0 {
|
||||
if (order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) && (bill.WaybillVendorID != order.VendorID /* || bill.WaybillVendorID == model.VendorIDEBAI*/) {
|
||||
s.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case model.WaybillStatusDelivering:
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
if s.isBillCandidate(order, bill) {
|
||||
// do nothing
|
||||
} else {
|
||||
// s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged Delivering order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
|
||||
}
|
||||
// case model.WaybillStatusDelivering:
|
||||
// s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
// if s.isBillCandidate(order, bill) {
|
||||
// // do nothing
|
||||
// } else {
|
||||
// // s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonNotAcceptIntime, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
// globals.SugarLogger.Infof("OnWaybillStatusChanged Delivering order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
|
||||
// }
|
||||
case model.WaybillStatusDelivered:
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
s.removeWaybillFromMap(savedOrderInfo, bill.WaybillVendorID)
|
||||
if !s.IsOrderPlatformWaybill(bill) && !isPending {
|
||||
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore {
|
||||
s.SelfDeliverDelivered(order, "")
|
||||
} else {
|
||||
s.Swtich2SelfDelivered(order, "")
|
||||
if !isPending {
|
||||
var err2 error
|
||||
if !model.IsWaybillPlatformOwn(bill) {
|
||||
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore {
|
||||
err2 = s.SelfDeliverDelivered(order, "")
|
||||
} else {
|
||||
err2 = s.Swtich2SelfDelivered(order, "")
|
||||
}
|
||||
} else if model.IsSpecialOrderPlatformWaybill(bill) {
|
||||
err2 = s.SelfDeliverDelivered(savedOrderInfo.order, "")
|
||||
}
|
||||
if err2 != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "送达设置失败", err2.Error())
|
||||
}
|
||||
} else if s.IsSpecialOrderPlatformWaybill(bill) {
|
||||
s.SelfDeliverDelivered(savedOrderInfo.order, "")
|
||||
}
|
||||
if !s.isBillCandidate(order, bill) {
|
||||
// 一般只会消息乱序才会到这里,即新订单消息在运单接单消息后到达
|
||||
// 典型的一个:1223633660228537567
|
||||
globals.SugarLogger.Infof("OnWaybillStatusChanged Delivered order(%d, %s) bill(%d, %s), bill:%v shouldn't get here", order.WaybillVendorID, order.VendorWaybillID, bill.WaybillVendorID, bill.VendorWaybillID, bill)
|
||||
if order.WaybillVendorID == model.VendorIDUnknown {
|
||||
if !model.IsOrderHaveWaybill(order) {
|
||||
s.updateOrderByBill(order, bill, false)
|
||||
}
|
||||
}
|
||||
@@ -461,14 +537,16 @@ func (s *DefScheduler) OnWaybillStatusChanged(bill *model.Waybill, isPending boo
|
||||
weixinmsg.NotifyWaybillStatus(bill, order, false)
|
||||
})
|
||||
}
|
||||
case model.WaybillStatusNeverSend: // 平台不配送,直接创建三方运单
|
||||
// case model.WaybillStatusNeverSend: // 平台不配送,直接创建三方运单
|
||||
// s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
// s.removeWaybillFromMap(savedOrderInfo, bill.WaybillVendorID)
|
||||
// if order.WaybillVendorID == model.VendorIDUnknown {
|
||||
// s.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
// }
|
||||
default:
|
||||
s.resetTimer(savedOrderInfo, bill, isPending)
|
||||
s.removeWaybillFromMap(savedOrderInfo, bill.WaybillVendorID)
|
||||
if order.WaybillVendorID == model.VendorIDUnknown {
|
||||
s.createWaybillOn3rdProviders(savedOrderInfo, nil)
|
||||
}
|
||||
}
|
||||
s.updateBillsInfo(savedOrderInfo, bill) // 更新可能的运单状态变化
|
||||
// s.updateBillsInfo(savedOrderInfo, bill) // 更新可能的运单状态变化
|
||||
}
|
||||
// }
|
||||
}
|
||||
@@ -481,7 +559,7 @@ func (s *DefScheduler) isWaybillCourierSame(savedOrderInfo *WatchOrderInfo, bill
|
||||
|
||||
func (s *DefScheduler) addWaybill2Map(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) {
|
||||
if _, ok := savedOrderInfo.waybills[bill.WaybillVendorID]; ok {
|
||||
if !s.IsOrderPlatformWaybill(bill) { // 购买平台重复发相同号的新运单是正常的,京东就是
|
||||
if !model.IsWaybillPlatformOwn(bill) { // 购买平台重复发相同号的新运单是正常的,京东就是
|
||||
globals.SugarLogger.Warnf("addWaybill2Map bill:%v already exists", bill)
|
||||
}
|
||||
}
|
||||
@@ -503,17 +581,17 @@ func (s *DefScheduler) createWaybillOn3rdProviders(savedOrderInfo *WatchOrderInf
|
||||
if err = s.canOrderCreateWaybillNormally(order); err == nil {
|
||||
if (order.DeliveryFlag & model.OrderDeliveryFlagMaskScheduleDisabled) == 0 {
|
||||
if savedOrderInfo.retryCount <= maxWaybillRetryCount {
|
||||
_, err = s.CreateWaybillOnProviders4SavedOrder(jxcontext.AdminCtx, savedOrderInfo, false)
|
||||
savedOrderInfo.retryCount++
|
||||
_, err = s.CreateWaybillOnProviders4SavedOrder(jxcontext.AdminCtx, savedOrderInfo, nil, false, 0, 0)
|
||||
} else {
|
||||
err = fmt.Errorf("订单:%s已经自动创建过了%d次运单,请人工处理", order.VendorOrderID, savedOrderInfo.retryCount)
|
||||
globals.SugarLogger.Infof("createWaybillOn3rdProviders [运营]同一订单orderID:%s尝试了%d次创建运单失败, 停止调度,如果还需要发单,请人工处理", order.VendorOrderID, savedOrderInfo.retryCount)
|
||||
globals.SugarLogger.Infof("createWaybillOn3rdProviders [运营2]同一订单orderID:%s尝试了%d次创建运单失败, 停止调度,如果还需要发单,请人工处理", order.VendorOrderID, savedOrderInfo.retryCount)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("createWaybillOn3rdProviders, orderID:%s, store:%d dont't support 3rd delivery platform", order.VendorOrderID, jxutils.GetSaleStoreIDFromOrder(order))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "自动创建三方运单", utils.LimitUTF8StringLen(err.Error(), 255))
|
||||
partner.CurOrderManager.OnOrderMsg(order, "自动创建三方运单失败", err.Error())
|
||||
}
|
||||
} else {
|
||||
err = nil
|
||||
@@ -521,73 +599,79 @@ func (s *DefScheduler) createWaybillOn3rdProviders(savedOrderInfo *WatchOrderInf
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) cancelOtherWaybills(savedOrderInfo *WatchOrderInfo, bill2Keep *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybills, orderID:%s, bill:%v", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
func (s *DefScheduler) cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo *WatchOrderInfo, bill2Keep *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybillsCheckOrderDeliveryFlag, orderID:%s, bill:%v", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
if (savedOrderInfo.order.DeliveryFlag & model.OrderDeliveryFlagMaskScheduleDisabled) == 0 {
|
||||
err = s.cancelOtherWaybills2(savedOrderInfo, bill2Keep, cancelReasonID, cancelReason)
|
||||
err = s.cancelOtherWaybills(savedOrderInfo, bill2Keep, cancelReasonID, cancelReason)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybills, orderID:%s, bill:%v stop schedule", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybillsCheckOrderDeliveryFlag, orderID:%s, bill:%v stop schedule", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) cancelOtherWaybills2(savedOrderInfo *WatchOrderInfo, bill2Keep *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybills2, orderID:%s, bill:%v", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
toBeDeleted := []*model.Waybill{}
|
||||
func (s *DefScheduler) cancelOtherWaybills(savedOrderInfo *WatchOrderInfo, bill2Keep *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybills, orderID:%s, bill:%v", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
for _, v := range savedOrderInfo.waybills {
|
||||
if !s.IsOrderPlatformWaybill(v) && (bill2Keep == nil || !(v.WaybillVendorID == bill2Keep.WaybillVendorID && v.VendorWaybillID == bill2Keep.VendorWaybillID)) {
|
||||
err2 := s.ProxyCancelWaybill(savedOrderInfo.order, v, cancelReasonID, cancelReason)
|
||||
if v.Status < model.WaybillStatusEndBegin &&
|
||||
!model.IsWaybillPlatformOwn(v) &&
|
||||
(bill2Keep == nil || !(v.WaybillVendorID == bill2Keep.WaybillVendorID && v.VendorWaybillID == bill2Keep.VendorWaybillID)) {
|
||||
err2 := s.CancelWaybill(v, cancelReasonID, cancelReason)
|
||||
if err2 == nil {
|
||||
toBeDeleted = append(toBeDeleted, v)
|
||||
}
|
||||
// 至少返回一个错误
|
||||
if err == nil && err2 != nil {
|
||||
err = err2
|
||||
// 在这里就从map里删除,而不是等收到运单结束事件才删除,可避免不必要的重复取消(第二次取消还会失败)
|
||||
s.removeWaybillFromMap(savedOrderInfo, v.WaybillVendorID)
|
||||
} else {
|
||||
// 至少返回一个错误
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
partner.CurOrderManager.OnOrderMsg(savedOrderInfo.order, "取消三方运单失败", err2.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(toBeDeleted) > 0 {
|
||||
// todo 这里为什么要删除运单,应该只需要在运单完成,取消或失败时才删除
|
||||
// for _, v := range toBeDeleted {
|
||||
// s.removeWaybillFromMap(savedOrderInfo, v.WaybillVendorID)
|
||||
// }
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("cancelOtherWaybills, orderID:%s, bill:%v cancel 0 bills", savedOrderInfo.order.VendorOrderID, bill2Keep)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) swtich2SelfDeliverWithRetry(savedOrderInfo *WatchOrderInfo, bill *model.Waybill, retryCount int, duration time.Duration) {
|
||||
order := savedOrderInfo.order
|
||||
globals.SugarLogger.Debugf("swtich2SelfDeliverWithRetry orderID:%s", order.VendorOrderID)
|
||||
if (order.DeliveryFlag & model.OrderDeliveryFlagMaskPurcahseDisabled) == 0 {
|
||||
if order.WaybillVendorID != order.VendorID {
|
||||
if err := s.Swtich2SelfDeliver(order, ""); err != nil && err != scheduler.ErrOrderStatusAlreadySatisfyCurOperation {
|
||||
globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry failed, bill:%v, err:%v", bill, err)
|
||||
if retryCount > 0 {
|
||||
utils.AfterFuncWithRecover(duration, func() {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
s.swtich2SelfDeliverWithRetry(savedOrderInfo, bill, retryCount-1, duration)
|
||||
}, order.VendorOrderID)
|
||||
})
|
||||
} else {
|
||||
globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry finally failed, orderID:%s bill:%v, err:%v", order.VendorOrderID, bill, err)
|
||||
if s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonSwitch2SelfFailed, partner.CancelWaybillReasonStrSwitch2SelfFailed) == nil {
|
||||
// 转自送失败的取消,要将订单中的运单状态更新
|
||||
if s.isBillCandidate(order, bill) {
|
||||
bill.WaybillVendorID = model.VendorIDUnknown
|
||||
s.updateOrderByBill(order, bill, false)
|
||||
}
|
||||
if order.WaybillVendorID != order.VendorID {
|
||||
if err := s.Swtich2SelfDeliver(order, ""); err != nil && err != scheduler.ErrOrderStatusAlreadySatisfyCurOperation {
|
||||
globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry failed, bill:%v, err:%v", bill, err)
|
||||
if retryCount > 0 {
|
||||
utils.AfterFuncWithRecover(duration, func() {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
s.swtich2SelfDeliverWithRetry(savedOrderInfo, bill, retryCount-1, duration)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
})
|
||||
} else {
|
||||
errStr := fmt.Sprintf("订单:%s转自配送失败, 错误信息:%v", order.VendorOrderID, err)
|
||||
globals.SugarLogger.Info(errStr)
|
||||
if s.ProxyCancelWaybill(order, bill, partner.CancelWaybillReasonSwitch2SelfFailed, partner.CancelWaybillReasonStrSwitch2SelfFailed) == nil {
|
||||
// 转自送失败的取消,要将订单中的运单状态更新
|
||||
if s.isBillCandidate(order, bill) {
|
||||
s.updateOrderByBill(order, nil, false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.removeWaybillFromMap(savedOrderInfo, order.VendorID)
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag"})
|
||||
|
||||
partner.CurOrderManager.OnOrderMsg(order, "转商家自配送失败", errStr)
|
||||
}
|
||||
} else {
|
||||
// 进到这里的原因是,在这个时间点,购物平台物流已经抢单(但抢单消息还没有被收到),所以转自送会失败 (比如:818810379000941),更好的做法应该是判断Swtich2SelfDeliver的返回值,这种情况下就不得试了
|
||||
globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry orderID:%s status is wrong(maybe purchase platform accepted waybill)", order.VendorOrderID)
|
||||
// globals.SugarLogger.Warnf("swtich2SelfDeliverWithRetry orderID:%s status is wrong, order details:%v", order.VendorOrderID, order)
|
||||
utils.CallFuncAsync(func() {
|
||||
weixinmsg.NotifyWaybillStatus(bill, order, false)
|
||||
})
|
||||
s.removeWaybillFromMap(savedOrderInfo, order.VendorID)
|
||||
}
|
||||
} else {
|
||||
s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrNotAcceptIntime)
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag"})
|
||||
|
||||
// 进到这里的原因是,在这个时间点,购物平台物流已经抢单(但抢单消息还没有被收到),所以转自送会失败 (比如:818810379000941),更好的做法应该是判断Swtich2SelfDeliver的返回值,这种情况下就不得试了
|
||||
globals.SugarLogger.Infof("swtich2SelfDeliverWithRetry orderID:%s status is wrong(maybe purchase platform accepted waybill)", order.VendorOrderID)
|
||||
partner.CurOrderManager.OnOrderMsg(order, "转商家自配送失败", "平台物流已接单")
|
||||
// globals.SugarLogger.Warnf("swtich2SelfDeliverWithRetry orderID:%s status is wrong, order details:%v", order.VendorOrderID, order)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,7 +708,7 @@ func (s *DefScheduler) stopTimer(savedOrderInfo *WatchOrderInfo) {
|
||||
if savedOrderInfo.timer != nil {
|
||||
globals.SugarLogger.Debugf("stopTimer orderID:%s", savedOrderInfo.order.VendorOrderID)
|
||||
savedOrderInfo.timer.Stop()
|
||||
savedOrderInfo.timerStatus = 0
|
||||
savedOrderInfo.timerStatus = model.OrderStatusUnknown
|
||||
savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown
|
||||
savedOrderInfo.timer = nil
|
||||
}
|
||||
@@ -641,47 +725,61 @@ func (s *DefScheduler) resetTimer(savedOrderInfo *WatchOrderInfo, bill *model.Wa
|
||||
statusTime = bill.StatusTime
|
||||
}
|
||||
globals.SugarLogger.Debugf("resetTimer, orderID:%s statusType:%d status:%v", order.VendorOrderID, statusType, status)
|
||||
if statusType != savedOrderInfo.timerStatusType || status >= savedOrderInfo.timerStatus { // 新设置的TIMER不能覆盖状态在其后的TIMER,如果状态回绕,需要注意
|
||||
if isStatusNewer(savedOrderInfo.timerStatusType, savedOrderInfo.timerStatus, statusType, status) { // 新设置的TIMER不能覆盖状态在其后的TIMER,如果状态回绕,需要注意
|
||||
config := s.mergeOrderStatusConfig(savedOrderInfo, statusTime, statusType, status)
|
||||
if config == nil || config.TimerType != partner.TimerTypeByPass {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
}
|
||||
if config != nil && config.TimeoutAction != nil && config.TimerType != partner.TimerTypeByPass {
|
||||
timeout := config.GetRefTimeout(statusTime)
|
||||
if config.TimeoutGap != 0 {
|
||||
timeout += time.Duration(rand.Intn(int(config.TimeoutGap))) * time.Second
|
||||
}
|
||||
if isPending && timeout < pendingOrderTimerMaxSecond*time.Second { // 如果是PENDING的订单,则将其分布到2--5秒内,让后续事件有机会执行
|
||||
timeout = time.Duration(jxutils.MapValue2Scope(int64(timeout), -pendingOrderTimerMinMinSecond*1000, pendingOrderTimerMaxSecond*1000, pendingOrderTimerMinSecond*1000, pendingOrderTimerMaxSecond*1000)) * time.Millisecond
|
||||
} else if timeout < 0 {
|
||||
timeout = 0
|
||||
}
|
||||
if timeout == 0 {
|
||||
config.TimeoutAction(savedOrderInfo)
|
||||
} else {
|
||||
timerName := ""
|
||||
if statusType == scheduler.TimerStatusTypeOrder {
|
||||
timerName = model.OrderStatusName[status]
|
||||
} else if statusType == scheduler.TimerStatusTypeWaybill {
|
||||
timerName = model.WaybillStatusName[status]
|
||||
if config.CallShouldSetTimer(savedOrderInfo, bill) {
|
||||
timeout := config.GetRefTimeout(statusTime, order.OrderCreatedAt)
|
||||
if config.TimeoutGap != 0 {
|
||||
timeout += time.Duration(rand.Intn(int(config.TimeoutGap))) * time.Second
|
||||
}
|
||||
savedOrderInfo.timerStatusType = statusType
|
||||
savedOrderInfo.timerStatus = status
|
||||
savedOrderInfo.timer = utils.AfterFuncWithRecover(timeout, func() {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
globals.SugarLogger.Debugf("fire timer:%s, orderID:%s", timerName, order.VendorOrderID)
|
||||
savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), true)
|
||||
config.TimeoutAction(savedOrderInfo)
|
||||
savedOrderInfo.timerStatus = 0
|
||||
savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown
|
||||
}, order.VendorOrderID)
|
||||
})
|
||||
if isPending && timeout < pendingOrderTimerMaxSecond*time.Second { // 如果是PENDING的订单,则将其分布到2--5秒内,让后续事件有机会执行
|
||||
timeout = time.Duration(jxutils.MapValue2Scope(int64(timeout), -pendingOrderTimerMinMinSecond*1000, pendingOrderTimerMaxSecond*1000, pendingOrderTimerMinSecond*1000, pendingOrderTimerMaxSecond*1000)) * time.Millisecond
|
||||
} else if timeout < 0 {
|
||||
timeout = 0
|
||||
}
|
||||
if timeout == 0 {
|
||||
config.TimeoutAction(savedOrderInfo, bill)
|
||||
} else {
|
||||
timerName := ""
|
||||
if statusType == scheduler.TimerStatusTypeOrder {
|
||||
timerName = model.OrderStatusName[status]
|
||||
} else if statusType == scheduler.TimerStatusTypeWaybill {
|
||||
timerName = model.WaybillStatusName[status]
|
||||
}
|
||||
savedOrderInfo.timerStatusType = statusType
|
||||
savedOrderInfo.timerStatus = status
|
||||
savedOrderInfo.timerTime = time.Now().Add(timeout)
|
||||
savedOrderInfo.timer = utils.AfterFuncWithRecover(timeout, func() {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
globals.SugarLogger.Debugf("fire timer:%s, orderID:%s", timerName, order.VendorOrderID)
|
||||
savedOrderInfo := s.loadSavedOrderFromMap(model.Order2Status(order), true)
|
||||
config.TimeoutAction(savedOrderInfo, bill)
|
||||
savedOrderInfo.timerStatus = 0
|
||||
savedOrderInfo.timerStatusType = scheduler.TimerStatusTypeUnknown
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
})
|
||||
}
|
||||
globals.SugarLogger.Debugf("resetTimer, orderID:%s, status:%d, timeout:%v", order.VendorOrderID, status, timeout)
|
||||
}
|
||||
globals.SugarLogger.Debugf("resetTimer, orderID:%s, status:%d, timeout:%v", order.VendorOrderID, status, timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isStatusNewer(curStatusType, curStatus, statusType, status int) bool {
|
||||
// 拣货完成及之前的订单事件TIMER不能覆盖运单TIMER(一般是消息错序引起的)
|
||||
if curStatusType == scheduler.TimerStatusTypeWaybill && statusType == scheduler.TimerStatusTypeOrder && status <= model.OrderStatusFinishedPickup {
|
||||
return false
|
||||
}
|
||||
if curStatusType == scheduler.TimerStatusTypeWaybill {
|
||||
return curStatus != status
|
||||
}
|
||||
return curStatusType != statusType || status >= curStatus
|
||||
}
|
||||
|
||||
func (s *DefScheduler) mergeOrderStatusConfig(savedOrderInfo *WatchOrderInfo, statusTime time.Time, statusType, status int) (retVal *StatusActionConfig) {
|
||||
s.locker.RLock()
|
||||
defer func() {
|
||||
@@ -709,7 +807,7 @@ func (s *DefScheduler) mergeOrderStatusConfig(savedOrderInfo *WatchOrderInfo, st
|
||||
TimeoutGap: -1,
|
||||
}
|
||||
timeout := statusTime.Sub(time.Now()) + minMinute2Schedule3rdCarrier*time.Minute
|
||||
if vendorActionParams.GetRefTimeout(statusTime) < timeout { // 如果非立即达订单,根据ExpectedDeliveredTime算出来的timeout太早
|
||||
if vendorActionParams.GetRefTimeout(statusTime, order.OrderCreatedAt) < timeout { // 如果非立即达订单,根据ExpectedDeliveredTime算出来的timeout太早
|
||||
vendorActionParams.Timeout = timeout
|
||||
vendorActionParams.TimeoutGap = 0
|
||||
}
|
||||
@@ -742,10 +840,18 @@ func (s *DefScheduler) mergeOrderStatusConfig(savedOrderInfo *WatchOrderInfo, st
|
||||
}
|
||||
}
|
||||
} else { // 有最后拣货时间,反推
|
||||
timeout := order.PickDeadline.Sub(time.Now()) - (time2AutoPickupAhead + second2AutoPickupGap*time.Second)
|
||||
realSecond2AutoPickupGap := second2AutoPickupGap
|
||||
if realSecond2AutoPickupGap > int(timeout/time.Second) {
|
||||
realSecond2AutoPickupGap = int(timeout / time.Second)
|
||||
if realSecond2AutoPickupGap < 0 {
|
||||
realSecond2AutoPickupGap = 0
|
||||
}
|
||||
}
|
||||
vendorActionParams = &partner.StatusActionParams{
|
||||
TimerType: partner.TimerTypeBaseNow,
|
||||
Timeout: order.PickDeadline.Sub(time.Now()) - time2AutoPickupAhead - second2AutoPickupGap*time.Second,
|
||||
TimeoutGap: second2AutoPickupGap,
|
||||
Timeout: timeout,
|
||||
TimeoutGap: realSecond2AutoPickupGap,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -795,40 +901,39 @@ func (s *DefScheduler) handleAutoAcceptOrder(orderID string, vendorID int, userM
|
||||
return handleType
|
||||
}
|
||||
|
||||
// func (s *DefScheduler) updateOrderByStatus(order *model.GoodsOrder, status *model.OrderStatus) (retVal *model.GoodsOrder) {
|
||||
// order.Status = status.Status
|
||||
// order.VendorStatus = status.VendorStatus
|
||||
// order.StatusTime = status.StatusTime
|
||||
// order.LockStatus = status.LockStatus
|
||||
// return order
|
||||
// }
|
||||
|
||||
func (s *DefScheduler) updateOrderByBill(order *model.GoodsOrder, bill *model.Waybill, revertStatus bool) {
|
||||
if order.Status > model.OrderStatusEndBegin {
|
||||
return
|
||||
}
|
||||
if bill.WaybillVendorID == model.VendorIDUnknown {
|
||||
bill.VendorWaybillID = ""
|
||||
updateFields := []string{
|
||||
"WaybillVendorID",
|
||||
"VendorWaybillID",
|
||||
}
|
||||
if bill == nil {
|
||||
order.WaybillVendorID = model.VendorIDUnknown
|
||||
order.VendorWaybillID = ""
|
||||
} else {
|
||||
order.WaybillVendorID = bill.WaybillVendorID
|
||||
order.VendorWaybillID = bill.VendorWaybillID
|
||||
}
|
||||
partner.CurOrderManager.UpdateWaybillVendorID(bill, revertStatus)
|
||||
order.WaybillVendorID = bill.WaybillVendorID
|
||||
order.VendorWaybillID = bill.VendorWaybillID
|
||||
if revertStatus {
|
||||
order.Status = model.OrderStatusFinishedPickup
|
||||
partner.CurOrderManager.UpdateOrderStatusAndFlag(order)
|
||||
updateFields = append(updateFields, "Status")
|
||||
}
|
||||
partner.CurOrderManager.UpdateOrderFields(order, updateFields)
|
||||
}
|
||||
|
||||
func (s *DefScheduler) updateBillsInfo(savedOrderInfo *WatchOrderInfo, bill *model.Waybill) (isBillExist bool) {
|
||||
if savedOrderInfo != nil {
|
||||
if savedBill := savedOrderInfo.waybills[bill.WaybillVendorID]; savedBill != nil {
|
||||
isBillExist = true
|
||||
if savedBill.Status > bill.Status {
|
||||
bill.Status = savedBill.Status
|
||||
} else if bill.Status > savedBill.Status {
|
||||
savedBill.Status = bill.Status
|
||||
}
|
||||
// if savedBill.Status > bill.Status {
|
||||
// bill.Status = savedBill.Status
|
||||
// } else if bill.Status > savedBill.Status {
|
||||
// savedBill.Status = bill.Status
|
||||
// }
|
||||
}
|
||||
savedOrderInfo.waybills[bill.WaybillVendorID] = bill
|
||||
}
|
||||
return isBillExist
|
||||
}
|
||||
@@ -848,7 +953,10 @@ func (s *DefScheduler) isBillCandidate(order *model.GoodsOrder, bill *model.Wayb
|
||||
func (s *DefScheduler) ProxyCancelWaybill(order *model.GoodsOrder, bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Debugf("ProxyCancelWaybill orderID:%s", order.VendorOrderID)
|
||||
if (order.DeliveryFlag & model.OrderDeliveryFlagMaskScheduleDisabled) == 0 {
|
||||
return s.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
if err = s.CancelWaybill(bill, cancelReasonID, cancelReason); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "取消三方运单失败", err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
globals.SugarLogger.Debugf("ProxyCancelWaybill orderID:%s stop schedule, bypass CancelWaybill", order.VendorOrderID)
|
||||
return nil
|
||||
@@ -868,18 +976,3 @@ func OnDefSchConfChanged(key, value string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否是购买平台自有物流
|
||||
// 对于京东,饿百来说,就是其自有的物流,对于微商城来说,是达达
|
||||
func (s *DefScheduler) IsOrderPlatformWaybill(bill *model.Waybill) bool {
|
||||
return bill.OrderVendorID == bill.WaybillVendorID || s.IsSpecialOrderPlatformWaybill(bill)
|
||||
}
|
||||
|
||||
// 是否是特殊物流
|
||||
func (s *DefScheduler) IsSpecialOrderPlatformWaybill(bill *model.Waybill) bool {
|
||||
return (bill.OrderVendorID == model.VendorIDWSC && bill.WaybillVendorID == model.VendorIDDada)
|
||||
}
|
||||
|
||||
func (s *DefScheduler) IsOrderHasWaybill(order *model.GoodsOrder) bool {
|
||||
return order.WaybillVendorID != model.VendorIDUnknown
|
||||
}
|
||||
|
||||
27
business/jxcallback/scheduler/defsch/defsch_afs.go
Normal file
27
business/jxcallback/scheduler/defsch/defsch_afs.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/msghub"
|
||||
)
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error) {
|
||||
if order.Status == model.AfsOrderStatusWait4Approve {
|
||||
if !isPending {
|
||||
msghub.OnNewWait4ApproveAfsOrder(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error) {
|
||||
if status.Status == model.AfsOrderStatusWait4ReceiveGoods {
|
||||
if !isPending {
|
||||
msghub.OnKeyAfsOrderStatusChanged(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -15,23 +15,25 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func (s *DefScheduler) loadSavedOrderByID(vendorOrderID string, vendorID int, isForceLoad bool) *WatchOrderInfo {
|
||||
return s.loadSavedOrderFromMap(&model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}, isForceLoad)
|
||||
}
|
||||
|
||||
func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
status := &model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}
|
||||
savedOrderInfo := s.loadSavedOrderFromMap(status, true)
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order := savedOrderInfo.order
|
||||
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
if err == nil {
|
||||
// todo
|
||||
if true { //order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled == 0 {
|
||||
if err = s.isPossibleSwitch2SelfDelivery(order); err == nil {
|
||||
err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
if err == nil {
|
||||
if savedOrderInfo.storeDeliveryType == scheduler.StoreDeliveryTypeByStore {
|
||||
if order.Status <= model.OrderStatusFinishedPickup {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), order.StoreID, order.VendorID)
|
||||
phone := userName
|
||||
if err = err2; err == nil {
|
||||
@@ -40,7 +42,7 @@ func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, ven
|
||||
err = s.SelfDeliverDelivering(order, phone)
|
||||
}
|
||||
} else {
|
||||
if order.Status <= model.OrderStatusFinishedPickup {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
err = s.Swtich2SelfDeliver(order, userName)
|
||||
} else if order.VendorID == order.WaybillVendorID { // 状态为配送中,且是购物平台运单,不能转自送了
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
@@ -51,7 +53,7 @@ func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, ven
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled | model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order); err == nil {
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
@@ -70,25 +72,47 @@ func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, ven
|
||||
func (s *DefScheduler) canOrderCreateWaybillNormally(order *model.GoodsOrder) (err error) {
|
||||
if !(order.LockStatus != model.OrderStatusLocked && order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) {
|
||||
err = fmt.Errorf("当前订单%s没有处于拣货完成且没有结束没有锁定的订单才能进行召唤配送操作", order.VendorOrderID)
|
||||
} else if s.IsOrderHasWaybill(order) {
|
||||
} else if model.IsOrderHaveWaybill(order) {
|
||||
err = fmt.Errorf("当前订单%s已经有了有效的承运人%s了", order.VendorOrderID, jxutils.GetVendorName(order.WaybillVendorID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, forceCreate bool) (bills []*model.Waybill, err error) {
|
||||
func (s *DefScheduler) isPossibleSwitch2SelfDelivery(order *model.GoodsOrder) (err error) {
|
||||
if scheduler.StoreDeliveryTypeByStore != s.GetStoreDeliveryType(order, nil) {
|
||||
if order.Status < model.OrderStatusFinishedPickup {
|
||||
err = fmt.Errorf("拣货完成后才能转自配送")
|
||||
} else if order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusDelivering {
|
||||
if time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute {
|
||||
err = fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier)
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin {
|
||||
if model.IsOrderHaveOwnWaybill(order) {
|
||||
err = fmt.Errorf("%s物流已在配送中,不能转自配送", jxutils.GetVendorName(order.VendorID))
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("订单%s已经结束,请刷新状态", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, courierVendorIDs []int, forceCreate bool, maxAddFee, maxDiffFee2Mtps int64) (bills []*model.Waybill, err error) {
|
||||
order := savedOrderInfo.order
|
||||
err = s.canOrderCreateWaybillNormally(order)
|
||||
if forceCreate || err == nil {
|
||||
err = nil
|
||||
if !forceCreate {
|
||||
err = s.canOrderCreateWaybillNormally(order)
|
||||
}
|
||||
if err == nil {
|
||||
feeHandler := delivery.DefCreateWaybillPolicy
|
||||
if forceCreate {
|
||||
feeHandler = delivery.NullCreateWaybillPolicy
|
||||
} else if maxAddFee != 0 {
|
||||
feeHandler = delivery.CreateWaybillPolicy(maxDiffFee2Mtps, maxAddFee)
|
||||
}
|
||||
if bills, err = s.CreateWaybillOnProviders(ctx, order, feeHandler); err == nil {
|
||||
if bills, err = s.CreateWaybillOnProviders(ctx, order, courierVendorIDs, feeHandler, forceCreate); err == nil {
|
||||
if forceCreate {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order)
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
@@ -105,7 +129,7 @@ func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Contex
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, forceCreate bool) (bills []*model.Waybill, err error) {
|
||||
func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, courierVendorIDs []int, forceCreate bool, maxAddFee, maxDiffFee2Mtps int64) (bills []*model.Waybill, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
bills, err = func() (bills []*model.Waybill, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
@@ -113,19 +137,15 @@ func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendor
|
||||
if vendorID == model.VendorIDELM {
|
||||
return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号")
|
||||
}
|
||||
status := &model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}
|
||||
savedOrderInfo := s.loadSavedOrderFromMap(status, true)
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order := savedOrderInfo.order
|
||||
if scheduler.StoreDeliveryTypeByStore != s.GetStoreDeliveryType(order, nil) &&
|
||||
order.Status == model.OrderStatusFinishedPickup &&
|
||||
time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute {
|
||||
return nil, fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier)
|
||||
if !forceCreate {
|
||||
err = s.isPossibleSwitch2SelfDelivery(order)
|
||||
}
|
||||
if err == nil {
|
||||
bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, courierVendorIDs, forceCreate, maxAddFee, maxDiffFee2Mtps)
|
||||
}
|
||||
bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, forceCreate)
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
@@ -141,13 +161,9 @@ func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderI
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s", vendorOrderID, ctx.GetUserName())
|
||||
status := &model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}
|
||||
savedOrderInfo := s.loadSavedOrderFromMap(status, true)
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
err = s.cancelOtherWaybills2(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
@@ -155,7 +171,7 @@ func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderI
|
||||
if err == nil && isStopSchedule {
|
||||
order := savedOrderInfo.order
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndFlag(order); err == nil {
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s successfully", vendorOrderID, ctx.GetUserName())
|
||||
}
|
||||
@@ -165,3 +181,80 @@ func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderI
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
deliveryFeeMap, err = func() (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Infof("GetWaybillsInfoEx orderID:%s userName:%s", vendorOrderID, userName)
|
||||
|
||||
db := dao.GetDB()
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storeCourierList, err := dao.GetStoreCourierList(db, jxutils.GetSaleStoreIDFromOrder(order), model.StoreStatusAll)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillMap := make(map[int]*model.Waybill)
|
||||
for _, bill := range waybillList {
|
||||
waybillMap[bill.WaybillVendorID] = bill
|
||||
}
|
||||
deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo)
|
||||
|
||||
var timeoutSecond int
|
||||
if savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, false); savedOrderInfo != nil {
|
||||
if savedOrderInfo.timerStatusType == scheduler.TimerStatusTypeWaybill && savedOrderInfo.timerStatus == model.WaybillStatusNew {
|
||||
timeoutSecond = int(savedOrderInfo.timerTime.Sub(time.Now()) / time.Second)
|
||||
}
|
||||
}
|
||||
for _, storeCourier := range storeCourierList {
|
||||
var feeInfo *partner.WaybillFeeInfo
|
||||
if waybillMap[storeCourier.VendorID] != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
Waybill: waybillMap[storeCourier.VendorID],
|
||||
}
|
||||
} else {
|
||||
if storeCourier.Status != model.StoreStatusOpened {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotOpen,
|
||||
ErrStr: fmt.Sprintf("%d配送门店没有启用", storeCourier.VendorID),
|
||||
}
|
||||
} else {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil {
|
||||
if handler.Use4CreateWaybill {
|
||||
if feeInfo, err = handler.Handler.GetWaybillFee(order); err != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierOthers,
|
||||
ErrStr: err.Error(),
|
||||
}
|
||||
} else {
|
||||
feeInfo.TimeoutSecond = timeoutSecond
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierForbidden,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不能用于创建运单", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotSupported,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不被支持", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
deliveryFeeMap[storeCourier.VendorID] = feeInfo
|
||||
}
|
||||
err = nil
|
||||
return deliveryFeeMap, err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return deliveryFeeMap, err
|
||||
}
|
||||
|
||||
@@ -40,4 +40,8 @@ type IScheduler interface {
|
||||
|
||||
// 以下是运单
|
||||
OnWaybillStatusChanged(bill *model.Waybill, isPending bool) (err error)
|
||||
|
||||
// 以下是售后单
|
||||
OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error)
|
||||
OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
}
|
||||
|
||||
355
business/jxstore/act/act.go
Normal file
355
business/jxstore/act/act.go
Normal file
@@ -0,0 +1,355 @@
|
||||
package act
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
const (
|
||||
ActionTypeNA = 0
|
||||
)
|
||||
|
||||
type ActOrderRuleParam struct {
|
||||
SalePrice int64 `orm:"" json:"salePrice"` // 满的价格
|
||||
DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格
|
||||
}
|
||||
|
||||
type ActStoreSkuParam struct {
|
||||
Action int // -1删除,1修改,2新增
|
||||
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"`
|
||||
SkuID int `orm:"column(sku_id)" json:"skuID"`
|
||||
|
||||
PricePercentage int `orm:"" json:"pricePercentage"` // 单品级活动用,SKU级的价格比例,非0覆盖Act中的PricePercentage
|
||||
ActPrice int64 `orm:"" json:"actPrice"` // 单品级活动用,SKU级指定的价格,非0覆盖CustomPricePercentage与Act中的PricePercentage
|
||||
|
||||
Stock int `orm:"" json:"stock"` // 订单级活动用
|
||||
}
|
||||
|
||||
type ActDetail struct {
|
||||
model.Act2
|
||||
}
|
||||
|
||||
func ActStoreSkuParam2Map(actStoreSku []*ActStoreSkuParam) (actStoreSkuMap map[int][]*ActStoreSkuParam) {
|
||||
if len(actStoreSku) > 0 {
|
||||
for _, v := range actStoreSku {
|
||||
actStoreSkuMap[v.StoreID] = append(actStoreSkuMap[v.StoreID], v)
|
||||
}
|
||||
}
|
||||
return actStoreSkuMap
|
||||
}
|
||||
|
||||
func genStoreSkuMapKey(storeID, skuID int) int64 {
|
||||
return int64(storeID) + int64(skuID)*1000000
|
||||
}
|
||||
|
||||
func ActStoreSkuParam2Model(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actStoreSku []*ActStoreSkuParam) (actMapList []*model.ActMap, actStoreMapList []*model.ActStoreMap, actStoreSkuList []*model.ActStoreSku, actStoreSkuMapList []*model.ActStoreSkuMap, err error) {
|
||||
if len(actStoreSku) > 0 {
|
||||
storeIDMap := make(map[int]int)
|
||||
skuIDMap := make(map[int]int)
|
||||
storeSkuParamMap := make(map[int][]*ActStoreSkuParam)
|
||||
for _, v := range actStoreSku {
|
||||
storeIDMap[v.StoreID] = 1
|
||||
skuIDMap[v.SkuID] = 1
|
||||
storeSkuParamMap[v.StoreID] = append(storeSkuParamMap[v.StoreID], v)
|
||||
}
|
||||
db := dao.GetDB()
|
||||
|
||||
storeSkuList, err2 := dao.GetStoresSkusInfo(db, jxutils.IntMap2List(storeIDMap), jxutils.IntMap2List(skuIDMap))
|
||||
if err = err2; err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
storeSkuMap := make(map[int64]*model.StoreSkuBind)
|
||||
for _, v := range storeSkuList {
|
||||
storeSkuMap[genStoreSkuMapKey(v.StoreID, v.SkuID)] = v
|
||||
}
|
||||
|
||||
wholeValidVendorMap := make(map[int]int)
|
||||
for storeID, oneStoreSkuParam := range storeSkuParamMap {
|
||||
validVendorMap := make(map[int]int)
|
||||
validSkuMap := make(map[int]int)
|
||||
for _, vendorID := range vendorIDs {
|
||||
storeDetail, err2 := dao.GetStoreDetail(db, storeID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
for _, v := range oneStoreSkuParam {
|
||||
if storeSkuInfo := storeSkuMap[genStoreSkuMapKey(v.StoreID, v.SkuID)]; storeSkuInfo != nil {
|
||||
validVendorMap[vendorID] = 1
|
||||
validSkuMap[v.SkuID] = 1
|
||||
actSkuMap := &model.ActStoreSkuMap{
|
||||
ActID: act.ID,
|
||||
StoreID: storeID,
|
||||
SkuID: v.SkuID,
|
||||
VendorID: vendorID,
|
||||
|
||||
SyncStatus: model.SyncFlagNewMask,
|
||||
}
|
||||
if v.ActPrice != 0 {
|
||||
actSkuMap.ActualActPrice = v.ActPrice
|
||||
} else {
|
||||
percentage := act.PricePercentage
|
||||
if v.PricePercentage != 0 {
|
||||
percentage = v.PricePercentage
|
||||
}
|
||||
percentage = percentage * int(storeDetail.PricePercentage) / 100
|
||||
actSkuMap.ActualActPrice = int64(jxutils.CaculateSkuVendorPrice(storeSkuInfo.Price, percentage, 0))
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(actSkuMap, ctx.GetUserName())
|
||||
actStoreSkuMapList = append(actStoreSkuMapList, actSkuMap)
|
||||
}
|
||||
}
|
||||
} else if !dao.IsNoRowsError(err) {
|
||||
return nil, nil, nil, nil, err
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range oneStoreSkuParam {
|
||||
if validSkuMap[v.SkuID] == 1 {
|
||||
if storeSkuInfo := storeSkuMap[genStoreSkuMapKey(v.StoreID, v.SkuID)]; storeSkuInfo != nil {
|
||||
storeSku := &model.ActStoreSku{
|
||||
ActID: act.ID,
|
||||
StoreID: v.StoreID,
|
||||
SkuID: v.SkuID,
|
||||
OriginalPrice: int64(storeSkuInfo.Price),
|
||||
PricePercentage: v.PricePercentage,
|
||||
ActPrice: v.ActPrice,
|
||||
Stock: v.Stock,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(storeSku, ctx.GetUserName())
|
||||
actStoreSkuList = append(actStoreSkuList, storeSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
for vendorID := range validVendorMap {
|
||||
wholeValidVendorMap[vendorID] = 1
|
||||
actStoreMap := &model.ActStoreMap{
|
||||
ActID: act.ID,
|
||||
StoreID: storeID,
|
||||
VendorID: vendorID,
|
||||
|
||||
SyncStatus: model.SyncFlagNewMask,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(actStoreMap, ctx.GetUserName())
|
||||
actStoreMapList = append(actStoreMapList, actStoreMap)
|
||||
}
|
||||
}
|
||||
for vendorID := range wholeValidVendorMap {
|
||||
actMap := &model.ActMap{
|
||||
ActID: act.ID,
|
||||
VendorID: vendorID,
|
||||
|
||||
SyncStatus: model.SyncFlagNewMask,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(actMap, ctx.GetUserName())
|
||||
actMapList = append(actMapList, actMap)
|
||||
}
|
||||
}
|
||||
return actMapList, actStoreMapList, actStoreSkuList, actStoreSkuMapList, err
|
||||
}
|
||||
|
||||
func CreateAct(ctx *jxcontext.Context, act *model.Act, vendorIDs []int, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam) (actID int, err error) {
|
||||
vendorIDMap := make(map[int]bool)
|
||||
for _, v := range vendorIDs {
|
||||
vendorIDMap[v] = true
|
||||
}
|
||||
db := dao.GetDB()
|
||||
dao.WrapAddIDCULDEntity(act, ctx.GetUserName())
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
err = dao.CreateEntity(db, act)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
actMapList, actStoreMapList, actStoreSkuList, actStoreSkuMapList, err := ActStoreSkuParam2Model(ctx, act, vendorIDs, actStoreSku)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
isEmptyAct := true
|
||||
for _, list := range []interface{}{
|
||||
actMapList, actStoreMapList, actStoreSkuList, actStoreSkuMapList,
|
||||
} {
|
||||
if len(utils.Interface2Slice(list)) > 0 {
|
||||
err = dao.CreateMultiEntities(db, list)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return 0, err
|
||||
}
|
||||
isEmptyAct = false
|
||||
}
|
||||
}
|
||||
if isEmptyAct {
|
||||
dao.Rollback(db)
|
||||
return 0, fmt.Errorf("没有门店及SKU满足需求,空操作")
|
||||
}
|
||||
dao.Commit(db)
|
||||
actID = act.ID
|
||||
err = SyncAct(ctx, actID, nil, nil, nil)
|
||||
return actID, err
|
||||
}
|
||||
|
||||
func QueryActs(ctx *jxcontext.Context, actID int, keyword string, statusList []int, actTypeList []int, storeID, skuID int, beginAt, endAt time.Time) (actList []*model.Act, err error) {
|
||||
return actList, err
|
||||
}
|
||||
|
||||
func GetActDetail(ctx *jxcontext.Context, actID int) (actDetail *ActDetail, err error) {
|
||||
return actDetail, err
|
||||
}
|
||||
|
||||
// func GetAcVendorInfo(ctx *jxcontext.Context, actID int) (err error) {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// func GetAcStoresVendorInfo(ctx *jxcontext.Context, actID int, storeIDs []int) (err error) {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// func GetAcStoresSkusVendorInfo(ctx *jxcontext.Context, actID int, storeIDs, skuIDs []int) (err error) {
|
||||
// return err
|
||||
// }
|
||||
|
||||
func parseActStoreSkuParam(actStoreSku []*ActStoreSkuParam) {
|
||||
|
||||
}
|
||||
|
||||
func UpdateAct(ctx *jxcontext.Context, act *model.Act, actRules []*ActOrderRuleParam, actStoreSku []*ActStoreSkuParam) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func CancelAct(ctx *jxcontext.Context, actID int) (err error) {
|
||||
db := dao.GetDB()
|
||||
act := &model.Act{}
|
||||
act.ID = actID
|
||||
if err = dao.GetEntity(db, act); err != nil {
|
||||
return err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
dao.UpdateEntityLogically(db, act, map[string]interface{}{
|
||||
model.FieldStatus: model.ActStatusCanceled,
|
||||
}, ctx.GetUserName(), nil)
|
||||
_, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, &model.ActMap{}, nil, ctx.GetUserName(), map[string]interface{}{
|
||||
model.FieldActID: actID,
|
||||
}, model.FieldSyncStatus, model.SyncFlagModifiedMask)
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
globals.SugarLogger.Debugf("CancelAct track:%s", ctx.GetTrackInfo())
|
||||
err = SyncAct(ctx, actID, nil, nil, nil)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SyncAct(ctx *jxcontext.Context, actID int, vendorIDs, storeIDs, skuIDs []int) (err error) {
|
||||
var actOrderRules []*model.ActOrderRule
|
||||
db := dao.GetDB()
|
||||
actMap, err := dao.GetActVendorInfo(db, actID, vendorIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actStoreMap, err := dao.GetActStoreVendorInfo(db, actID, vendorIDs, storeIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actStoreSkuMap, err := dao.GetActStoreSkuVendorInfo(db, actID, vendorIDs, storeIDs, skuIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var realVendorIDs []int
|
||||
for vendorID := range actMap {
|
||||
realVendorIDs = append(realVendorIDs, vendorID)
|
||||
}
|
||||
|
||||
task := tasksch.NewParallelTask("SyncAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorID := batchItemList[0].(int)
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
|
||||
if handler == nil {
|
||||
err = fmt.Errorf("不被支持的vendorID:%d", vendorID)
|
||||
} else {
|
||||
act := actMap[vendorID]
|
||||
actStore := actStoreMap[vendorID]
|
||||
actStoreSku := actStoreSkuMap[vendorID]
|
||||
// globals.SugarLogger.Debugf("%s", utils.Format4Output(act, false))
|
||||
// globals.SugarLogger.Debugf("%s", utils.Format4Output(actStore, false))
|
||||
// globals.SugarLogger.Debugf("%s", utils.Format4Output(actStoreSku, false))
|
||||
if act != nil && actStore != nil && actStoreSku != nil {
|
||||
if model.IsSyncStatusNeedCreate(act.SyncStatus) {
|
||||
err = handler.CreateAct(ctx, task, act, actOrderRules, actStore, actStoreSku)
|
||||
} else if model.IsSyncStatusNeedUpdate(act.SyncStatus) {
|
||||
if act.Status == model.ActStatusCanceled {
|
||||
err = handler.CancelAct(ctx, task, act, actStore, actStoreSku)
|
||||
} else {
|
||||
// actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update := splitActStore(actStore)
|
||||
// err = handler.UpdateAct(ctx, task, act, actOrderRules, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update, actStoreSku)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
actMap := &model.ActMap{}
|
||||
actMap.ID = act.MapID
|
||||
dao.UpdateEntityLogically(db, actMap, map[string]interface{}{
|
||||
model.FieldSyncStatus: 0,
|
||||
model.FieldVendorActID: act.VendorActID,
|
||||
}, ctx.GetUserName(), nil)
|
||||
for _, v := range actStore {
|
||||
storeMap := model.ActStoreMap{}
|
||||
storeMap.ID = v.MapID
|
||||
dao.UpdateEntityLogically(db, storeMap, map[string]interface{}{
|
||||
model.FieldSyncStatus: 0,
|
||||
model.FieldVendorActID: v.VendorActID,
|
||||
}, ctx.GetUserName(), nil)
|
||||
}
|
||||
for _, v := range actStoreSku {
|
||||
storeSkuMap := model.ActStoreSkuMap{}
|
||||
storeSkuMap.ID = v.MapID
|
||||
dao.UpdateEntityLogically(db, storeSkuMap, map[string]interface{}{
|
||||
model.FieldSyncStatus: 0,
|
||||
model.FieldVendorActID: v.VendorActID,
|
||||
}, ctx.GetUserName(), nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, realVendorIDs)
|
||||
tasksch.ManageTask(task).Run()
|
||||
_, err = task.GetResult(0)
|
||||
return err
|
||||
}
|
||||
|
||||
func splitActStore(actStore []*model.ActStore2) (actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2) {
|
||||
for _, v := range actStore {
|
||||
if model.IsSyncStatusNeedDelete(v.SyncStatus) {
|
||||
if !dao.IsVendorThingIDEmpty(v.VendorActID) {
|
||||
actStoreMap2Remove = append(actStoreMap2Remove, v)
|
||||
}
|
||||
} else if model.IsSyncStatusNeedCreate(v.SyncStatus) {
|
||||
actStoreMap2Add = append(actStoreMap2Add, v)
|
||||
} else if model.IsSyncStatusNeedUpdate(v.SyncStatus) {
|
||||
actStoreMap2Update = append(actStoreMap2Update, v)
|
||||
}
|
||||
}
|
||||
return actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update
|
||||
}
|
||||
68
business/jxstore/act/act_test.go
Normal file
68
business/jxstore/act/act_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package act
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestInitDb(t *testing.T) {
|
||||
dao.ExecuteSQL(dao.GetDB(), `
|
||||
DROP TABLE IF EXISTS act,act_map, act_order_rule, act_store_map, act_store_sku, act_store_sku_map;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestCreateAct(t *testing.T) {
|
||||
actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
Name: "测试活动2",
|
||||
PricePercentage: 80,
|
||||
}, []int{0, 1, 3}, nil, []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
StoreID: 100119,
|
||||
SkuID: 30828,
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
StoreID: 100119,
|
||||
SkuID: 30827,
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
StoreID: 100118,
|
||||
SkuID: 30592,
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
StoreID: 100118,
|
||||
SkuID: 30565,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCancelAct(t *testing.T) {
|
||||
err := CancelAct(jxcontext.AdminCtx, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncAct(t *testing.T) {
|
||||
err := SyncAct(jxcontext.AdminCtx, 1, nil, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,12 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
serviceInfo map[string]interface{}
|
||||
serviceInfo map[string]interface{}
|
||||
allowUpdatePlaceFieldsMap = map[string]bool{
|
||||
"name": true,
|
||||
"enabled": true,
|
||||
"mtpsPrice": true,
|
||||
}
|
||||
)
|
||||
|
||||
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
@@ -55,6 +60,8 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
"shopChineseNames": model.ShopChineseNames,
|
||||
"printerVendorInfo": model.PrinterVendorInfo,
|
||||
"purchaseVendorInfo": model.PurchaseVendorInfo,
|
||||
"afsReasonTypeName": model.AfsReasonTypeName,
|
||||
"afsAppealTypeName": model.AfsAppealTypeName,
|
||||
},
|
||||
}
|
||||
Init()
|
||||
@@ -124,12 +131,18 @@ func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userN
|
||||
if len(places) == 0 {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
updateFields := []string{}
|
||||
for k := range places[0] {
|
||||
if allowUpdatePlaceFieldsMap[k] {
|
||||
updateFields = append(updateFields, k)
|
||||
}
|
||||
}
|
||||
for _, place := range places {
|
||||
if place["code"] == nil {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
placeid := &model.Place{}
|
||||
valid := dao.NormalMakeMapByFieldList(place, []string{"jdCode", "enabled", "mtpsPrice"}, userName)
|
||||
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
|
||||
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
|
||||
return num, err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,12 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type MessageStatusExt struct {
|
||||
model.MessageStatus
|
||||
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
func SendStoreMessage(ctx *jxcontext.Context, title, content string, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
@@ -128,8 +134,11 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
|
||||
|
||||
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
sql := `
|
||||
SELECT SQL_CALC_FOUND_ROWS t1.*
|
||||
SELECT SQL_CALC_FOUND_ROWS
|
||||
t1.*,
|
||||
t2.title
|
||||
FROM message_status t1
|
||||
JOIN message t2 ON t2.id = t1.message_id
|
||||
WHERE 1 = 1
|
||||
`
|
||||
sqlParams := []interface{}{}
|
||||
@@ -167,7 +176,7 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fro
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer dao.Commit(db)
|
||||
var msgStatusList []*model.MessageStatus
|
||||
var msgStatusList []*MessageStatusExt
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||||
if err = dao.GetRows(db, &msgStatusList, sql, sqlParams...); err == nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type SkuNamesInfo struct {
|
||||
@@ -25,6 +27,19 @@ var (
|
||||
ErrInputCatsDoesntMatch = errors.New("输入的类别列表不合法,需要输入一个父ID下的所有子类别")
|
||||
)
|
||||
|
||||
var (
|
||||
ebaiUploadRTFShopID string // 饿百找一个店用于调用SkuUploadRTF
|
||||
)
|
||||
|
||||
func getAndSetEbaiUploadRTFShopID() (shopID string) {
|
||||
if ebaiUploadRTFShopID == "" {
|
||||
if storeDetail, err := dao.GetStoreDetail(dao.GetDB(), 0, model.VendorIDEBAI); err == nil {
|
||||
ebaiUploadRTFShopID = utils.Int2Str(storeDetail.Store.ID)
|
||||
}
|
||||
}
|
||||
return ebaiUploadRTFShopID
|
||||
}
|
||||
|
||||
// parentID 为-1表示所有
|
||||
func GetVendorCategories(ctx *jxcontext.Context, vendorID int, parentID string) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
cond := map[string]interface{}{
|
||||
@@ -72,7 +87,7 @@ func AddCategory(ctx *jxcontext.Context, cat *model.SkuCategory, userName string
|
||||
|
||||
dao.WrapAddIDCULDEntity(cat, userName)
|
||||
cat.JdSyncStatus = model.SyncFlagNewMask
|
||||
cat.JdID = 0 //jxutils.GenFakeID()
|
||||
cat.JdID = 0
|
||||
cat.Name = strings.Trim(cat.Name, " ")
|
||||
if cat.Seq <= 0 {
|
||||
var maxSeq struct {
|
||||
@@ -93,19 +108,83 @@ func AddCategory(ctx *jxcontext.Context, cat *model.SkuCategory, userName string
|
||||
func UpdateCategory(ctx *jxcontext.Context, categoryID int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||||
cat := &model.SkuCategory{}
|
||||
cat.ID = categoryID
|
||||
valid := dao.NormalMakeMapByStructObject(payload, cat, userName)
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, cat); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
valid := dao.StrictMakeMapByStructObject(payload, cat, userName)
|
||||
if len(valid) > 0 {
|
||||
syncStatus := 0
|
||||
if valid["name"] != nil {
|
||||
valid["name"] = strings.Trim(valid["name"].(string), " ")
|
||||
syncStatus = model.SyncFlagModifiedMask
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, cat, valid, userName, nil, model.FieldJdSyncStatus, model.SyncFlagModifiedMask); err == nil {
|
||||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, cat, valid, userName, nil, model.FieldJdSyncStatus, syncStatus); err == nil {
|
||||
SetStoreCategorySyncStatus2(db, nil, []int{categoryID}, model.SyncFlagModifiedMask)
|
||||
if valid["jdCategoryID"] != nil || valid["ebaiCategoryID"] != nil || valid["mtwmCategoryID"] != nil ||
|
||||
valid["jdPricePercentage"] != nil || valid["ebaiPricePercentage"] != nil || valid["mtwmPricePercentage"] != nil {
|
||||
if skuList, err2 := dao.GetSkuByCats(db, []int{categoryID}); err2 == nil && len(skuList) > 0 {
|
||||
var skuIDs []int
|
||||
for _, sku := range skuList {
|
||||
skuIDs = append(skuIDs, sku.ID)
|
||||
}
|
||||
if valid["jdCategoryID"] != nil {
|
||||
dao.SetSkuSyncStatus(db, model.VendorIDJD, skuIDs, model.SyncFlagModifiedMask)
|
||||
}
|
||||
|
||||
// todo 如下逻辑,在不同平台同时改pricePercentage与平台分类映射时,会不必要的打上多余的标记
|
||||
var vendorIDs []int
|
||||
syncStatus := model.SyncFlagModifiedMask
|
||||
if valid["jdPricePercentage"] != nil {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDJD)
|
||||
syncStatus |= model.SyncFlagPriceMask
|
||||
}
|
||||
|
||||
if valid["ebaiPricePercentage"] != nil {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
|
||||
syncStatus |= model.SyncFlagPriceMask
|
||||
} else if valid["ebaiCategoryID"] != nil {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
|
||||
}
|
||||
|
||||
if valid["mtwmPricePercentage"] != nil {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
|
||||
syncStatus |= model.SyncFlagPriceMask
|
||||
} else if valid["mtwmCategoryID"] != nil {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
|
||||
}
|
||||
if len(vendorIDs) > 0 {
|
||||
SetStoreSkuSyncStatus2(db, nil, vendorIDs, skuIDs, syncStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = CurVendorSync.SyncCategory(ctx, db, categoryID, false, userName)
|
||||
}
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func SetStoreCategorySyncStatus2(db *dao.DaoDB, storeIDs []int, catIDs []int, syncStatus int) (num int64, err error) {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
for _, vendorID := range CurVendorSync.SingleStoreVendorIDs {
|
||||
num2, err2 := dao.SetStoreCategorySyncStatus(db, vendorID, storeIDs, catIDs, syncStatus)
|
||||
if err = err2; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
num += num2
|
||||
}
|
||||
dao.Commit(db)
|
||||
return num, nil
|
||||
}
|
||||
|
||||
func ReorderCategories(ctx *jxcontext.Context, parentID int, categoryIDs []int, userName string) (err error) {
|
||||
var cats []*model.SkuCategory
|
||||
parentCat := &model.SkuCategory{}
|
||||
@@ -211,8 +290,8 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma
|
||||
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike)
|
||||
|
||||
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
|
||||
sql += " OR t2.jd_id = ? OR t1.id = ? OR t1.category_id = ?"
|
||||
sqlParams = append(sqlParams, keywordInt64, keywordInt64, keywordInt64)
|
||||
sql += " OR t1.id = ? OR t2.id = ? OR t2.jd_id = ? OR t1.category_id = ?"
|
||||
sqlParams = append(sqlParams, keywordInt64, keywordInt64, keywordInt64, keywordInt64)
|
||||
}
|
||||
sql += ")"
|
||||
}
|
||||
@@ -340,6 +419,7 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma
|
||||
t1.name,
|
||||
t1.brand_id,
|
||||
t1.category_id,
|
||||
t1.jd_category_id,
|
||||
t1.is_global,
|
||||
t1.unit,
|
||||
t1.price,
|
||||
@@ -348,6 +428,7 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma
|
||||
t1.status,
|
||||
t1.is_spu,
|
||||
t1.img_hash_code,
|
||||
t1.desc_img,
|
||||
t1.upc`
|
||||
if isBySku {
|
||||
sql += `,
|
||||
@@ -365,6 +446,7 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma
|
||||
t1.name,
|
||||
t1.brand_id,
|
||||
t1.category_id,
|
||||
t1.jd_category_id,
|
||||
t1.is_global,
|
||||
t1.unit,
|
||||
t1.price,
|
||||
@@ -373,6 +455,7 @@ func GetSkuNames(ctx *jxcontext.Context, keyword string, isBySku bool, params ma
|
||||
t1.status,
|
||||
t1.is_spu,
|
||||
t1.img_hash_code,
|
||||
t1.desc_img,
|
||||
t1.upc,
|
||||
t1.jd_id,
|
||||
t1.jd_sync_status,
|
||||
@@ -463,30 +546,39 @@ func AddSkuName(ctx *jxcontext.Context, skuNameExt *model.SkuNameExt, userName s
|
||||
skuNameExt.SpecQuality = skuNameExt.Skus[0].SpecQuality
|
||||
skuNameExt.SpecUnit = skuNameExt.Skus[0].SpecUnit
|
||||
}
|
||||
imgContent, imgMD5, err := jxutils.DownloadFileByURL(skuNameExt.Img)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
if skuNameExt.ImgHashCode == "" {
|
||||
skuNameExt.ImgHashCode = imgMD5
|
||||
} else if skuNameExt.ImgHashCode != imgMD5 {
|
||||
dao.Rollback(db)
|
||||
return nil, errors.New("图片HASH值不同")
|
||||
}
|
||||
imgHintMap, err := UploadImg2Platforms(ctx, nil, skuNameExt.Img, imgContent, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
skuNameExt.ImgWeimob = imgHintMap[model.VendorIDWSC]
|
||||
skuNameExt.ImgEbai = imgHintMap[model.VendorIDEBAI]
|
||||
|
||||
if globals.EnableStoreWrite {
|
||||
imgContent, imgMD5, err := jxutils.DownloadFileByURL(skuNameExt.Img)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
if skuNameExt.ImgHashCode == "" {
|
||||
skuNameExt.ImgHashCode = imgMD5
|
||||
} else if skuNameExt.ImgHashCode != imgMD5 {
|
||||
dao.Rollback(db)
|
||||
return nil, errors.New("图片HASH值不同")
|
||||
}
|
||||
imgHintMap, err := UploadImg2Platforms(ctx, nil, skuNameExt.Img, imgContent, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
skuNameExt.ImgWeimob = imgHintMap[model.VendorIDWSC]
|
||||
skuNameExt.ImgEbai = imgHintMap[model.VendorIDEBAI]
|
||||
|
||||
if skuNameExt.DescImg != "" && getAndSetEbaiUploadRTFShopID() != "" {
|
||||
skuNameExt.DescImgEbai, err = api.EbaiAPI.SkuUploadRTF(getAndSetEbaiUploadRTFShopID(), ebaiapi.BuildRFTFromImgs(skuNameExt.DescImg))
|
||||
}
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = dao.CreateEntity(db, &skuNameExt.SkuName); err != nil {
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
// beginJDID := jxutils.GenFakeID()
|
||||
for _, sku := range skuNameExt.Skus {
|
||||
dao.WrapAddIDCULDEntity(sku, userName)
|
||||
sku.NameID = skuNameExt.ID
|
||||
@@ -496,7 +588,6 @@ func AddSkuName(ctx *jxcontext.Context, skuNameExt *model.SkuNameExt, userName s
|
||||
dao.Rollback(db)
|
||||
return nil, err
|
||||
}
|
||||
// beginJDID++
|
||||
}
|
||||
for _, placeCode := range skuNameExt.Places {
|
||||
placeBind := &model.SkuNamePlaceBind{}
|
||||
@@ -528,9 +619,12 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf
|
||||
if err = dao.GetEntity(db, skuName); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if _, ok := payload["isSpu"]; ok {
|
||||
delete(payload, "isSpu")
|
||||
}
|
||||
delete(payload, "isSpu")
|
||||
delete(payload, "ImgHashCode")
|
||||
delete(payload, "ImgWeimob")
|
||||
delete(payload, "ImgEbai")
|
||||
delete(payload, "descImgEbai")
|
||||
|
||||
valid := dao.StrictMakeMapByStructObject(payload, skuName, userName)
|
||||
valid = utils.RemoveGeneralMapKeys(valid, model.FieldSpecQuality, model.FieldSpecUnit)
|
||||
_, hasPlaces := payload["places"]
|
||||
@@ -550,19 +644,35 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
if valid["img"] != nil {
|
||||
imgContent, imgMD5, err2 := jxutils.DownloadFileByURL(valid["img"].(string))
|
||||
if err = err2; err != nil {
|
||||
return 0, err
|
||||
if globals.EnableStoreWrite {
|
||||
if valid["img"] != nil {
|
||||
imgContent, imgMD5, err2 := jxutils.DownloadFileByURL(valid["img"].(string))
|
||||
if err = err2; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
valid["ImgHashCode"] = imgMD5
|
||||
imgHintMap, err := UploadImg2Platforms(ctx, nil, valid["img"].(string), imgContent, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return 0, err
|
||||
}
|
||||
valid["ImgWeimob"] = imgHintMap[model.VendorIDWSC]
|
||||
valid["ImgEbai"] = imgHintMap[model.VendorIDEBAI]
|
||||
}
|
||||
valid["ImgHashCode"] = imgMD5
|
||||
imgHintMap, err := UploadImg2Platforms(ctx, nil, valid["img"].(string), imgContent, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return 0, err
|
||||
if valid["descImg"] != nil {
|
||||
descImg := valid["descImg"].(string)
|
||||
if descImg != "" {
|
||||
if getAndSetEbaiUploadRTFShopID() != "" {
|
||||
valid["descImgEbai"], err = api.EbaiAPI.SkuUploadRTF(getAndSetEbaiUploadRTFShopID(), ebaiapi.BuildRFTFromImgs(descImg))
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
valid["descImgEbai"] = ""
|
||||
}
|
||||
}
|
||||
valid["ImgWeimob"] = imgHintMap[model.VendorIDWSC]
|
||||
valid["ImgEbai"] = imgHintMap[model.VendorIDEBAI]
|
||||
}
|
||||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, skuName, valid, userName, nil, model.FieldJdSyncStatus, model.SyncFlagModifiedMask); err == nil && num == 1 {
|
||||
if utils.Interface2Int64WithDefault(payload["isGlobal"], 0) == 0 && payload["places"] != nil {
|
||||
@@ -588,8 +698,14 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf
|
||||
model.FieldNameID: nameID,
|
||||
}, model.FieldJdSyncStatus, model.SyncFlagModifiedMask)
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
|
||||
skuIDs, err2 := dao.GetSkuIDByNames(db, []int{nameID})
|
||||
if err = err2; err == nil && len(skuIDs) > 0 {
|
||||
_, err = SetStoreSkuSyncStatus2(db, nil, CurVendorSync.SingleStoreVendorIDs, skuIDs, model.SyncFlagModifiedMask)
|
||||
}
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
_, err = CurVendorSync.SyncSku(ctx, db, nameID, -1, false, false, userName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -597,6 +713,27 @@ func UpdateSkuName(ctx *jxcontext.Context, nameID int, payload map[string]interf
|
||||
return num, err
|
||||
}
|
||||
|
||||
func SetStoreSkuSyncStatus2(db *dao.DaoDB, storeIDs []int, vendorIDs, skuIDs []int, syncStatus int) (num int64, err error) {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
for _, vendorID := range vendorIDs {
|
||||
num2, err2 := dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, skuIDs, syncStatus)
|
||||
if err = err2; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
num += num2
|
||||
}
|
||||
dao.Commit(db)
|
||||
return num, nil
|
||||
}
|
||||
|
||||
func DeleteSkuName(ctx *jxcontext.Context, nameID int, userName string) (num int64, err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
@@ -647,7 +784,7 @@ func AddSku(ctx *jxcontext.Context, nameID int, sku *model.Sku, userName string)
|
||||
dao.WrapAddIDCULDEntity(sku, userName)
|
||||
sku.JdSyncStatus = model.SyncFlagNewMask
|
||||
sku.NameID = nameID
|
||||
sku.JdID = 0 //jxutils.GenFakeID()
|
||||
sku.JdID = 0
|
||||
if err = dao.CreateEntity(db, sku); err == nil {
|
||||
result, err2 := GetSkuNames(ctx, "", false, utils.Params2Map("skuID", sku.ID), 0, 0)
|
||||
if err = err2; err == nil {
|
||||
@@ -691,8 +828,10 @@ func UpdateSku(ctx *jxcontext.Context, skuID int, payload map[string]interface{}
|
||||
`, utils.DefaultTimeValue, skuID, model.SpecialUnit); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dao.Commit(db)
|
||||
_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
|
||||
if _, err = SetStoreSkuSyncStatus2(db, nil, CurVendorSync.SingleStoreVendorIDs, []int{skuID}, model.SyncFlagModifiedMask); err == nil {
|
||||
dao.Commit(db)
|
||||
_, err = CurVendorSync.SyncSku(ctx, db, -1, sku.ID, false, false, userName)
|
||||
}
|
||||
} else {
|
||||
err = ErrEntityNotExist
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@ import (
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/feieapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
|
||||
"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"
|
||||
@@ -19,6 +21,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
@@ -59,6 +62,37 @@ var (
|
||||
ErrCanNotFindVendor = errors.New("vendorID参数不合法")
|
||||
)
|
||||
|
||||
var (
|
||||
dadaDistrictMap = map[string]string{
|
||||
"苏州工业园区": "工业园区",
|
||||
"郫都区": "郫县",
|
||||
"管城回族区": "管城区",
|
||||
"昆山市": "1",
|
||||
"常熟市": "1",
|
||||
"太仓市": "1",
|
||||
"虞山街道": "虞山镇",
|
||||
"常福街道": "虞山镇",
|
||||
}
|
||||
|
||||
storeKeyPropertyMap = map[string]int{
|
||||
"name": 1,
|
||||
"cityCode": 1,
|
||||
"districtCode": 1,
|
||||
"address": 1,
|
||||
"tel1": 1,
|
||||
"tel2": 1,
|
||||
"openTime1": 1,
|
||||
"closeTime1": 1,
|
||||
"openTime2": 1,
|
||||
"closeTime2": 1,
|
||||
"lng": 1,
|
||||
"lat": 1,
|
||||
"deliveryRangeType": 1,
|
||||
"deliveryRange": 1,
|
||||
"status": 1,
|
||||
}
|
||||
)
|
||||
|
||||
// todo 门店绑定信息可以考虑以数组形式返回,而不是现在这样
|
||||
func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interface{}, offset, pageSize int) (retVal *StoresInfo, err error) {
|
||||
sql := `
|
||||
@@ -92,17 +126,46 @@ func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interfa
|
||||
t1.printer_sn,
|
||||
t1.printer_key,
|
||||
t1.printer_vendor_id,
|
||||
|
||||
t1.licence_type,
|
||||
t1.licence_corp_name,
|
||||
t1.licence_owner_name,
|
||||
t1.licence_address,
|
||||
t1.licence_valid,
|
||||
t1.licence_expire,
|
||||
t1.id_name,
|
||||
t1.id_code,
|
||||
t1.id_valid,
|
||||
t1.id_expire,
|
||||
t1.licence2_image,
|
||||
t1.licence2_code,
|
||||
t1.licence2_valid,
|
||||
t1.licence2_expire,
|
||||
t1.market_man_name,
|
||||
t1.market_man_phone,
|
||||
t1.jx_brand_fee_factor,
|
||||
t1.market_add_fee_factor,
|
||||
t1.payee_name,
|
||||
t1.payee_account_no,
|
||||
t1.payee_bank_branch_name,
|
||||
t1.payee_bank_name,
|
||||
|
||||
t1.pay_percentage,
|
||||
t1.operator_name,
|
||||
t1.operator_phone,
|
||||
|
||||
city.name city_name,
|
||||
district.name district_name,
|
||||
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"vendorStoreID":"', m1.vendor_store_id, '", "vendorID":', m1.vendor_id,
|
||||
', "status":', m1.status, ', "pricePercentage":', m1.price_percentage, ', "vendorStoreName":"',
|
||||
CONCAT('[', GROUP_CONCAT(DISTINCT CONCAT('{"vendorStoreID":"', m1.vendor_store_id, '", "vendorID":', m1.vendor_id,
|
||||
', "status":', m1.status, ', "pricePercentage":', m1.price_percentage, ', "vendorStoreName":"',
|
||||
CASE m1.vendor_id
|
||||
WHEN 0 THEN IF(jd.name IS NULL, '', jd.name)
|
||||
WHEN 3 THEN IF(eb.col_name IS NULL, '', eb.col_name)
|
||||
ELSE ''
|
||||
END,
|
||||
'"}')), ']') store_map_str,
|
||||
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"vendorStoreID":"', m2.vendor_store_id, '", "vendorID":', m2.vendor_id, ', "status":', m2.status, "}")), "]") courier_map_str
|
||||
'", "isSync":', m1.is_sync, '}')), ']') store_map_str,
|
||||
CONCAT('[', GROUP_CONCAT(DISTINCT CONCAT('{"vendorStoreID":"', m2.vendor_store_id, '", "vendorID":', m2.vendor_id,
|
||||
', "status":', m2.status, '}')), ']') courier_map_str
|
||||
FROM store t1
|
||||
LEFT JOIN place city ON t1.city_code = city.code AND city.level = 2
|
||||
LEFT JOIN place district ON t1.district_code = district.code AND district.level = 3
|
||||
@@ -228,7 +291,7 @@ func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interfa
|
||||
}
|
||||
|
||||
sql += sqlWhere + `
|
||||
GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
|
||||
GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53
|
||||
ORDER BY t1.id DESC
|
||||
LIMIT ? OFFSET ?`
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
@@ -249,8 +312,9 @@ func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interfa
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
var storeList []*StoreExt
|
||||
mapLimit := false
|
||||
if err = dao.GetRows(db, &storeList, sql, sqlParams...); err == nil {
|
||||
mapLimit := false
|
||||
// globals.SugarLogger.Debugf("GetStores, len(storeList):%d", len(storeList))
|
||||
var (
|
||||
mapLatitude, mapLongitude float64
|
||||
mapRadius int
|
||||
@@ -289,8 +353,9 @@ func GetStores(ctx *jxcontext.Context, keyword string, params map[string]interfa
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
|
||||
retVal.MapCenterLng, retVal.MapCenterLat = getMapCenter(retVal.Stores)
|
||||
if mapLimit {
|
||||
retVal.MapCenterLng, retVal.MapCenterLat = getMapCenter(retVal.Stores)
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
@@ -365,6 +430,15 @@ func GetVendorStore(ctx *jxcontext.Context, vendorStoreID string, vendorID int)
|
||||
return nil, ErrCanNotFindVendor
|
||||
}
|
||||
|
||||
func isUpdateStoreNeedSync(valid map[string]interface{}) bool {
|
||||
for k := range valid {
|
||||
if storeKeyPropertyMap[k] == 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("UpdateStore storeID:%d, payload:%s", storeID, utils.Format4Output(payload, false))
|
||||
|
||||
@@ -458,14 +532,18 @@ func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interfa
|
||||
dao.Rollback(db)
|
||||
}()
|
||||
if num, err = dao.UpdateEntityLogically(db, store, valid, userName, nil); err == nil && num == 1 {
|
||||
dummy := &model.StoreMap{}
|
||||
_, err2 := dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, dummy, nil, userName, map[string]interface{}{
|
||||
model.FieldStoreID: store.ID,
|
||||
}, model.FieldSyncStatus, syncStatus)
|
||||
if err = err2; err == nil {
|
||||
if isUpdateStoreNeedSync(valid) {
|
||||
dummy := &model.StoreMap{}
|
||||
_, err2 := dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, dummy, nil, userName, map[string]interface{}{
|
||||
model.FieldStoreID: store.ID,
|
||||
}, model.FieldSyncStatus, syncStatus)
|
||||
if err = err2; err == nil {
|
||||
dao.Commit(db)
|
||||
globals.SugarLogger.Debugf("UpdateStore track:%s, before call SyncStore", ctx.GetTrackInfo())
|
||||
_, err = CurVendorSync.SyncStore(ctx, db, -1, store.ID, false, userName)
|
||||
}
|
||||
} else {
|
||||
dao.Commit(db)
|
||||
globals.SugarLogger.Debugf("UpdateStore track:%s, before call SyncStore", ctx.GetTrackInfo())
|
||||
_, err = CurVendorSync.SyncStore(ctx, db, -1, store.ID, false, userName)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -474,6 +552,42 @@ func UpdateStore(ctx *jxcontext.Context, storeID int, payload map[string]interfa
|
||||
return num, err
|
||||
}
|
||||
|
||||
func SetStoreStatus(ctx *jxcontext.Context, storeID, status int) (err error) {
|
||||
payload := map[string]interface{}{
|
||||
"status": status,
|
||||
}
|
||||
_, err = UpdateStore(ctx, storeID, payload, ctx.GetUserName())
|
||||
return err
|
||||
}
|
||||
|
||||
func EnableHaveRestStores(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
storeInfo, err := GetStores(ctx, "", map[string]interface{}{
|
||||
"statuss": string(utils.MustMarshal([]int{model.StoreStatusHaveRest})),
|
||||
}, 0, model.UnlimitedPageSize)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(storeInfo.Stores) == 0 {
|
||||
return "0", nil
|
||||
}
|
||||
|
||||
task := tasksch.NewParallelTask("EnableHaveRestStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
store := batchItemList[0].(*StoreExt)
|
||||
err = SetStoreStatus(ctx, store.ID, model.StoreStatusOpened)
|
||||
return nil, err
|
||||
}, storeInfo.Stores)
|
||||
tasksch.ManageTask(task).Run()
|
||||
if !isAsync {
|
||||
if _, err = task.GetResult(0); err == nil {
|
||||
hint = utils.Int2Str(len(storeInfo.Stores))
|
||||
}
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func CreateStore(ctx *jxcontext.Context, storeExt *StoreExt, userName string) (id int, err error) {
|
||||
globals.SugarLogger.Debugf("CreateStore storeExt:%s", utils.Format4Output(storeExt, false))
|
||||
store := &storeExt.Store
|
||||
@@ -547,6 +661,9 @@ func AddStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID
|
||||
if storeID == 0 {
|
||||
return nil, fmt.Errorf("storeID不能为0")
|
||||
}
|
||||
if vendorID != model.VendorIDJD && (storeMap.AutoPickup == 0) {
|
||||
return nil, fmt.Errorf("非京东平台要求必须自动拣货")
|
||||
}
|
||||
userName := ctx.GetUserName()
|
||||
if handler := CurVendorSync.GetStoreHandler(vendorID); handler != nil {
|
||||
store, err2 := handler.ReadStore(storeMap.VendorStoreID)
|
||||
@@ -605,6 +722,11 @@ func DeleteStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendor
|
||||
}
|
||||
|
||||
func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||||
if vendorID != model.VendorIDJD {
|
||||
if autoPickup, ok := payload["autoPickup"]; ok && autoPickup == 0 {
|
||||
return 0, fmt.Errorf("非京东平台要求必须自动拣货")
|
||||
}
|
||||
}
|
||||
storeHandler := CurVendorSync.GetStoreHandler(vendorID)
|
||||
if storeHandler == nil {
|
||||
return 0, ErrCanNotFindVendor
|
||||
@@ -651,7 +773,7 @@ func UpdateStoreVendorMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendor
|
||||
storeSkuBind := &model.StoreSkuBind{}
|
||||
if num, err = dao.UpdateEntityLogicallyAndUpdateSyncStatus(db, storeSkuBind, nil, userName, map[string]interface{}{
|
||||
model.FieldStoreID: storeID,
|
||||
}, dao.GetSyncStatusStructField(model.VendorNames[vendorID]), model.SyncFlagModifiedMask); err != nil {
|
||||
}, dao.GetSyncStatusStructField(model.VendorNames[vendorID]), model.SyncFlagPriceMask); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
@@ -797,9 +919,22 @@ func AddStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID
|
||||
dao.WrapAddIDCULDEntity(storeCourierMap, userName)
|
||||
storeCourierMap.StoreID = storeID
|
||||
storeCourierMap.VendorID = vendorID
|
||||
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
if vendorID == model.VendorIDDada {
|
||||
storeList, err2 := dao.GetMissingDadaStores(db, storeID, false)
|
||||
if err = err2; err == nil && len(storeList) > 0 {
|
||||
storeList[0].DadaStoreID = storeCourierMap.VendorStoreID
|
||||
err = updateOrCreateDadaStore(storeList[0])
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("AddStoreCourierMap GetMissingDadaStores error:%v, len(storeList):%d", err, len(storeList))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -809,15 +944,6 @@ func AddStoreCourierMap(ctx *jxcontext.Context, db *dao.DaoDB, storeID, vendorID
|
||||
}()
|
||||
if err = dao.CreateEntity(db, storeCourierMap); err == nil {
|
||||
dao.Commit(db)
|
||||
if vendorID == model.VendorIDDada {
|
||||
storeList, err := dao.GetMissingDadaStores(db, storeID, false)
|
||||
if err == nil && len(storeList) > 0 {
|
||||
storeList[0].DadaStoreID = storeCourierMap.VendorStoreID
|
||||
err = updateOrCreateDadaStore(storeList[0])
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("AddStoreCourierMap GetMissingDadaStores error:%v, len(storeList):%d", err, len(storeList))
|
||||
}
|
||||
}
|
||||
outStoreCourierMap = storeCourierMap
|
||||
if err == nil {
|
||||
_, err = CurVendorSync.SyncStore(ctx, db, storeCourierMap.VendorID, storeID, false, userName)
|
||||
@@ -871,46 +997,74 @@ func RefreshMissingDadaStores(ctx *jxcontext.Context, storeID int, isAsync, isCo
|
||||
task := tasksch.NewParallelTask("RefreshMissingDadaStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeDetail := batchItemList[0].(*dao.StoreDetail2)
|
||||
var resultList []interface{}
|
||||
if storeDetail.DadaStoreID == "" {
|
||||
if storeDetail.DistrictName == "" || storeDetail.CityName == "" {
|
||||
return nil, fmt.Errorf("门店:%s的城市码或区码有错误", storeDetail.Name)
|
||||
}
|
||||
db := dao.GetDB()
|
||||
_, err = AddStoreCourierMap(ctx, db, storeDetail.ID, model.VendorIDDada, &model.StoreCourierMap{
|
||||
if _, err = AddStoreCourierMap(ctx, db, storeDetail.ID, model.VendorIDDada, &model.StoreCourierMap{
|
||||
VendorStoreID: utils.Int2Str(storeDetail.ID),
|
||||
Status: model.StoreStatusOpened,
|
||||
})
|
||||
}); err == nil {
|
||||
resultList = append(resultList, 1)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
return resultList, err
|
||||
}, storeList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
} else {
|
||||
hint = task.ID
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func updateOrCreateDadaStore(storeDetail *dao.StoreDetail2) (err error) {
|
||||
_, err = api.DadaAPI.ShopDetail(storeDetail.DadaStoreID)
|
||||
if err != nil {
|
||||
if codeErr, ok := err.(*utils.ErrorWithCode); ok && codeErr.IntCode() == dadaapi.ResponseCodeShopNotExist {
|
||||
_, err = api.DadaAPI.ShopAdd(storeDetail.DadaStoreID, composeDadaStoreName(storeDetail), dadaapi.BusinessTypeConvStore, storeDetail.CityName,
|
||||
storeDetail.DistrictName, storeDetail.Address, jxutils.IntCoordinate2Standard(storeDetail.Lng), jxutils.IntCoordinate2Standard(storeDetail.Lat),
|
||||
storeDetail.Tel1, storeDetail.Tel1, nil)
|
||||
if storeDetail.DistrictName == "" {
|
||||
return fmt.Errorf("门店的区码有问题,请检查")
|
||||
}
|
||||
if storeDetail.CityName == "" {
|
||||
return fmt.Errorf("门店的城市码有问题,请检查")
|
||||
}
|
||||
if dadaDistrictMap[storeDetail.DistrictName] != "" {
|
||||
if dadaDistrictMap[storeDetail.DistrictName] == "1" { // 区镇信息
|
||||
storeDetail.CityName = storeDetail.DistrictName
|
||||
storeDetail.DistrictName, _ = api.AutonaviAPI.GetCoordinateTownInfo(jxutils.IntCoordinate2Standard(storeDetail.Lng), jxutils.IntCoordinate2Standard(storeDetail.Lat))
|
||||
}
|
||||
} else {
|
||||
params := map[string]interface{}{
|
||||
"station_name": composeDadaStoreName(storeDetail),
|
||||
"business": dadaapi.BusinessTypeConvStore,
|
||||
"city_name": storeDetail.CityName,
|
||||
"area_name": storeDetail.DistrictName,
|
||||
"station_address": storeDetail.Address,
|
||||
"lng": jxutils.IntCoordinate2Standard(storeDetail.Lng),
|
||||
"lat": jxutils.IntCoordinate2Standard(storeDetail.Lat),
|
||||
"contact_name": storeDetail.Tel1,
|
||||
"phone": storeDetail.Tel1,
|
||||
if dadaDistrictMap[storeDetail.DistrictName] != "" {
|
||||
storeDetail.DistrictName = dadaDistrictMap[storeDetail.DistrictName]
|
||||
}
|
||||
}
|
||||
if globals.EnableStoreWrite {
|
||||
_, err = api.DadaAPI.ShopDetail(storeDetail.DadaStoreID)
|
||||
if err != nil {
|
||||
if codeErr, ok := err.(*utils.ErrorWithCode); ok && codeErr.IntCode() == dadaapi.ResponseCodeShopNotExist {
|
||||
_, err = api.DadaAPI.ShopAdd(storeDetail.DadaStoreID, composeDadaStoreName(storeDetail), dadaapi.BusinessTypeConvStore, storeDetail.CityName,
|
||||
storeDetail.DistrictName, storeDetail.Address, jxutils.IntCoordinate2Standard(storeDetail.Lng), jxutils.IntCoordinate2Standard(storeDetail.Lat),
|
||||
storeDetail.Tel1, storeDetail.Tel1, nil)
|
||||
}
|
||||
} else {
|
||||
params := map[string]interface{}{
|
||||
"station_name": composeDadaStoreName(storeDetail),
|
||||
"business": dadaapi.BusinessTypeConvStore,
|
||||
"city_name": storeDetail.CityName,
|
||||
"area_name": storeDetail.DistrictName,
|
||||
"station_address": storeDetail.Address,
|
||||
"lng": jxutils.IntCoordinate2Standard(storeDetail.Lng),
|
||||
"lat": jxutils.IntCoordinate2Standard(storeDetail.Lat),
|
||||
"contact_name": storeDetail.Tel1,
|
||||
"phone": storeDetail.Tel1,
|
||||
}
|
||||
err = api.DadaAPI.ShopUpdate(storeDetail.DadaStoreID, params)
|
||||
}
|
||||
err = api.DadaAPI.ShopUpdate(storeDetail.DadaStoreID, params)
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("门店ID:%d,门店名:%s,错误描述:%s", storeDetail.Store.ID, storeDetail.Name, err.Error())
|
||||
globals.SugarLogger.Debugf("updateOrCreateDadaStore storeID:%d failed with error:%v", storeDetail.ID, err)
|
||||
}
|
||||
return err
|
||||
@@ -919,3 +1073,91 @@ func updateOrCreateDadaStore(storeDetail *dao.StoreDetail2) (err error) {
|
||||
func composeDadaStoreName(storeDetail *dao.StoreDetail2) (storeName string) {
|
||||
return storeDetail.Name + "-" + storeDetail.DadaStoreID
|
||||
}
|
||||
|
||||
func ExportShopsHealthInfo(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
vendorID := model.VendorIDEBAI
|
||||
storeMapList, err := dao.GetStoresMapList(db, []int{vendorID}, storeIDs, model.StoreStatusAll)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
storeMap2 := make(map[string]*model.StoreMap)
|
||||
for _, v := range storeMapList {
|
||||
storeMap2[v.VendorStoreID] = v
|
||||
}
|
||||
if len(storeMapList) > 0 {
|
||||
var healthInfoList []interface{}
|
||||
var excelBin []byte
|
||||
var excelURL string
|
||||
task := tasksch.NewSeqTask(fmt.Sprintf("ExportShopHealthInfo[%s]", model.VendorChineseNames[vendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
subTask := tasksch.NewParallelTask(fmt.Sprintf("ExportShopHealthInfo2[%s]", model.VendorChineseNames[vendorID]), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
healthInfo, err := ebai.CurPurchaseHandler.GetShopHealthInfo(storeMap.VendorStoreID)
|
||||
if err == nil {
|
||||
retVal = []map[string]interface{}{healthInfo}
|
||||
}
|
||||
return retVal, err
|
||||
}, storeMapList)
|
||||
tasksch.AddChild(task, subTask).Run()
|
||||
healthInfoList, err = subTask.GetResult(0)
|
||||
if isContinueWhenError && err != nil && len(healthInfoList) > 0 {
|
||||
err = nil
|
||||
}
|
||||
case 1:
|
||||
var healthInfoList2 []map[string]interface{}
|
||||
for _, v := range healthInfoList {
|
||||
mapInfo := v.(map[string]interface{})
|
||||
mapInfo["real_shop_id"] = storeMap2[utils.Interface2String(mapInfo["merchant_id"])].StoreID
|
||||
healthInfoList2 = append(healthInfoList2, mapInfo)
|
||||
}
|
||||
excelConf := &excel.Obj2ExcelSheetConfig{
|
||||
Title: "饿百门店情况导出",
|
||||
Data: healthInfoList2,
|
||||
CaptionList: []string{
|
||||
"real_shop_id",
|
||||
"merchant_id",
|
||||
"merchant_name",
|
||||
"hours",
|
||||
"sku_num",
|
||||
"target_jiedan",
|
||||
"is_healthy",
|
||||
"bad_order_rate",
|
||||
},
|
||||
}
|
||||
excelBin = excel.Obj2Excel([]*excel.Obj2ExcelSheetConfig{excelConf})
|
||||
case 2:
|
||||
keyPart := []string{
|
||||
ctx.GetUserName(),
|
||||
"饿百门店情况",
|
||||
}
|
||||
keyPart = append(keyPart, time.Now().Format("20060102T150405")+".xlsx")
|
||||
key := "export/" + strings.Join(keyPart, "_")
|
||||
excelURL, err = jxutils.UploadExportContent(excelBin, key)
|
||||
if err == nil {
|
||||
task.SetNoticeMsg(excelURL)
|
||||
}
|
||||
globals.SugarLogger.Debugf("导出饿百门店情况excelURL:%s, err:%v", excelURL, err)
|
||||
}
|
||||
return nil, err
|
||||
}, 3)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
if err == nil {
|
||||
hint = excelURL
|
||||
}
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func GetCorporationInfo(ctx *jxcontext.Context, licenceCode string) (corporationInfo *jdapi.CorporationInfo, err error) {
|
||||
corporationInfo, err = api.JdAPI.GetCorporationInfo("", licenceCode)
|
||||
return corporationInfo, err
|
||||
}
|
||||
|
||||
@@ -6,8 +6,14 @@ import (
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/auth/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
@@ -20,6 +26,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
MaxSkuUnitPrice = 100000
|
||||
|
||||
CopyStoreSkuModeFresh = "fresh"
|
||||
CopyStoreSkuModeUpdate = "update"
|
||||
// CopyStoreSkuModeAdd = "add"
|
||||
@@ -48,24 +56,26 @@ type StoreSkuNamesInfo struct {
|
||||
// UpdateStoreSku用,API调用时
|
||||
type StoreSkuBindSkuInfo struct {
|
||||
SkuID int `json:"skuID"`
|
||||
IsSale int `json:"isSale"` // -1:不可售,0:忽略,1:可售
|
||||
IsSale int `json:"isSale,omitempty"` // -1:不可售,0:忽略,1:可售
|
||||
|
||||
ElmID int64 `json:"elmID"`
|
||||
EbaiID int64 `json:"ebaiID"`
|
||||
ElmID int64 `json:"elmID,omitempty"`
|
||||
EbaiID int64 `json:"ebaiID,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateStoreSku用,API调用时
|
||||
type StoreSkuBindInfo struct {
|
||||
StoreID int `json:"storeID"`
|
||||
NameID int `json:"nameID"`
|
||||
UnitPrice int `json:"unitPrice"` // 对于是份的SKU就是单价(每斤价格),其它则为总价
|
||||
IsFocus int `json:"isFocus"` // -1:不关注,0:忽略,1:关注
|
||||
IsSale int `json:"isSale"` // -1:不可售,0:忽略,1:可售
|
||||
SubStoreID int `json:"subStoreID"`
|
||||
Skus []*StoreSkuBindSkuInfo `json:"skus"`
|
||||
SubStoreID int `json:"subStoreID,omitempty"`
|
||||
Skus []*StoreSkuBindSkuInfo `json:"skus,omitempty"`
|
||||
}
|
||||
|
||||
type tStoreSkuBindAndSpec struct {
|
||||
model.StoreSkuBind
|
||||
Name string
|
||||
SpecQuality float32
|
||||
SpecUnit string
|
||||
SkuNamePrice int
|
||||
@@ -88,6 +98,11 @@ type StoreOpRequestInfo struct {
|
||||
UnitPrice int `json:"unitPrice"`
|
||||
}
|
||||
|
||||
const (
|
||||
maxStoreNameBind = 3000 // 最大门店SkuName bind个数
|
||||
maxStoreNameBind2 = 10000 // 最大门店乘SkuName个数
|
||||
)
|
||||
|
||||
func GetStoreSkus(ctx *jxcontext.Context, storeID int, isFocus bool, keyword string, isBySku bool, params map[string]interface{}, offset, pageSize int) (skuNamesInfo *StoreSkuNamesInfo, err error) {
|
||||
return GetStoresSkus(ctx, []int{storeID}, isFocus, keyword, isBySku, params, offset, pageSize)
|
||||
}
|
||||
@@ -102,7 +117,7 @@ func GetStoresSkus(ctx *jxcontext.Context, storeIDs []int, isFocus bool, keyword
|
||||
JOIN store t3 ON t3.id IN (` + dao.GenQuestionMarks(len(storeIDs)) + `)
|
||||
LEFT JOIN store_sku_bind t4 ON t4.sku_id = t2.id AND t4.deleted_at = ? AND t4.store_id = t3.id
|
||||
LEFT JOIN sku_name_place_bind t5 ON t1.id = t5.name_id AND t3.city_code = t5.place_code
|
||||
WHERE t1.deleted_at = ? AND (t1.is_global = 1 OR t5.id IS NOT NULL OR t4.status = ?)/* AND t1.status = ?*/
|
||||
WHERE t1.deleted_at = ? AND (t1.is_global = 1 OR t5.id IS NOT NULL OR 1 = ?)/* AND t1.status = ?*/
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
@@ -110,7 +125,7 @@ func GetStoresSkus(ctx *jxcontext.Context, storeIDs []int, isFocus bool, keyword
|
||||
storeIDs,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
model.SkuStatusNormal,
|
||||
utils.Bool2Int(isFocus),
|
||||
// model.SkuStatusNormal,
|
||||
}
|
||||
if isFocus {
|
||||
@@ -122,12 +137,12 @@ func GetStoresSkus(ctx *jxcontext.Context, storeIDs []int, isFocus bool, keyword
|
||||
}
|
||||
if keyword != "" {
|
||||
keywordLike := "%" + keyword + "%"
|
||||
sql += " AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t2.comment LIKE ?"
|
||||
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike)
|
||||
sql += " AND (t1.name LIKE ? OR t1.prefix LIKE ? OR t1.upc LIKE ? OR t2.comment LIKE ?"
|
||||
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike)
|
||||
|
||||
if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
|
||||
sql += " OR t2.jd_id = ? OR t4.id = ?"
|
||||
sqlParams = append(sqlParams, keywordInt64, keywordInt64)
|
||||
sql += " OR t1.id = ? OR t2.id = ? OR t2.jd_id = ? OR t4.ebai_id = ? OR t4.mtwm_id = ?"
|
||||
sqlParams = append(sqlParams, keywordInt64, keywordInt64, keywordInt64, keywordInt64, keywordInt64)
|
||||
}
|
||||
sql += ")"
|
||||
}
|
||||
@@ -197,14 +212,36 @@ func GetStoresSkus(ctx *jxcontext.Context, storeIDs []int, isFocus bool, keyword
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
}
|
||||
if isFocus && params["fromStatus"] != nil {
|
||||
fromStatus := params["fromStatus"].(int)
|
||||
toStatus := fromStatus
|
||||
if params["toStatus"] != nil {
|
||||
toStatus = params["toStatus"].(int)
|
||||
if isFocus {
|
||||
if params["fromStatus"] != nil {
|
||||
fromStatus := params["fromStatus"].(int)
|
||||
toStatus := fromStatus
|
||||
if params["toStatus"] != nil {
|
||||
toStatus = params["toStatus"].(int)
|
||||
}
|
||||
sql += " AND t4.status >= ? AND t4.status <= ?"
|
||||
sqlParams = append(sqlParams, fromStatus, toStatus)
|
||||
}
|
||||
if params["jdSyncStatus"] != nil || params["ebaiSyncStatus"] != nil || params["mtwmSyncStatus"] != nil {
|
||||
realVendorMap, err2 := getValidStoreVendorMap(db, storeIDs)
|
||||
if err = err2; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sql += " AND ( 1 = 0"
|
||||
if params["jdSyncStatus"] != nil && realVendorMap[model.VendorIDJD] == 1 {
|
||||
sql += " OR (t4.jd_sync_status & ? <> 0 AND t4.jd_sync_status & ? = 0 AND t2.jd_id <> 0 AND t1.status = ? AND t2.status = ?)"
|
||||
sqlParams = append(sqlParams, params["jdSyncStatus"], model.SyncFlagDeletedMask|model.SyncFlagNewMask, model.SkuStatusNormal, model.SkuStatusNormal)
|
||||
}
|
||||
if params["ebaiSyncStatus"] != nil && realVendorMap[model.VendorIDEBAI] == 1 {
|
||||
sql += " OR (t4.ebai_sync_status & ? <> 0 AND t4.ebai_sync_status & ? = 0)"
|
||||
sqlParams = append(sqlParams, params["ebaiSyncStatus"], model.SyncFlagDeletedMask|model.SyncFlagNewMask)
|
||||
}
|
||||
if params["mtwmSyncStatus"] != nil && realVendorMap[model.VendorIDMTWM] == 1 {
|
||||
sql += " OR (t4.mtwm_sync_status & ? <> 0 AND t4.mtwm_sync_status & ? = 0)"
|
||||
sqlParams = append(sqlParams, params["mtwmSyncStatus"], model.SyncFlagDeletedMask|model.SyncFlagNewMask)
|
||||
}
|
||||
sql += ")"
|
||||
}
|
||||
sql += " AND t4.status >= ? AND t4.status <= ?"
|
||||
sqlParams = append(sqlParams, fromStatus, toStatus)
|
||||
}
|
||||
sql += `
|
||||
GROUP BY
|
||||
@@ -392,6 +429,80 @@ func GetStoresSkus(ctx *jxcontext.Context, storeIDs []int, isFocus bool, keyword
|
||||
return skuNamesInfo, err
|
||||
}
|
||||
|
||||
func getValidStoreVendorMap(db *dao.DaoDB, storeIDs []int) (realVendorMap map[int]int, err error) {
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, model.StoreStatusAll)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
realVendorMap = make(map[int]int)
|
||||
for _, v := range storeMapList {
|
||||
if v.IsSync != 0 {
|
||||
realVendorMap[v.VendorID] = 1
|
||||
}
|
||||
}
|
||||
return realVendorMap, nil
|
||||
}
|
||||
|
||||
func GetStoreAbnormalSkuCount(ctx *jxcontext.Context, storeID, syncStatus int, isBySku bool, params map[string]interface{}) (count int, err error) {
|
||||
db := dao.GetDB()
|
||||
realVendorMap, err2 := getValidStoreVendorMap(db, []int{storeID})
|
||||
if err = err2; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
sql := `
|
||||
SELECT COUNT(*) ct`
|
||||
if !isBySku {
|
||||
sql += `
|
||||
FROM (
|
||||
SELECT DISTINCT t3.id`
|
||||
}
|
||||
sql += `
|
||||
FROM store_sku_bind t1
|
||||
JOIN sku t2 ON t2.id = t1.sku_id AND t2.deleted_at = ?
|
||||
JOIN sku_name t3 ON t3.id = t2.name_id AND t3.deleted_at = ?
|
||||
WHERE t1.deleted_at = ? AND t1.store_id = ? AND
|
||||
((t2.status = ? AND t3.status = ?) OR t1.status = ?) AND
|
||||
(1 = 0`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
model.SkuStatusNormal,
|
||||
model.SkuStatusNormal,
|
||||
model.SkuStatusNormal,
|
||||
}
|
||||
for _, vendorID := range []int{model.VendorIDJD, model.VendorIDEBAI, model.VendorIDMTWM} {
|
||||
if realVendorMap[vendorID] != 0 {
|
||||
prefix := dao.ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql += fmt.Sprintf(" OR (t1.%s_sync_status & ? <> 0 AND t1.%s_sync_status & ? = 0", prefix, prefix)
|
||||
sqlParams = append(sqlParams, syncStatus, model.SyncFlagDeletedMask|model.SyncFlagNewMask)
|
||||
if model.MultiStoresVendorMap[vendorID] == 1 {
|
||||
sql += fmt.Sprintf(" AND t2.%s_id <> 0 AND t2.status = ? AND t3.status = ?", prefix)
|
||||
sqlParams = append(sqlParams, model.SkuStatusNormal, model.SkuStatusNormal)
|
||||
}
|
||||
sql += ")"
|
||||
}
|
||||
}
|
||||
sql += ")"
|
||||
if params["fromStatus"] != nil {
|
||||
fromStatus := params["fromStatus"].(int)
|
||||
toStatus := fromStatus
|
||||
if params["toStatus"] != nil {
|
||||
toStatus = params["toStatus"].(int)
|
||||
}
|
||||
sql += " AND t1.status >= ? AND t1.status <= ?"
|
||||
sqlParams = append(sqlParams, fromStatus, toStatus)
|
||||
}
|
||||
if !isBySku {
|
||||
sql += `
|
||||
) t1`
|
||||
}
|
||||
err = dao.GetRow(db, &count, sql, sqlParams...)
|
||||
return count, err
|
||||
}
|
||||
|
||||
func GetStoresSkusSaleInfo(ctx *jxcontext.Context, storeIDs []int, skuIDs []int, fromTime, toTime time.Time, fromCount, toCount int) (saleInfoList []*SkuSaleInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetStoresSkusSaleInfo storeIDs:%v, fromTime:%v, toTime:%v, fromCount:%d, toCount:%d", storeIDs, fromTime, toTime, fromCount, toCount)
|
||||
|
||||
@@ -436,24 +547,65 @@ func UpdateStoreSku(ctx *jxcontext.Context, storeID int, skuBindInfo *StoreSkuBi
|
||||
}
|
||||
|
||||
func UpdateStoreSkus(ctx *jxcontext.Context, storeID int, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
// skuIDs, err := updateStoresSkusWithoutSync(ctx, []int{storeID}, skuBindInfos)
|
||||
// num = int64(len(skuIDs))
|
||||
// if err == nil && num > 0 {
|
||||
// db := dao.GetDB()
|
||||
// _, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, []int{storeID}, skuIDs, false, false)
|
||||
// return int64(len(skuIDs)), err
|
||||
// }
|
||||
// return 0, err
|
||||
return UpdateStoresSkus(ctx, []int{storeID}, skuBindInfos, isAsync, isContinueWhenError)
|
||||
}
|
||||
|
||||
func UpdateStoresSkus(ctx *jxcontext.Context, storeIDs []int, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
var num int64
|
||||
skuIDs, err := updateStoresSkusWithoutSync(ctx, storeIDs, skuBindInfos)
|
||||
db := dao.GetDB()
|
||||
skuIDs, err := updateStoresSkusWithoutSync(ctx, db, storeIDs, skuBindInfos)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
num = int64(len(skuIDs))
|
||||
if num > 0 {
|
||||
db := dao.GetDB()
|
||||
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, isAsync, isContinueWhenError)
|
||||
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
|
||||
}
|
||||
if num == 0 || !isAsync || hint == "" {
|
||||
hint = utils.Int64ToStr(num)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func UpdateStoresSkusByBind(ctx *jxcontext.Context, skuBindInfos []*StoreSkuBindInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
if len(skuBindInfos) > maxStoreNameBind {
|
||||
return "", fmt.Errorf("门店商品信息大于%d", maxStoreNameBind)
|
||||
}
|
||||
skuBindInfosMap := make(map[int][]*StoreSkuBindInfo)
|
||||
storeIDMap := make(map[int]int)
|
||||
for _, v := range skuBindInfos {
|
||||
if v.StoreID > 9 {
|
||||
skuBindInfosMap[v.StoreID] = append(skuBindInfosMap[v.StoreID], v)
|
||||
storeIDMap[v.StoreID] = 1
|
||||
}
|
||||
}
|
||||
storeIDs := jxutils.IntMap2List(storeIDMap)
|
||||
sort.Ints(storeIDs)
|
||||
var num int64
|
||||
skuIDMap := make(map[int]int)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
for _, storeID := range storeIDs {
|
||||
skuIDs, err2 := updateStoresSkusWithoutSync(ctx, db, []int{storeID}, skuBindInfosMap[storeID])
|
||||
if err = err2; err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
for _, v := range skuIDs {
|
||||
skuIDMap[v] = 1
|
||||
}
|
||||
num += int64(len(skuIDs))
|
||||
}
|
||||
dao.Commit(db)
|
||||
if num > 0 {
|
||||
skuIDs := jxutils.IntMap2List(skuIDMap)
|
||||
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
|
||||
}
|
||||
if num == 0 || !isAsync || hint == "" {
|
||||
hint = utils.Int64ToStr(num)
|
||||
@@ -504,13 +656,41 @@ func checkStoresSkusSaleCity(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs []i
|
||||
return err
|
||||
}
|
||||
|
||||
func updateStoresSkusWithoutSync(ctx *jxcontext.Context, storeIDs []int, skuBindInfos []*StoreSkuBindInfo) (needSyncSkus []int, err error) {
|
||||
func uniqueStoreIDs(storeIDs []int) []int {
|
||||
storeIDMap := make(map[int]int)
|
||||
for _, v := range storeIDs {
|
||||
storeIDMap[v] = 1
|
||||
}
|
||||
return jxutils.IntMap2List(storeIDMap)
|
||||
}
|
||||
|
||||
func uniqueStoreNameBind(skuBindInfos []*StoreSkuBindInfo) (outSkuBindInfos []*StoreSkuBindInfo) {
|
||||
nameIDMap := make(map[int]int)
|
||||
for _, v := range skuBindInfos {
|
||||
if nameIDMap[v.NameID] != 1 {
|
||||
outSkuBindInfos = append(outSkuBindInfos, v)
|
||||
nameIDMap[v.NameID] = 1
|
||||
}
|
||||
}
|
||||
return outSkuBindInfos
|
||||
}
|
||||
|
||||
func updateStoresSkusWithoutSync(ctx *jxcontext.Context, db *dao.DaoDB, storeIDs []int, skuBindInfos []*StoreSkuBindInfo) (needSyncSkus []int, err error) {
|
||||
if len(storeIDs)*len(skuBindInfos) > maxStoreNameBind2 {
|
||||
return nil, fmt.Errorf("门店商品信息大于%d", maxStoreNameBind2)
|
||||
}
|
||||
|
||||
storeIDs = uniqueStoreIDs(storeIDs)
|
||||
skuBindInfos = uniqueStoreNameBind(skuBindInfos)
|
||||
|
||||
sort.Ints(storeIDs)
|
||||
globals.SugarLogger.Debugf("updateStoresSkusWithoutSync, storeIDs:%v, skuBindInfos:%s", storeIDs, utils.Format4Output(skuBindInfos, false))
|
||||
db := dao.GetDB()
|
||||
if err = checkStoresSkusSaleCity(ctx, db, storeIDs, skuBindInfos); err != nil {
|
||||
return nil, err
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
// if err = checkStoresSkusSaleCity(ctx, db, storeIDs, skuBindInfos); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
if storeIDs, skuBindInfos, err = filterStorePriceChange(ctx, storeIDs, skuBindInfos); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -527,27 +707,45 @@ func updateStoresSkusWithoutSync(ctx *jxcontext.Context, storeIDs []int, skuBind
|
||||
}()
|
||||
for _, storeID := range storeIDs {
|
||||
for _, skuBindInfo := range skuBindInfos {
|
||||
// 关注且没有给价时,需要尝试从store_sku_bind中得到已有的单价
|
||||
needGetExistingUnitPrice := skuBindInfo.UnitPrice == 0 && skuBindInfo.IsFocus == 1
|
||||
inSkuBinds := skuBindInfo.Skus
|
||||
var allBinds []*tStoreSkuBindAndSpec
|
||||
sql := `
|
||||
SELECT
|
||||
t2.*,
|
||||
t1.id real_sku_id, t1.spec_quality, t1.spec_unit,
|
||||
t3.price sku_name_price, t3.unit sku_name_unit
|
||||
t1.id real_sku_id, t1.spec_quality, t1.spec_unit,`
|
||||
if needGetExistingUnitPrice {
|
||||
sql += " IF(t5.unit_price > 0, t5.unit_price, t3.price) sku_name_price,"
|
||||
}
|
||||
sql += `
|
||||
t3.unit sku_name_unit, t3.name
|
||||
FROM sku t1
|
||||
JOIN store ts ON ts.id = ? AND ts.deleted_at = ?
|
||||
LEFT JOIN store_sku_bind t2 ON t2.sku_id = t1.id AND t2.store_id = ts.id AND t2.deleted_at = ?
|
||||
JOIN sku_name t3 ON t1.name_id = t3.id AND t3.deleted_at = ?
|
||||
WHERE t1.name_id = ? AND t1.deleted_at = ?
|
||||
FOR UPDATE`
|
||||
JOIN sku_name t3 ON t1.name_id = t3.id AND t3.deleted_at = ?`
|
||||
sqlParams := []interface{}{
|
||||
storeID,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
skuBindInfo.NameID,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if needGetExistingUnitPrice {
|
||||
sql += `
|
||||
LEFT JOIN (
|
||||
SELECT t7.store_id, t8.name_id, CAST(AVG(t7.unit_price) AS SIGNED) unit_price
|
||||
FROM store_sku_bind t7
|
||||
JOIN sku t8 ON t8.id = t7.sku_id AND t8.name_id = ?
|
||||
WHERE t7.deleted_at = ? AND t7.store_id = ?
|
||||
GROUP BY 1,2
|
||||
) t5 ON t5.store_id = ts.id AND t5.name_id = t1.name_id`
|
||||
sqlParams = append(sqlParams, skuBindInfo.NameID, utils.DefaultTimeValue, storeID)
|
||||
}
|
||||
sql += `
|
||||
WHERE t1.name_id = ? AND t1.deleted_at = ?
|
||||
FOR UPDATE`
|
||||
sqlParams = append(sqlParams, skuBindInfo.NameID, utils.DefaultTimeValue)
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
if err = dao.GetRows(db, &allBinds, sql, sqlParams...); err == nil {
|
||||
if len(allBinds) > 0 {
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(allBinds, false))
|
||||
@@ -557,6 +755,10 @@ func updateStoresSkusWithoutSync(ctx *jxcontext.Context, storeIDs []int, skuBind
|
||||
}
|
||||
unitPrice := 0
|
||||
if skuBindInfo.UnitPrice != 0 {
|
||||
if skuBindInfo.UnitPrice > MaxSkuUnitPrice {
|
||||
dao.Rollback(db)
|
||||
return nil, fmt.Errorf("商品:%s价格:%s太夸张", allBinds[0].Name, jxutils.IntPrice2StandardCurrencyString(int64(skuBindInfo.UnitPrice)))
|
||||
}
|
||||
unitPrice = skuBindInfo.UnitPrice
|
||||
} else {
|
||||
unitPrice = allBinds[0].UnitPrice
|
||||
@@ -650,7 +852,7 @@ func updateStoresSkusWithoutSync(ctx *jxcontext.Context, storeIDs []int, skuBind
|
||||
updateFieldMap[model.FieldUpdatedAt] = 1
|
||||
updateFieldMap[model.FieldLastOperator] = 1
|
||||
|
||||
setStoreSkuBindStatus(skuBind, model.SyncFlagModifiedMask)
|
||||
// setStoreSkuBindStatus(skuBind, model.SyncFlagModifiedMask)
|
||||
dao.WrapUpdateULEntity(skuBind, userName)
|
||||
if num, err = dao.UpdateEntity(db, skuBind /*, utils.Map2KeySlice(updateFieldMap)...*/); err != nil {
|
||||
dao.Rollback(db)
|
||||
@@ -712,11 +914,11 @@ func updateStoreSkusSaleWithoutSync(ctx *jxcontext.Context, storeID int, skuBind
|
||||
}
|
||||
if num, err = dao.UpdateEntityLogically(db, skuBind, map[string]interface{}{
|
||||
model.FieldStatus: skuBind.Status,
|
||||
model.FieldJdSyncStatus: skuBind.JdSyncStatus | model.SyncFlagSaleMask | model.SyncFlagModifiedMask,
|
||||
model.FieldEbaiSyncStatus: skuBind.EbaiSyncStatus | model.SyncFlagSaleMask | model.SyncFlagModifiedMask,
|
||||
model.FieldMtwmSyncStatus: skuBind.MtwmSyncStatus | model.SyncFlagSaleMask | model.SyncFlagModifiedMask,
|
||||
model.FieldElmSyncStatus: skuBind.ElmSyncStatus | model.SyncFlagSaleMask | model.SyncFlagModifiedMask,
|
||||
model.FieldWscSyncStatus: skuBind.WscSyncStatus | model.SyncFlagSaleMask | model.SyncFlagModifiedMask,
|
||||
model.FieldJdSyncStatus: skuBind.JdSyncStatus | model.SyncFlagSaleMask,
|
||||
model.FieldEbaiSyncStatus: skuBind.EbaiSyncStatus | model.SyncFlagSaleMask,
|
||||
model.FieldMtwmSyncStatus: skuBind.MtwmSyncStatus | model.SyncFlagSaleMask,
|
||||
model.FieldElmSyncStatus: skuBind.ElmSyncStatus | model.SyncFlagSaleMask,
|
||||
model.FieldWscSyncStatus: skuBind.WscSyncStatus | model.SyncFlagSaleMask,
|
||||
}, userName, map[string]interface{}{
|
||||
model.FieldStoreID: storeID,
|
||||
model.FieldSkuID: v.SkuID,
|
||||
@@ -734,7 +936,21 @@ func updateStoreSkusSaleWithoutSync(ctx *jxcontext.Context, storeID int, skuBind
|
||||
return needSyncSkus, err
|
||||
}
|
||||
|
||||
func uniqueStoreSkuBind(skuBindSkuInfos []*StoreSkuBindSkuInfo) (outSkuBindSkuInfos []*StoreSkuBindSkuInfo) {
|
||||
skuIDMap := make(map[int]int)
|
||||
for _, v := range skuBindSkuInfos {
|
||||
if skuIDMap[v.SkuID] != 1 {
|
||||
outSkuBindSkuInfos = append(outSkuBindSkuInfos, v)
|
||||
skuIDMap[v.SkuID] = 1
|
||||
}
|
||||
}
|
||||
return outSkuBindSkuInfos
|
||||
}
|
||||
|
||||
func UpdateStoresSkusSale(ctx *jxcontext.Context, storeIDs []int, skuBindSkuInfos []*StoreSkuBindSkuInfo, userName string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
storeIDs = uniqueStoreIDs(storeIDs)
|
||||
skuBindSkuInfos = uniqueStoreSkuBind(skuBindSkuInfos)
|
||||
|
||||
var num int64
|
||||
for _, storeID := range storeIDs {
|
||||
skuIDs, err2 := updateStoreSkusSaleWithoutSync(ctx, storeID, skuBindSkuInfos, userName)
|
||||
@@ -749,7 +965,7 @@ func UpdateStoresSkusSale(ctx *jxcontext.Context, storeIDs []int, skuBindSkuInfo
|
||||
skuIDs = append(skuIDs, v.SkuID)
|
||||
}
|
||||
db := dao.GetDB()
|
||||
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, isAsync, isContinueWhenError)
|
||||
hint, err = CurVendorSync.SyncStoresSkus(ctx, db, nil, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
|
||||
}
|
||||
if num == 0 || !isAsync || hint == "" {
|
||||
hint = utils.Int64ToStr(num)
|
||||
@@ -823,11 +1039,11 @@ func CopyStoreSkus(ctx *jxcontext.Context, fromStoreID, toStoreID int, copyMode
|
||||
now,
|
||||
pricePercentage,
|
||||
pricePercentage,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask,
|
||||
model.SyncFlagPriceMask,
|
||||
model.SyncFlagPriceMask,
|
||||
model.SyncFlagPriceMask,
|
||||
model.SyncFlagPriceMask,
|
||||
model.SyncFlagPriceMask,
|
||||
toStoreID,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
@@ -927,11 +1143,11 @@ func CopyStoreSkus(ctx *jxcontext.Context, fromStoreID, toStoreID int, copyMode
|
||||
pricePercentage,
|
||||
pricePercentage,
|
||||
pricePercentage,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask | model.SyncFlagSaleMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask | model.SyncFlagSaleMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask | model.SyncFlagSaleMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask | model.SyncFlagSaleMask,
|
||||
model.SyncFlagModifiedMask | model.SyncFlagPriceMask | model.SyncFlagSaleMask,
|
||||
model.SyncFlagStoreSkuOnlyMask,
|
||||
model.SyncFlagStoreSkuOnlyMask,
|
||||
model.SyncFlagStoreSkuOnlyMask,
|
||||
model.SyncFlagStoreSkuOnlyMask,
|
||||
model.SyncFlagStoreSkuOnlyMask,
|
||||
toStoreID,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
@@ -1349,3 +1565,186 @@ func checkStoreExisting(db *dao.DaoDB, storeID int) (err error) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RefreshStoresSkuByVendor(ctx *jxcontext.Context, storeIDs []int, vendorID int, isAsync bool) (hint string, err error) {
|
||||
if vendorID != model.VendorIDJD {
|
||||
return "", fmt.Errorf("此功能当前只支持京东到家平台")
|
||||
}
|
||||
db := dao.GetDB()
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, storeIDs, model.StoreStatusAll)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(storeMapList) != len(storeIDs) {
|
||||
return "", fmt.Errorf("门店绑定信息不匹配,请确定门店绑定且只绑定了京东平台")
|
||||
}
|
||||
storeMap := make(map[int]*model.StoreMap)
|
||||
for _, v := range storeMapList {
|
||||
if v.VendorID != vendorID {
|
||||
return "", fmt.Errorf("门店%d绑定的不(只)是京东", v.StoreID)
|
||||
}
|
||||
storeMap[v.StoreID] = v
|
||||
}
|
||||
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
|
||||
var storeSkuList []*model.StoreSkuBind
|
||||
rootTask := tasksch.NewSeqTask(fmt.Sprintf("根据厂家门店商品信息相应刷新本地数据:%v", storeIDs), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
storeSkuList, err = handler.GetStoresSku(ctx, task, storeIDs)
|
||||
case 1:
|
||||
if len(storeSkuList) > 0 {
|
||||
var skuList []*model.SkuAndName
|
||||
skuList, err = dao.GetSkus(db, nil, nil, nil, nil)
|
||||
if err == nil {
|
||||
skuNameMap := make(map[int]*model.SkuName)
|
||||
skuMap := make(map[int]*model.SkuAndName)
|
||||
for _, sku := range skuList {
|
||||
if skuNameMap[sku.NameID] == nil {
|
||||
skuNameMap[sku.NameID] = &model.SkuName{
|
||||
Unit: sku.Unit,
|
||||
}
|
||||
}
|
||||
skuMap[sku.ID] = sku
|
||||
}
|
||||
for _, v := range storeSkuList {
|
||||
sku := skuMap[v.SkuID]
|
||||
skuName := skuNameMap[sku.NameID]
|
||||
if skuName.IsGlobal == 0 && (jxutils.IsSkuSpecial(sku.SpecQuality, sku.SpecUnit) || skuName.Unit != model.SpecialUnit) {
|
||||
skuName.Price = v.Price
|
||||
skuName.IsGlobal = 1 // 标准价
|
||||
}
|
||||
}
|
||||
for _, v := range storeSkuList {
|
||||
sku := skuMap[v.SkuID]
|
||||
skuName := skuNameMap[sku.NameID]
|
||||
if skuName.IsGlobal == 0 {
|
||||
if skuName.Price == 0 {
|
||||
skuName.Price = jxutils.CaculateUnitPrice(v.Price, sku.SpecQuality, sku.SpecUnit, skuName.Unit)
|
||||
} else {
|
||||
skuName.Price = (skuName.Price + jxutils.CaculateUnitPrice(v.Price, sku.SpecQuality, sku.SpecUnit, skuName.Unit)) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, v := range storeSkuList {
|
||||
pricePercentage := int(storeMap[v.StoreID].PricePercentage)
|
||||
skuName := skuNameMap[skuMap[v.SkuID].NameID]
|
||||
v.Price = jxutils.CaculateSkuPriceFromVendor(v.Price, pricePercentage, 0)
|
||||
v.UnitPrice = jxutils.CaculateSkuPriceFromVendor(skuName.Price, pricePercentage, 0)
|
||||
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
|
||||
setStoreSkuBindStatus(v, model.SyncFlagNewMask)
|
||||
v.JdSyncStatus = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if len(storeSkuList) > 0 {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if _, err = dao.ExecuteSQL(db, `
|
||||
DELETE t1
|
||||
FROM store_sku_bind t1
|
||||
WHERE t1.store_id IN (
|
||||
`+dao.GenQuestionMarks(len(storeIDs))+")", storeIDs); err == nil {
|
||||
if err = dao.CreateMultiEntities(db, storeSkuList); err == nil {
|
||||
hint = utils.Int2Str(len(storeSkuList))
|
||||
dao.Commit(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, 3)
|
||||
tasksch.ManageTask(rootTask).Run()
|
||||
if isAsync {
|
||||
hint = rootTask.GetID()
|
||||
} else {
|
||||
_, err = rootTask.GetResult(0)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func GetVendorStoreSkusInfo(ctx *jxcontext.Context, storeID int, vendorIDs, skuIDs []int, isContinueWhenError bool) (skuVendorMap map[int][]*partner.BareStoreSkuInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetVendorStoreSkusInfo, storeID:%d, vendorIDs:%v, skuID:%v", storeID, vendorIDs, skuIDs)
|
||||
db := dao.GetDB()
|
||||
var locker sync.RWMutex
|
||||
skuVendorMap = make(map[int][]*partner.BareStoreSkuInfo)
|
||||
_, err = CurVendorSync.LoopStoresMap(ctx, db, fmt.Sprintf("GetVendorStoreSkusInfo storeID:%d", storeID), false, false, vendorIDs, []int{storeID},
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
if handler := CurVendorSync.GetStoreHandler(loopMapInfo.VendorID); handler != nil {
|
||||
storeSkuList, err2 := dao.GetStoreSkus2(db, loopMapInfo.VendorID, storeID, skuIDs, false)
|
||||
if err = err2; err == nil && len(storeSkuList) > 0 {
|
||||
bareStoreSkuInfoList := make([]*partner.BareStoreSkuInfo, len(skuIDs))
|
||||
for k, v := range storeSkuList {
|
||||
bareStoreSkuInfoList[k] = &partner.BareStoreSkuInfo{
|
||||
SkuID: v.SkuID,
|
||||
VendorSkuID: v.VendorSkuID,
|
||||
}
|
||||
}
|
||||
outBareStoreSkuInfoList, err2 := handler.GetStoreSkusInfo(ctx, t, loopMapInfo.StoreMapList[0].StoreID, loopMapInfo.StoreMapList[0].VendorStoreID, bareStoreSkuInfoList)
|
||||
if err = err2; err == nil && outBareStoreSkuInfoList != nil {
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
skuVendorMap[loopMapInfo.VendorID] = outBareStoreSkuInfoList
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, true)
|
||||
if err != nil {
|
||||
skuVendorMap = nil
|
||||
}
|
||||
return skuVendorMap, err
|
||||
}
|
||||
|
||||
func SyncJdStoreProducts(ctx *jxcontext.Context, storeIDs, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
isManageIt := len(storeIDs) != 1 || len(skuIDs) == 0 || len(skuIDs) > 8
|
||||
hint, err = CurVendorSync.LoopStoresMap(ctx, db, fmt.Sprintf("京东商家商品状态同步:%v", storeIDs), isAsync, isManageIt, []int{model.VendorIDJD}, storeIDs,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(loopMapInfo.VendorID); handler != nil {
|
||||
jdHandler := handler.(*jd.PurchaseHandler)
|
||||
hint, err2 := jdHandler.SyncStoreProducts(ctx, t, loopMapInfo.StoreMapList[0].StoreID, skuIDs, false, isContinueWhenError)
|
||||
if err = err2; err == nil {
|
||||
retVal = []interface{}{hint}
|
||||
}
|
||||
}
|
||||
return retVal, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}, isContinueWhenError)
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func GetMissingStoreSkuFromOrder(ctx *jxcontext.Context, fromTime time.Time) (missingList []*StoreSkuBindInfo, err error) {
|
||||
storeSkuList, err := dao.GetMissingStoreSkuFromOrder(dao.GetDB(), nil, fromTime)
|
||||
if err == nil {
|
||||
storeSkuNameMap := make(map[int64]*StoreSkuBindInfo)
|
||||
for _, v := range storeSkuList {
|
||||
skuName := storeSkuNameMap[jxutils.Combine2Int(v.StoreID, v.NameID)]
|
||||
if skuName == nil {
|
||||
skuName = &StoreSkuBindInfo{
|
||||
StoreID: v.StoreID,
|
||||
NameID: v.NameID,
|
||||
IsFocus: 1,
|
||||
IsSale: 1,
|
||||
// 这里没有考虑平台价格比例
|
||||
UnitPrice: jxutils.CaculateUnitPrice(v.RefPrice, v.SpecQuality, v.SpecUnit, v.Unit),
|
||||
}
|
||||
missingList = append(missingList, skuName)
|
||||
}
|
||||
skuName.Skus = append(skuName.Skus, &StoreSkuBindSkuInfo{
|
||||
SkuID: v.SkuID,
|
||||
})
|
||||
}
|
||||
}
|
||||
return missingList, err
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ func init() {
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error) {
|
||||
return err
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeStatus:%d", vendorStoreID, storeStatus)
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
@@ -81,14 +82,14 @@ func Init() {
|
||||
}
|
||||
|
||||
func (p *MultiStoreHandlerWrapper) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) {
|
||||
if jxutils.IsFakeID(cat.JdID) {
|
||||
if jxutils.IsEmptyID(cat.JdID) {
|
||||
return nil
|
||||
}
|
||||
return p.IMultipleStoresHandler.DeleteCategory(db, cat, userName)
|
||||
}
|
||||
|
||||
func (p *MultiStoreHandlerWrapper) UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) {
|
||||
if jxutils.IsFakeID(cat.JdID) {
|
||||
if jxutils.IsEmptyID(cat.JdID) {
|
||||
globals.SugarLogger.Warnf("UpdateCategory fakeid cat:%s should not get here", utils.Format4Output(cat, true))
|
||||
return nil
|
||||
}
|
||||
@@ -97,14 +98,14 @@ func (p *MultiStoreHandlerWrapper) UpdateCategory(db *dao.DaoDB, cat *model.SkuC
|
||||
|
||||
func (p *MultiStoreHandlerWrapper) DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("wrapper DeleteSku, sku:%s", utils.Format4Output(sku, false))
|
||||
if jxutils.IsFakeID(sku.JdID) {
|
||||
if jxutils.IsEmptyID(sku.JdID) {
|
||||
return nil
|
||||
}
|
||||
return p.IMultipleStoresHandler.DeleteSku(db, sku, userName)
|
||||
}
|
||||
|
||||
func (p *MultiStoreHandlerWrapper) UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
|
||||
if jxutils.IsFakeID(sku.JdID) {
|
||||
if jxutils.IsEmptyID(sku.JdID) {
|
||||
globals.SugarLogger.Warnf("UpdateSku fakeid sku:%s should not get here", utils.Format4Output(sku, true))
|
||||
return nil
|
||||
}
|
||||
@@ -213,32 +214,36 @@ func (v *VendorSync) SyncStore(ctx *jxcontext.Context, db *dao.DaoDB, vendorID,
|
||||
vendorID,
|
||||
}
|
||||
}
|
||||
hint, err = v.LoopStoresMap(ctx, db, fmt.Sprintf("同步门店信息:%d", storeID), isAsync, false, vendorIDs, []int{storeID}, func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
hint, err = v.LoopStoresMap(ctx, db, fmt.Sprintf("同步门店信息:%d", storeID), isAsync, false, vendorIDs, []int{storeID}, func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (resultList interface{}, err error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
handler := v.GetStoreHandler(loopMapInfo.VendorID)
|
||||
if len(loopMapInfo.StoreMapList) > 1 {
|
||||
loopStoreTask := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
var resultList []interface{}
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
if err = handler.UpdateStore(db, storeMap.StoreID, userName); err == nil {
|
||||
storeMap.SyncStatus = 0
|
||||
_, err = dao.UpdateEntity(db, storeMap, model.FieldSyncStatus)
|
||||
resultList = append(resultList, 1)
|
||||
}
|
||||
return nil, err
|
||||
return resultList, err
|
||||
}, loopMapInfo.StoreMapList)
|
||||
t.AddChild(loopStoreTask).Run()
|
||||
_, err = loopStoreTask.GetResult(0)
|
||||
return nil, err
|
||||
resultList, err = loopStoreTask.GetResult(0)
|
||||
} else {
|
||||
storeMap := loopMapInfo.StoreMapList[0]
|
||||
if err = handler.UpdateStore(db, storeMap.StoreID, userName); err == nil {
|
||||
storeMap.SyncStatus = 0
|
||||
_, err = dao.UpdateEntity(db, storeMap, model.FieldSyncStatus)
|
||||
}
|
||||
if err == nil {
|
||||
resultList = []interface{}{1}
|
||||
}
|
||||
}
|
||||
storeMap := loopMapInfo.StoreMapList[0]
|
||||
if err = handler.UpdateStore(db, storeMap.StoreID, userName); err == nil {
|
||||
storeMap.SyncStatus = 0
|
||||
_, err = dao.UpdateEntity(db, storeMap, model.FieldSyncStatus)
|
||||
}
|
||||
err = jxutils.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
return nil, err
|
||||
})
|
||||
return hint, err
|
||||
return resultList, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}, true)
|
||||
return hint, makeSyncError(err)
|
||||
}
|
||||
|
||||
func (v *VendorSync) SyncSku(ctx *jxcontext.Context, db *dao.DaoDB, nameID, skuID int, isAsync, isContinueWhenError bool, userName string) (hint string, err error) {
|
||||
@@ -259,6 +264,7 @@ func (v *VendorSync) SyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []i
|
||||
globals.SugarLogger.Debugf("SyncSku trackInfo:%s, nameIDs:%v, skuIDs:%v, userName:%s", ctx.GetTrackInfo(), nameIDs, skuIDs, userName)
|
||||
return v.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("同步商品信息, nameIDs:%v, skuIDs:%v", nameIDs, skuIDs), isAsync, userName,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
var resultList []interface{}
|
||||
vendorID := batchItemList[0].(int)
|
||||
multiStoresHandler := v.GetMultiStoreHandler(vendorID)
|
||||
syncStatusFieldName := dao.GetSyncStatusStructField(model.VendorNames[multiStoresHandler.GetVendorID()])
|
||||
@@ -297,6 +303,7 @@ func (v *VendorSync) SyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []i
|
||||
// todo 同一skuName下的sku顺序处理的原因是京东SPU特殊类型必须要序列化同步才能正常处理, db可能会有多线程问题
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[vendorID]), tasksch.NewParallelConfig().SetParallelCount(10).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
var resultList []interface{}
|
||||
skuName := batchItemList[0].(*model.SkuName)
|
||||
var skuList []*model.Sku
|
||||
if err = dao.GetRows(db, &skuList, fmt.Sprintf(`
|
||||
@@ -333,6 +340,8 @@ func (v *VendorSync) SyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []i
|
||||
refutil.SetObjFieldByName(sku, syncStatusFieldName, int8(0))
|
||||
if _, err = dao.UpdateEntity(db, sku, updateFields...); err != nil {
|
||||
break
|
||||
} else {
|
||||
resultList = append(resultList, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,22 +351,28 @@ func (v *VendorSync) SyncSkus(ctx *jxcontext.Context, db *dao.DaoDB, nameIDs []i
|
||||
refutil.SetObjFieldByName(skuName, syncStatusFieldName, int8(0))
|
||||
_, err = dao.UpdateEntity(db, skuName, syncStatusFieldName)
|
||||
}
|
||||
return nil, err
|
||||
return resultList, err
|
||||
}, skuNameList)
|
||||
t.AddChild(task).Run()
|
||||
_, err = task.GetResult(0)
|
||||
result, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
resultList = append(resultList, result...)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
return resultList, err
|
||||
})
|
||||
}
|
||||
|
||||
func (v *VendorSync) SyncStoresCategory(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, isAsync bool) (hint string, err error) {
|
||||
func (v *VendorSync) SyncStoresCategory(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debug("SyncStoresCategory")
|
||||
isManageIt := len(storeIDs) != 1
|
||||
return v.LoopStoresMap(ctx, db, fmt.Sprintf("同步门店分类信息:%v", storeIDs), isAsync, isManageIt, vendorIDs, storeIDs,
|
||||
hint, err = v.LoopStoresMap(ctx, db, fmt.Sprintf("同步门店分类信息:%v", storeIDs), isAsync, isManageIt, vendorIDs, storeIDs,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
if handler := v.GetSingleStoreHandler(loopMapInfo.VendorID); handler != nil {
|
||||
if isForce {
|
||||
dao.SetStoreCategorySyncStatus(db, loopMapInfo.VendorID, storeIDs, nil, model.SyncFlagModifiedMask)
|
||||
}
|
||||
if len(loopMapInfo.StoreMapList) > 1 {
|
||||
loopStoreTask := tasksch.NewSeqTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
@@ -367,73 +382,120 @@ func (v *VendorSync) SyncStoresCategory(ctx *jxcontext.Context, db *dao.DaoDB, v
|
||||
}, len(loopMapInfo.StoreMapList))
|
||||
t.AddChild(loopStoreTask).Run()
|
||||
_, err = loopStoreTask.GetResult(0)
|
||||
return nil, err
|
||||
} else {
|
||||
_, err = handler.SyncStoreCategory(ctx, t, loopMapInfo.StoreMapList[0].StoreID, false)
|
||||
}
|
||||
_, err = handler.SyncStoreCategory(ctx, t, loopMapInfo.StoreMapList[0].StoreID, false)
|
||||
err = jxutils.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}
|
||||
return nil, err
|
||||
})
|
||||
return nil, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}, isContinueWhenError)
|
||||
return hint, makeSyncError(err)
|
||||
}
|
||||
|
||||
//
|
||||
func (v *VendorSync) SyncStoresSkus(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
func (v *VendorSync) SyncStoresSkus(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, skuIDs []int, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debug("SyncStoresSkus")
|
||||
isManageIt := len(storeIDs) != 1 || len(skuIDs) == 0 || len(skuIDs) > 8
|
||||
return v.LoopStoresMap(ctx, db, fmt.Sprintf("同步门店商品信息:%v", storeIDs), isAsync, isManageIt, vendorIDs, storeIDs,
|
||||
task, hint, err := v.LoopStoresMap2(ctx, db, fmt.Sprintf("同步门店商品信息:%v", storeIDs), isAsync, isManageIt, vendorIDs, storeIDs,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
if handler := v.GetStoreHandler(loopMapInfo.VendorID); handler != nil {
|
||||
if isForce {
|
||||
dao.SetStoreSkuSyncStatus(db, loopMapInfo.VendorID, storeIDs, skuIDs, model.SyncFlagModifiedMask)
|
||||
}
|
||||
if len(loopMapInfo.StoreMapList) > 1 {
|
||||
loopStoreTask := tasksch.NewSeqTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
storeID := loopMapInfo.StoreMapList[step].StoreID
|
||||
if _, err = handler.SyncStoreSkus(ctx, task, storeID, skuIDs, false, isContinueWhenError); err != nil {
|
||||
globals.SugarLogger.Debugf("SyncStoresSkus failed1 store:%d failed with error:%v", storeID, err)
|
||||
if isContinueWhenError {
|
||||
err = nil
|
||||
var loopStoreTask tasksch.ITask
|
||||
if model.MultiStoresVendorMap[loopMapInfo.VendorID] == 1 {
|
||||
loopStoreTask = tasksch.NewSeqTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
storeID := loopMapInfo.StoreMapList[step].StoreID
|
||||
if _, err = handler.SyncStoreSkus(ctx, task, storeID, skuIDs, false, isContinueWhenError); err != nil {
|
||||
globals.SugarLogger.Debugf("SyncStoresSkus failed1 store:%d failed with error:%v", storeID, err)
|
||||
if isContinueWhenError {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, len(loopMapInfo.StoreMapList))
|
||||
return nil, err
|
||||
}, len(loopMapInfo.StoreMapList))
|
||||
} else {
|
||||
loopStoreTask = tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
if _, err = handler.SyncStoreSkus(ctx, task, storeMap.StoreID, skuIDs, false, isContinueWhenError); err != nil {
|
||||
globals.SugarLogger.Debugf("SyncStoresSkus failed2 store:%d failed with error:%v", storeMap.StoreID, err)
|
||||
}
|
||||
return nil, err
|
||||
}, loopMapInfo.StoreMapList)
|
||||
}
|
||||
t.AddChild(loopStoreTask).Run()
|
||||
_, err = loopStoreTask.GetResult(0)
|
||||
return nil, err
|
||||
} else {
|
||||
_, err = handler.SyncStoreSkus(ctx, t, loopMapInfo.StoreMapList[0].StoreID, skuIDs, false, isContinueWhenError)
|
||||
}
|
||||
_, err = handler.SyncStoreSkus(ctx, t, loopMapInfo.StoreMapList[0].StoreID, skuIDs, false, isContinueWhenError)
|
||||
err = jxutils.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}
|
||||
return nil, err
|
||||
})
|
||||
return nil, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}, isContinueWhenError)
|
||||
if task != nil {
|
||||
if vendorErr := partner.IsErrChangePriceFailed(task.GetOriginalErr()); vendorErr != nil {
|
||||
platformList := make([]string, len(task.GetDetailErrList()))
|
||||
for k, v := range task.GetDetailErrList() {
|
||||
if vendorErr := partner.IsErrVendorError(v); vendorErr != nil {
|
||||
platformList[k] = model.VendorChineseNames[vendorErr.VendorID()]
|
||||
} else {
|
||||
platformList[k] = "未知"
|
||||
}
|
||||
}
|
||||
err = fmt.Errorf("同步价格失败\n失败平台:%s", strings.Join(platformList, ","))
|
||||
} else {
|
||||
err = makeSyncError(err)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func (v *VendorSync) FullSyncStoresSkus(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debug("FullSyncStoresSkus")
|
||||
return v.LoopStoresMap(ctx, db, fmt.Sprintf("初始化门店商品信息:%v", storeIDs), isAsync, true, vendorIDs, storeIDs,
|
||||
hint, err = v.LoopStoresMap(ctx, db, fmt.Sprintf("初始化门店商品信息:%v", storeIDs), isAsync, true, vendorIDs, storeIDs,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
if handler := v.GetStoreHandler(loopMapInfo.VendorID); handler != nil {
|
||||
if len(loopMapInfo.StoreMapList) > 1 {
|
||||
loopStoreTask := tasksch.NewSeqTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
storeID := loopMapInfo.StoreMapList[step].StoreID
|
||||
_, err = handler.FullSyncStoreSkus(ctx, task, storeID, false, isContinueWhenError)
|
||||
return nil, err
|
||||
}, len(loopMapInfo.StoreMapList))
|
||||
var loopStoreTask tasksch.ITask
|
||||
if model.MultiStoresVendorMap[loopMapInfo.VendorID] == 1 {
|
||||
loopStoreTask = tasksch.NewSeqTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
storeID := loopMapInfo.StoreMapList[step].StoreID
|
||||
if _, err = handler.FullSyncStoreSkus(ctx, task, storeID, false, isContinueWhenError); err != nil {
|
||||
globals.SugarLogger.Debugf("FullSyncStoresSkus failed1 store:%d failed with error:%v", storeID, err)
|
||||
if isContinueWhenError {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, len(loopMapInfo.StoreMapList))
|
||||
} else {
|
||||
loopStoreTask = tasksch.NewParallelTask(fmt.Sprintf("处理平台%s", model.VendorChineseNames[loopMapInfo.VendorID]), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
if _, err = handler.FullSyncStoreSkus(ctx, task, storeMap.StoreID, false, isContinueWhenError); err != nil {
|
||||
globals.SugarLogger.Debugf("FullSyncStoresSkus failed2 store:%d failed with error:%v", storeMap.StoreID, err)
|
||||
}
|
||||
return nil, err
|
||||
}, loopMapInfo.StoreMapList)
|
||||
}
|
||||
t.AddChild(loopStoreTask).Run()
|
||||
_, err = loopStoreTask.GetResult(0)
|
||||
return nil, err
|
||||
} else {
|
||||
_, err = handler.FullSyncStoreSkus(ctx, t, loopMapInfo.StoreMapList[0].StoreID, false, isContinueWhenError)
|
||||
}
|
||||
_, err = handler.FullSyncStoreSkus(ctx, t, loopMapInfo.StoreMapList[0].StoreID, false, isContinueWhenError)
|
||||
err = jxutils.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}
|
||||
return nil, err
|
||||
})
|
||||
return nil, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}, isContinueWhenError)
|
||||
return hint, makeSyncError(err)
|
||||
}
|
||||
|
||||
func (v *VendorSync) DeleteRemoteStoreSkus(ctx *jxcontext.Context, db *dao.DaoDB, vendorIDs []int, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debug("DeleteRemoteStoreSkus")
|
||||
return v.LoopStoresMap(ctx, db, fmt.Sprintf("删除远程门店商品信息:%v", storeIDs), isAsync, true, vendorIDs, storeIDs,
|
||||
hint, err = v.LoopStoresMap(ctx, db, fmt.Sprintf("删除远程门店商品信息:%v", storeIDs), isAsync, true, vendorIDs, storeIDs,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
loopMapInfo := batchItemList[0].(*LoopStoreMapInfo)
|
||||
if handler := v.GetStoreHandler(loopMapInfo.VendorID); handler != nil {
|
||||
@@ -446,16 +508,16 @@ func (v *VendorSync) DeleteRemoteStoreSkus(ctx *jxcontext.Context, db *dao.DaoDB
|
||||
}, len(loopMapInfo.StoreMapList))
|
||||
t.AddChild(loopStoreTask).Run()
|
||||
_, err = loopStoreTask.GetResult(0)
|
||||
return nil, err
|
||||
} else {
|
||||
_, err = handler.DeleteRemoteStoreSkus(ctx, t, loopMapInfo.StoreMapList[0].StoreID, false, isContinueWhenError)
|
||||
}
|
||||
_, err = handler.DeleteRemoteStoreSkus(ctx, t, loopMapInfo.StoreMapList[0].StoreID, false, isContinueWhenError)
|
||||
err = jxutils.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}
|
||||
return nil, err
|
||||
})
|
||||
return nil, partner.AddVendorInfo2Err(err, loopMapInfo.VendorID)
|
||||
}, isContinueWhenError)
|
||||
return hint, makeSyncError(err)
|
||||
}
|
||||
|
||||
func (v *VendorSync) LoopStoresMap(ctx *jxcontext.Context, db *dao.DaoDB, taskName string, isAsync, isManageIt bool, vendorIDs []int, storeIDs []int, handler tasksch.WorkFunc) (hint string, err error) {
|
||||
func (v *VendorSync) LoopStoresMap2(ctx *jxcontext.Context, db *dao.DaoDB, taskName string, isAsync, isManageIt bool, vendorIDs []int, storeIDs []int, handler tasksch.WorkFunc, isContinueWhenError bool) (task tasksch.ITask, hint string, err error) {
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM store_map t1
|
||||
@@ -475,11 +537,11 @@ func (v *VendorSync) LoopStoresMap(ctx *jxcontext.Context, db *dao.DaoDB, taskNa
|
||||
sql += " ORDER BY t1.store_id, t1.vendor_id"
|
||||
var storeMapList []*model.StoreMap
|
||||
if err = dao.GetRows(db, &storeMapList, sql, sqlParams...); err != nil {
|
||||
return "", err
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if len(storeMapList) == 0 {
|
||||
return "", nil
|
||||
return nil, "", nil
|
||||
}
|
||||
vendorStoreMap := make(map[int][]*model.StoreMap)
|
||||
for _, v := range storeMapList {
|
||||
@@ -497,21 +559,40 @@ func (v *VendorSync) LoopStoresMap(ctx *jxcontext.Context, db *dao.DaoDB, taskNa
|
||||
if len(loopInfoList) == 1 {
|
||||
taskName = fmt.Sprintf("%s,处理平台%s", taskName, model.VendorChineseNames[loopInfoList[0].VendorID])
|
||||
}
|
||||
task := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, handler, loopInfoList)
|
||||
task = tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, handler, loopInfoList)
|
||||
tasksch.HandleTask(task, nil, isManageIt).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
if len(resultList) == 0 {
|
||||
hint = "1" // todo 暂时这样
|
||||
} else {
|
||||
hint = jxutils.TaskResult2Hint(resultList)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
return task.ID, makeSyncError(err)
|
||||
return task, hint, err
|
||||
}
|
||||
|
||||
func (v *VendorSync) LoopStoresMap(ctx *jxcontext.Context, db *dao.DaoDB, taskName string, isAsync, isManageIt bool, vendorIDs []int, storeIDs []int, handler tasksch.WorkFunc, isContinueWhenError bool) (hint string, err error) {
|
||||
_, hint, err = v.LoopStoresMap2(ctx, db, taskName, isAsync, isManageIt, vendorIDs, storeIDs, handler, isContinueWhenError)
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func (v *VendorSync) LoopMultiStoresVendors(ctx *jxcontext.Context, db *dao.DaoDB, taskName string, isAsync bool, userName string, handler tasksch.WorkFunc) (hint string, err error) {
|
||||
task := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, handler, v.MultiStoreVendorIDs)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
result, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(result))
|
||||
}
|
||||
} else {
|
||||
hint = task.ID
|
||||
}
|
||||
return task.ID, makeSyncError(err)
|
||||
return hint, makeSyncError(err)
|
||||
}
|
||||
|
||||
func (v *VendorSync) RefreshAllSkusID(ctx *jxcontext.Context, isAsync bool, vendorIDs []int, storeIDs []int) (hint string, err error) {
|
||||
@@ -552,8 +633,10 @@ func (v *VendorSync) RefreshAllStoresID(ctx *jxcontext.Context, isAsync bool, ve
|
||||
|
||||
func makeSyncError(err error) (newErr error) {
|
||||
if err != nil {
|
||||
return &SyncError{
|
||||
Original: err,
|
||||
if _, ok := err.(*SyncError); !ok {
|
||||
return &SyncError{
|
||||
Original: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -61,7 +61,7 @@ func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, ti
|
||||
globals.SugarLogger.Debugf("SendFilesToStores upload file:%s", fileHeader.Filename)
|
||||
if err == nil {
|
||||
ret := storage.PutRet{}
|
||||
key := "storeBill_" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
|
||||
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
|
||||
@@ -73,7 +73,7 @@ func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, ti
|
||||
db := dao.GetDB()
|
||||
billRec := &legacymodel.StoreBill{
|
||||
Date: time.Now(),
|
||||
Url: jxutils.ComposeQiniuResURL(strings.Replace(ret.Key, "http://", "https://", -1)),
|
||||
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
|
||||
StoreId: storeID,
|
||||
BillName: fileHeader.Filename,
|
||||
ShopName: shopName,
|
||||
|
||||
@@ -57,86 +57,135 @@ func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *autonavi.Distric
|
||||
}
|
||||
|
||||
func InitPlace(ctx *jxcontext.Context) (err error) {
|
||||
placeList, err2 := api.AutonaviAPI.GetDistricts(autonavi.DistrictLevelDistrict, "")
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
placeList = placeList[0].Districts
|
||||
db := dao.GetDB()
|
||||
if err = TruncateTable(db, "place"); err == nil {
|
||||
placeList, err2 := api.AutonaviAPI.GetDistricts(autonavi.DistrictLevelDistrict, "")
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
placeList = placeList[0].Districts
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
}()
|
||||
if err = insertPlace(ctx, db, nil, placeList); err != nil {
|
||||
return err
|
||||
}
|
||||
updateSqls := []string{
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN jde_city t2 ON t1.code = t2.col_tencentAddressCode
|
||||
SET t1.jd_code = t2.col_areaCode;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN place t2 ON t1.parent_code = t2.code AND t2.jd_code != 0
|
||||
JOIN jde_district t3 ON t1.name = t3.col_areaName AND t2.jd_code = t3.col_cityCode
|
||||
SET t1.jd_code = t3.col_areaCode
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 1 OR t1.level = 2;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN place t1p ON t1.parent_code = t1p.code
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
JOIN ebde_places t2p ON t2.col_parent_id = t2p.col_city_id AND t1p.ebai_code = t2p.col_city_id
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.code = t2.citycode
|
||||
SET t1.mtps_price = t2.price;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.name LIKE CONCAT(t2.cityname, '%')
|
||||
SET t1.mtps_price = t2.price
|
||||
WHERE t1.level = 2 AND t1.mtps_price = 0;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT city_code
|
||||
FROM store
|
||||
UNION DISTINCT
|
||||
SELECT DISTINCT place_code city_code
|
||||
FROM sku_name_place_bind
|
||||
) t2 ON t1.code = t2.city_code
|
||||
SET t1.enabled = 0
|
||||
WHERE t1.level = 2 AND t2.city_code IS NULL;
|
||||
`,
|
||||
}
|
||||
for _, v := range updateSqls {
|
||||
if _, err = dao.ExecuteSQL(db, v); err != nil {
|
||||
return err
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
}()
|
||||
if _, err = dao.ExecuteSQL(db, `
|
||||
DELETE t1
|
||||
FROM place t1
|
||||
WHERE code < 9000000;
|
||||
`); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = insertPlace(ctx, db, nil, placeList); err != nil {
|
||||
return err
|
||||
}
|
||||
updateSqls := []string{
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN jde_city t2 ON t1.code = t2.col_tencentAddressCode
|
||||
SET t1.jd_code = t2.col_areaCode;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN place t2 ON t1.parent_code = t2.code AND t2.jd_code != 0
|
||||
JOIN jde_district t3 ON t1.name = t3.col_areaName AND t2.jd_code = t3.col_cityCode
|
||||
SET t1.jd_code = t3.col_areaCode
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 1 OR t1.level = 2;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN place t1p ON t1.parent_code = t1p.code
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
JOIN ebde_places t2p ON t2.col_parent_id = t2p.col_city_id AND t1p.ebai_code = t2p.col_city_id
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.code = t2.citycode
|
||||
SET t1.mtps_price = t2.price;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.name LIKE CONCAT(t2.cityname, '%')
|
||||
SET t1.mtps_price = t2.price
|
||||
WHERE t1.level = 2 AND t1.mtps_price = 0;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT city_code
|
||||
FROM store
|
||||
UNION DISTINCT
|
||||
SELECT DISTINCT place_code city_code
|
||||
FROM sku_name_place_bind
|
||||
) t2 ON t1.code = t2.city_code
|
||||
SET t1.enabled = 0
|
||||
WHERE t1.level = 2 AND t2.city_code IS NULL;
|
||||
`,
|
||||
}
|
||||
for _, v := range updateSqls {
|
||||
if _, err = dao.ExecuteSQL(db, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func InitSkuName(ctx *jxcontext.Context, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
func RefreshSkuNameImg(ctx *jxcontext.Context, parentTask tasksch.ITask, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
var skuNameList []*model.SkuName
|
||||
if err = dao.GetRows(db, &skuNameList, `
|
||||
SELECT t1.id, t1.img, MAX(t2.jd_id) jd_id
|
||||
FROM sku_name t1
|
||||
JOIN sku t2 ON t2.name_id = t1.id AND t2.deleted_at = ?
|
||||
WHERE t1.deleted_at = ?
|
||||
GROUP BY 1,2
|
||||
ORDER BY t1.id
|
||||
`, utils.DefaultTimeValue, utils.DefaultTimeValue); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
task := tasksch.NewParallelTask("RefreshSkuNameImg", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
skuName := batchItemList[0].(*model.SkuName)
|
||||
if !jxutils.IsEmptyID(skuName.JdID) {
|
||||
if skuName.Img == "" || isForce {
|
||||
var imgList []*jdapi.SkuPageImg
|
||||
if imgList, err = api.JdAPI.GetSkuPageImageInfo(skuName.JdID); err == nil {
|
||||
if len(imgList) > 0 {
|
||||
skuName.Img = imgList[0].Big
|
||||
_, err = dao.UpdateEntity(db, skuName, "Img")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, skuNameList)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.ID
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func RefreshImgMd5(ctx *jxcontext.Context, parentTask tasksch.ITask, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
var skuNameList []*model.SkuName
|
||||
if err = dao.GetRows(db, &skuNameList, `
|
||||
@@ -169,7 +218,7 @@ func InitSkuName(ctx *jxcontext.Context, isForce, isAsync, isContinueWhenError b
|
||||
}
|
||||
return nil, err
|
||||
}, skuNameList)
|
||||
tasksch.ManageTask(task).Run()
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
@@ -178,6 +227,26 @@ func InitSkuName(ctx *jxcontext.Context, isForce, isAsync, isContinueWhenError b
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func InitSkuName(ctx *jxcontext.Context, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
rootTask := tasksch.NewSeqTask("InitSkuName", ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
_, err = RefreshSkuNameImg(ctx, task, isForce, false, isContinueWhenError)
|
||||
case 1:
|
||||
_, err = RefreshImgMd5(ctx, task, isForce, false, isContinueWhenError)
|
||||
}
|
||||
return nil, err
|
||||
}, 2)
|
||||
tasksch.ManageTask(rootTask).Run()
|
||||
if !isAsync {
|
||||
_, err = rootTask.GetResult(0)
|
||||
} else {
|
||||
hint = rootTask.ID
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func InitVendorCategory(ctx *jxcontext.Context, vendorID int) (num int64, err error) {
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
cats, err2 := handler.GetVendorCategories(ctx)
|
||||
@@ -437,7 +506,7 @@ func BuildSkuFromEbaiStore(ctx *jxcontext.Context, baiduShopID int64, isAsync, i
|
||||
}
|
||||
price := sku.LinkID
|
||||
sku.LinkID = 0
|
||||
skuName := jxutils.ComposeSkuName(skuNameExt.Prefix, skuNameExt.Name, sku.Comment, skuNameExt.Unit, sku.SpecQuality, sku.SpecUnit, jdapi.MaxSkuNameLen)
|
||||
skuName := jxutils.ComposeSkuName(skuNameExt.Prefix, skuNameExt.Name, sku.Comment, skuNameExt.Unit, sku.SpecQuality, sku.SpecUnit, jdapi.MaxSkuNameCharCount)
|
||||
fixedStatus := 1
|
||||
if sku.Status != model.SkuStatusNormal {
|
||||
fixedStatus = 2
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
@@ -47,11 +48,10 @@ func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime ti
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE vendor_id = ? AND consignee_mobile2 = '' AND order_created_at <= ?
|
||||
WHERE vendor_id = ? AND consignee_mobile2 = ''
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorID,
|
||||
time.Now().Add(-4 * time.Hour), // 最近的刷新意义不大
|
||||
}
|
||||
if !utils.IsTimeZero(fromTime) {
|
||||
sql += " AND order_created_at >= ?"
|
||||
@@ -97,29 +97,6 @@ func StartGetCityStoreInfo() {
|
||||
}
|
||||
cityCenters = append(cityCenters, guiyang)
|
||||
GetCityStoreInfo(cityCenters)
|
||||
// countries, err := api.AutonaviAPI.GetDistricts(2, "")
|
||||
// if err == nil {
|
||||
// cityCenters := make([]*CityCenter, 0)
|
||||
// country := countries[0]
|
||||
// districts := country.Districts
|
||||
// for _, province := range districts { // 省
|
||||
// for _, city := range province.Districts { // 市
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(city.Name, false))
|
||||
// cityCenter := &CityCenter{
|
||||
// Lng: city.Lng,
|
||||
// Lat: city.Lat,
|
||||
// CityName: city.Name,
|
||||
// }
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(cityCenter, false))
|
||||
// cityCenters = append(cityCenters, cityCenter)
|
||||
// }
|
||||
// }
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(cityCenters, false))
|
||||
// GetCityStoreInfo(cityCenters)
|
||||
// }
|
||||
// utils.AfterFuncWithRecover(12*time.Hour, func() {
|
||||
// StartGetCityStoreInfo()
|
||||
// })
|
||||
}
|
||||
|
||||
func GetCityStoreInfo(cityCenters []*CityCenter) {
|
||||
@@ -233,63 +210,6 @@ func SaveEbaiStoreInfo(storeId, cityName string) {
|
||||
}
|
||||
}
|
||||
|
||||
// func GetCityStoreInfo(cityCenters []*CityCenter, i int) {
|
||||
// cityCenter := cityCenters[i]
|
||||
// cityPoints := GetCityPoints(cityCenter.lng, cityCenter.lat)
|
||||
// GetJdCityPointsStores(jxcontext.AdminCtx, cityPoints, true, true)
|
||||
// utils.AfterFuncWithRecover(10*time.Minute, func() {
|
||||
// GetEbaiCityPointsStores(jxcontext.AdminCtx, cityPoints, true, true)
|
||||
// utils.AfterFuncWithRecover(10*time.Minute, func() {
|
||||
// i++
|
||||
// if i < len(cityCenters) {
|
||||
// GetCityStoreInfo(cityCenters, i)
|
||||
// }
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
|
||||
// func GetJdCityPointsStores(ctx *jxcontext.Context, cityPoints [][]string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
// if len(cityPoints) > 0 {
|
||||
// task := tasksch.NewParallelTask("misc GetJdCityPointsStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// // globals.SugarLogger.Debug(batchItemList)
|
||||
// point := batchItemList[0].([]string)
|
||||
// err2 := jd.OnSaveStoreListInfo(point[0], point[1])
|
||||
// if err = err2; err != nil {
|
||||
// globals.SugarLogger.Infof("GetJdCityPointsStores point:%s,%s failed with error:%v", point[0], point[1], err)
|
||||
// }
|
||||
// return nil, err
|
||||
// }, cityPoints)
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(task, false))
|
||||
// tasksch.HandleTask(task, nil, true).Run()
|
||||
// hint = task.ID
|
||||
// if !isAsync {
|
||||
// _, err = task.GetResult(0)
|
||||
// }
|
||||
// }
|
||||
// return hint, err
|
||||
// }
|
||||
|
||||
// func GetEbaiCityPointsStores(ctx *jxcontext.Context, cityPoints [][]string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
// if len(cityPoints) > 0 {
|
||||
// task := tasksch.NewParallelTask("misc GetEbaiCityPointsStores", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// point := batchItemList[0].([]interface{})
|
||||
// err2 := ebai.OnSaveStoreListInfo(point[0].(string), point[1].(string))
|
||||
// if err = err2; err != nil {
|
||||
// globals.SugarLogger.Infof("GetEbaiCityPointsStores point:%s,%s failed with error:%v", point[0].(string), point[1].(string), err)
|
||||
// }
|
||||
// return nil, err
|
||||
// }, cityPoints)
|
||||
// tasksch.HandleTask(task, nil, true).Run()
|
||||
// hint = task.ID
|
||||
// if !isAsync {
|
||||
// _, err = task.GetResult(0)
|
||||
// }
|
||||
// }
|
||||
// return hint, err
|
||||
// }
|
||||
|
||||
func GetCityPoints(lng float64, lat float64, cityName string) (cityPoints [][]string) {
|
||||
oneDu := 111319.55
|
||||
for a := 0; a <= 80; a++ {
|
||||
@@ -309,3 +229,25 @@ func GetCityPoints(lng float64, lat float64, cityName string) (cityPoints [][]st
|
||||
}
|
||||
return cityPoints
|
||||
}
|
||||
func StartDailyWork() {
|
||||
if globals.ReallyCallPlatformAPI {
|
||||
now := time.Now()
|
||||
runTime := time.Date(now.Year(), now.Month(), now.Day(), 21, 0, 0, 0, time.Local) // 凌晨00:25点开始执行
|
||||
waitDuration := runTime.Sub(now)
|
||||
if waitDuration < 5*time.Second {
|
||||
waitDuration += 24 * time.Hour
|
||||
}
|
||||
globals.SugarLogger.Debugf("dailyWork waitDuration:%d minutes", waitDuration/time.Minute)
|
||||
utils.AfterFuncWithRecover(waitDuration, func() {
|
||||
doDailyWork()
|
||||
StartDailyWork()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func doDailyWork() {
|
||||
globals.SugarLogger.Debug("doDailyWork")
|
||||
cms.EnableHaveRestStores(jxcontext.AdminCtx, true, true)
|
||||
// cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDJD}, nil, true, true)
|
||||
cms.CurVendorSync.SyncStoresSkus(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDJD, model.VendorIDEBAI, model.VendorIDMTWM}, nil, nil, false, true, true)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ type SkuPrice struct {
|
||||
Price int `json:"price"` // 分,这个不是单价,是这个sku的活动价
|
||||
LimitSkuCount int `json:"limitSkuCount"`
|
||||
IsLock int8 `json:"isLock"`
|
||||
|
||||
EarningPrice int `json:"earningPrice"` // 活动商品设置,结算给门店老板的钱
|
||||
}
|
||||
|
||||
type tPromotionItemInfo struct {
|
||||
@@ -131,7 +133,7 @@ var (
|
||||
type JdPromotionHandler interface {
|
||||
CreatePromotionInfos(name string, beginDate, endDate time.Time, outInfoId, advertising string) (infoId int64, err error)
|
||||
CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error)
|
||||
CreatePromotionSku(infoId int64, outInfoId string, skus []map[string]interface{}) (skusResult []map[string]interface{}, err error)
|
||||
CreatePromotionSku(infoId int64, outInfoId string, skus []*jdapi.PromotionSku) (skusResult []*jdapi.PromotionSku, err error)
|
||||
ConfirmPromotion(infoId int64, outInfoId string) (err error)
|
||||
CancelPromotion(infoId int64, outInfoId string) (err error)
|
||||
}
|
||||
@@ -140,38 +142,38 @@ type JdDirectDownHandler struct {
|
||||
}
|
||||
|
||||
func (p *JdDirectDownHandler) CreatePromotionInfos(name string, beginDate, endDate time.Time, outInfoId, advertising string) (infoId int64, err error) {
|
||||
return api.JdAPI.CreatePromotionInfosSingle(name, beginDate, endDate, outInfoId, advertising)
|
||||
return api.JdAPI.CreatePromotionInfosSingle(name, beginDate, endDate, outInfoId, advertising, "")
|
||||
}
|
||||
func (p *JdDirectDownHandler) CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error) {
|
||||
return api.JdAPI.CreatePromotionRules(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily)
|
||||
return api.JdAPI.CreatePromotionRulesSingle(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, "")
|
||||
}
|
||||
func (p *JdDirectDownHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []map[string]interface{}) (skusResult []map[string]interface{}, err error) {
|
||||
return api.JdAPI.CreatePromotionSkuSingle(infoId, outInfoId, skus)
|
||||
func (p *JdDirectDownHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []*jdapi.PromotionSku) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
return api.JdAPI.CreatePromotionSkuSingle(infoId, outInfoId, skus, "")
|
||||
}
|
||||
func (p *JdDirectDownHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) {
|
||||
return api.JdAPI.ConfirmPromotionSingle(infoId, outInfoId)
|
||||
return api.JdAPI.ConfirmPromotionSingle(infoId, outInfoId, "")
|
||||
}
|
||||
func (p *JdDirectDownHandler) CancelPromotion(infoId int64, outInfoId string) (err error) {
|
||||
return api.JdAPI.CancelPromotionSingle(infoId, outInfoId)
|
||||
return api.JdAPI.CancelPromotionSingle(infoId, outInfoId, "")
|
||||
}
|
||||
|
||||
type JdLimitedTimeHandler struct {
|
||||
}
|
||||
|
||||
func (p *JdLimitedTimeHandler) CreatePromotionInfos(name string, beginDate, endDate time.Time, outInfoId, advertising string) (infoId int64, err error) {
|
||||
return api.JdAPI.CreatePromotionInfosLimitTime(name, beginDate, endDate, outInfoId, advertising)
|
||||
return api.JdAPI.CreatePromotionInfosLimitTime(name, beginDate, endDate, outInfoId, advertising, "")
|
||||
}
|
||||
func (p *JdLimitedTimeHandler) CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error) {
|
||||
return api.JdAPI.CreatePromotionRules(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily)
|
||||
return api.JdAPI.CreatePromotionRulesLimitTime(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, "")
|
||||
}
|
||||
func (p *JdLimitedTimeHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []map[string]interface{}) (skusResult []map[string]interface{}, err error) {
|
||||
return api.JdAPI.CreatePromotionSkuLimitTime(infoId, outInfoId, skus)
|
||||
func (p *JdLimitedTimeHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []*jdapi.PromotionSku) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
return api.JdAPI.CreatePromotionSkuLimitTime(infoId, outInfoId, skus, "")
|
||||
}
|
||||
func (p *JdLimitedTimeHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) {
|
||||
return api.JdAPI.ConfirmPromotionLimitTime(infoId, outInfoId)
|
||||
return api.JdAPI.ConfirmPromotionLimitTime(infoId, outInfoId, "")
|
||||
}
|
||||
func (p *JdLimitedTimeHandler) CancelPromotion(infoId int64, outInfoId string) (err error) {
|
||||
return api.JdAPI.CancelPromotionLimitTime(infoId, outInfoId)
|
||||
return api.JdAPI.CancelPromotionLimitTime(infoId, outInfoId, "")
|
||||
}
|
||||
|
||||
type JdNullHandler struct {
|
||||
@@ -183,7 +185,7 @@ func (p *JdNullHandler) CreatePromotionInfos(name string, beginDate, endDate tim
|
||||
func (p *JdNullHandler) CreatePromotionRules(infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int) (err error) {
|
||||
return nil
|
||||
}
|
||||
func (p *JdNullHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []map[string]interface{}) (skusResult []map[string]interface{}, err error) {
|
||||
func (p *JdNullHandler) CreatePromotionSku(infoId int64, outInfoId string, skus []*jdapi.PromotionSku) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (p *JdNullHandler) ConfirmPromotion(infoId int64, outInfoId string) (err error) {
|
||||
@@ -230,7 +232,10 @@ func Init() {
|
||||
// scheduleRoutine(true)
|
||||
}
|
||||
|
||||
func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueWhenError bool, vendorPromotionID string, params *PromotionParams, mapData map[string]interface{}) (hint string, err error) {
|
||||
func CreateJdPromotion(ctx *jxcontext.Context, vendorID int, isIDJd bool, isAsync, isContinueWhenError bool, vendorPromotionID string, params *PromotionParams, mapData map[string]interface{}) (hint string, err error) {
|
||||
if vendorID != model.VendorIDJD && vendorID != model.VendorIDJX {
|
||||
return "", fmt.Errorf("当前只支持京西与京东活动")
|
||||
}
|
||||
if vendorPromotionID != "" && len(vendorPromotionID) != len("14863853") {
|
||||
return "", fmt.Errorf("%s看起来不像是一个有效的京东活动ID,请仔细检查一下", vendorPromotionID)
|
||||
}
|
||||
@@ -260,12 +265,12 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
userName := ctx.GetUserName()
|
||||
db := dao.GetDB()
|
||||
modifyPricesList := make(map[int][]*jdapi.SkuPriceInfo)
|
||||
promotionPrices := make([]map[string]interface{}, len(params.StoreIDs)*len(params.SkuPrices))
|
||||
promotionPrices := make([]*jdapi.PromotionSku, len(params.StoreIDs)*len(params.SkuPrices))
|
||||
var jxStoreIDs []int
|
||||
promotion := &model.Promotion{
|
||||
Name: params.Name,
|
||||
Advertising: params.Advertising,
|
||||
VendorID: model.VendorIDJD,
|
||||
VendorID: vendorID,
|
||||
Type: params.Type,
|
||||
Status: model.PromotionStatusLocalCreated,
|
||||
LimitDevice: int8(limitDevice),
|
||||
@@ -278,7 +283,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
Source: PromotionSourceOpenPlatform,
|
||||
}
|
||||
|
||||
if vendorPromotionID == "" {
|
||||
if vendorPromotionID == "" && vendorID == model.VendorIDJD {
|
||||
skuIDs := make([]int, len(params.SkuPrices))
|
||||
skuPriceMap := make(map[int64]*SkuPrice)
|
||||
for k, v := range params.SkuPrices {
|
||||
@@ -323,7 +328,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
if promotionSkuPrice.PriceType == PriceTypePercentage {
|
||||
promotionSkuPrice.Price = skuBind.Price * promotionSkuPrice.Price / 100
|
||||
}
|
||||
if promotionSkuPrice.Price >= skuBind.Price {
|
||||
if vendorID != model.VendorIDJX && promotionSkuPrice.Price >= skuBind.Price {
|
||||
errMsg += fmt.Sprintf("活动价大于等于原价,storeID:%d, skuID:%d\n", skuBind.StoreID, skuBind.SkuID)
|
||||
}
|
||||
if promotionSkuPrice.LimitSkuCount <= 0 {
|
||||
@@ -338,13 +343,11 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
})
|
||||
}
|
||||
}
|
||||
promotionPrices[index] = map[string]interface{}{
|
||||
jdapi.KeyStationNo: utils.Str2Int64(skuBind.VendorStoreID),
|
||||
jdapi.KeySkuId: skuBind.JdSkuID,
|
||||
// jdapi.KeyOutStationNo: utils.Int2Str(skuBind.StoreID),
|
||||
// jdapi.KeyOutSkuId: utils.Int2Str(skuBind.SkuID),
|
||||
jdapi.KeyPromotionPrice: promotionSkuPrice.Price,
|
||||
jdapi.KeyLimitSkuCount: promotionSkuPrice.LimitSkuCount,
|
||||
promotionPrices[index] = &jdapi.PromotionSku{
|
||||
StationNo: utils.Str2Int64(skuBind.VendorStoreID),
|
||||
SkuID: skuBind.JdSkuID,
|
||||
PromotionPrice: int64(promotionSkuPrice.Price),
|
||||
LimitSkuCount: promotionSkuPrice.LimitSkuCount,
|
||||
}
|
||||
index++
|
||||
}
|
||||
@@ -402,6 +405,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
Price: skuPrice.Price,
|
||||
LimitSkuCount: skuPrice.LimitSkuCount,
|
||||
IsLock: skuPrice.IsLock,
|
||||
EarningPrice: skuPrice.EarningPrice,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(promotionSku, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, promotionSku); err != nil {
|
||||
@@ -409,7 +413,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
}
|
||||
}
|
||||
|
||||
if vendorPromotionID == "" {
|
||||
if vendorID != model.VendorIDJX && vendorPromotionID == "" {
|
||||
promotionHandler := getPromotionHander(params.Type)
|
||||
if promotionHandler == nil {
|
||||
return "", errors.New("非法的活动类型")
|
||||
@@ -436,7 +440,7 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
for k, v := range modifyPrices {
|
||||
modifyPrices2[k] = v.(*jdapi.SkuPriceInfo)
|
||||
}
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if _, err = api.JdAPI.UpdateVendorStationPrice(utils.Int2Str(storeID), "", modifyPrices2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -451,9 +455,9 @@ func CreateJdPromotion(ctx *jxcontext.Context, isIDJd bool, isAsync, isContinueW
|
||||
} else if step == 2 {
|
||||
task2 := tasksch.NewParallelTask("CreateJdPromotion CreatePromotionSku", tasksch.NewParallelConfig().SetBatchSize(MaxPromotionSkuCount).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params2 ...interface{}) (retVal interface{}, err error) {
|
||||
skus := make([]map[string]interface{}, len(batchItemList))
|
||||
skus := make([]*jdapi.PromotionSku, len(batchItemList))
|
||||
for k, v := range batchItemList {
|
||||
skus[k] = v.(map[string]interface{})
|
||||
skus[k] = v.(*jdapi.PromotionSku)
|
||||
}
|
||||
_, err = promotionHandler.CreatePromotionSku(infoId, "", skus)
|
||||
return nil, err
|
||||
@@ -510,7 +514,8 @@ func GetJdPromotions(ctx *jxcontext.Context, keyword string, params map[string]i
|
||||
t1.end_at,
|
||||
t1.advertising,
|
||||
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"storeID":', t2.store_id, ', "name":"', REPLACE(REPLACE(t22.name, '\t', ''), '"', ''), '"}')), "]") store_str,
|
||||
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"skuID":', t3.sku_id, ', "priceType":', t3.price_type, ', "price":', t3.price, ', "limitSkuCount":', t3.limit_sku_count, ', "isLock":', t3.is_lock, '}')), "]") sku_price_str
|
||||
CONCAT("[", GROUP_CONCAT(DISTINCT CONCAT('{"skuID":', t3.sku_id, ', "priceType":', t3.price_type, ', "price":', t3.price,
|
||||
', "limitSkuCount":', t3.limit_sku_count, ', "isLock":', t3.is_lock, ', "earningPrice":', t3.earning_price, '}')), "]") sku_price_str
|
||||
FROM promotion t1
|
||||
JOIN promotion_store t2 ON t1.id = t2.promotion_id
|
||||
JOIN store t22 ON t2.store_id = t22.id
|
||||
@@ -881,6 +886,34 @@ func LockPromotionSkus(ctx *jxcontext.Context, promotionID int, isLock int, skuI
|
||||
return num, err
|
||||
}
|
||||
|
||||
func UpdatePromotionSkusEarningPrice(ctx *jxcontext.Context, promotionID int, skuPriceList []*SkuPrice) (num int64, err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
for _, v := range skuPriceList {
|
||||
var tmpNum int64
|
||||
if tmpNum, err = dao.UpdateEntityLogically(db, &model.PromotionSku{}, map[string]interface{}{
|
||||
"EarningPrice": v.EarningPrice,
|
||||
}, ctx.GetUserName(), map[string]interface{}{
|
||||
"PromotionID": promotionID,
|
||||
model.FieldSkuID: v.SkuID,
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
num += tmpNum
|
||||
}
|
||||
dao.Commit(db)
|
||||
return num, err
|
||||
}
|
||||
|
||||
func OnStoreStockMsg(msg *jdapi.CallbackStoreStockMsg) (retVal *jdapi.CallbackResponse) {
|
||||
var err error
|
||||
// globals.SugarLogger.Debugf("OnStoreStockMsg IsJdStoreSkuLocked:%t", storeskulock.IsJdStoreSkuLocked(msg.StationNo, msg.SkuId))
|
||||
@@ -930,12 +963,12 @@ func createLocalPromotionFromRemote(promotionInfoId int64) (retVal *jdapi.Callba
|
||||
if err = dao.GetEntity(db, promotion, "VendorPromotionID"); dao.IsNoRowsError(err) {
|
||||
storeIDMap := make(map[int64]int)
|
||||
skuIDMap := make(map[int64]int)
|
||||
skuMap := make(map[int64]*jdapi.PromotionSkuResult)
|
||||
skuMap := make(map[int64]*jdapi.PromotionLspQuerySkuResult)
|
||||
// 注意,这样处理可能是有问题,我们假定的是门店信息与SKU信息的叉乘
|
||||
for _, v := range result.SkuResultList {
|
||||
storeIDMap[v.StationNo] = 1
|
||||
skuIDMap[v.SkuId] = 1
|
||||
skuMap[v.SkuId] = v
|
||||
skuIDMap[v.SkuID] = 1
|
||||
skuMap[v.SkuID] = v
|
||||
}
|
||||
jdStoreIDs := make([]string, len(storeIDMap))
|
||||
index := 0
|
||||
@@ -970,7 +1003,7 @@ func createLocalPromotionFromRemote(promotionInfoId int64) (retVal *jdapi.Callba
|
||||
jxStoreIDs[k] = v.StoreID
|
||||
}
|
||||
priceList := make([]*SkuPrice, len(skuList))
|
||||
var skuResult *jdapi.PromotionSkuResult
|
||||
var skuResult *jdapi.PromotionLspQuerySkuResult
|
||||
for k, v := range skuList {
|
||||
skuResult = skuMap[v.JdID]
|
||||
priceList[k] = &SkuPrice{
|
||||
@@ -985,11 +1018,11 @@ func createLocalPromotionFromRemote(promotionInfoId int64) (retVal *jdapi.Callba
|
||||
// globals.SugarLogger.Debugf("priceList:%s", utils.Format4Output(priceList, false))
|
||||
source := strings.Trim(result.Source, "来源")
|
||||
promotionParams := &PromotionParams{
|
||||
Name: source + "-" + utils.Int64ToStr(result.PromotionInfoId),
|
||||
Name: source + "-" + utils.Int64ToStr(result.PromotionInfoID),
|
||||
Advertising: "",
|
||||
Type: result.PromotionType,
|
||||
BeginAt: result.BeginTime,
|
||||
EndAt: result.EndTime,
|
||||
BeginAt: result.BeginTime.GoTime(),
|
||||
EndAt: result.EndTime.GoTime(),
|
||||
StoreIDs: jxStoreIDs,
|
||||
SkuPrices: priceList,
|
||||
}
|
||||
@@ -1002,7 +1035,7 @@ func createLocalPromotionFromRemote(promotionInfoId int64) (retVal *jdapi.Callba
|
||||
mapData[keyLimitDevice] = skuResult.LimitDevice
|
||||
mapData[keyLimitPin] = skuResult.LimitPin
|
||||
}
|
||||
_, err = CreateJdPromotion(jxcontext.AdminCtx, false, true, false, utils.Int64ToStr(promotionInfoId), promotionParams, mapData)
|
||||
_, err = CreateJdPromotion(jxcontext.AdminCtx, model.VendorIDJD, false, true, false, utils.Int64ToStr(promotionInfoId), promotionParams, mapData)
|
||||
if dao.IsDuplicateError(err) || err == ErrLimitDeviceIsInvalid {
|
||||
err = nil
|
||||
}
|
||||
@@ -1048,7 +1081,7 @@ func getPromotionHander(promotionType int) JdPromotionHandler {
|
||||
// panic(fmt.Sprintf("unknown promotion type:%d", promotionType))
|
||||
return nil
|
||||
}
|
||||
if !globals.EnableStoreWrite {
|
||||
if !globals.EnableJdStoreWrite {
|
||||
promotionHandler = &JdNullHandler{}
|
||||
}
|
||||
return promotionHandler
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/delivery"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
@@ -102,7 +104,7 @@ func Convert2JDSPU(ctx *jxcontext.Context, count int, isAsync, isContinueWhenErr
|
||||
skuNew2 := *sku
|
||||
skuNew := &skuNew2
|
||||
dao.WrapAddIDCULEntity(skuNew, ctx.GetUserName())
|
||||
skuNew.JdID = 0 //jxutils.GenFakeID()
|
||||
skuNew.JdID = 0
|
||||
skuNew.LinkID = sku.ID
|
||||
skuNew.NameID = skuNameNew.ID
|
||||
skuNew.JdSyncStatus = model.SyncFlagNewMask
|
||||
@@ -277,7 +279,7 @@ func Change2JDSPU4Store(ctx *jxcontext.Context, storeIDs []int, step int, isAsyn
|
||||
if err = dao.GetRows(db, &skuIDs, sql, sqlParams...); err != nil {
|
||||
return "", err
|
||||
}
|
||||
hint, err = cms.CurVendorSync.SyncStoresSkus(ctx, db, []int{model.VendorIDJD}, storeIDs, skuIDs, isAsync, isContinueWhenError)
|
||||
hint, err = cms.CurVendorSync.SyncStoresSkus(ctx, db, []int{model.VendorIDJD}, storeIDs, skuIDs, false, isAsync, isContinueWhenError)
|
||||
return hint, err
|
||||
}
|
||||
|
||||
@@ -706,7 +708,7 @@ func TransformJdSpu2Sku(ctx *jxcontext.Context, skuNameIDs []int, count int, isA
|
||||
subTask := tasksch.NewParallelTask(fmt.Sprintf("TransformJdSpu2Sku:%d", step), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(subTask *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
skuName := batchItemList[0].(*model.SkuName)
|
||||
if !jxutils.IsFakeID(skuName.JdID) {
|
||||
if !jxutils.IsEmptyID(skuName.JdID) {
|
||||
sql = `
|
||||
SELECT *
|
||||
FROM sku
|
||||
@@ -727,8 +729,8 @@ func TransformJdSpu2Sku(ctx *jxcontext.Context, skuNameIDs []int, count int, isA
|
||||
locker.Lock()
|
||||
skuIDs = append(skuIDs, sku.ID)
|
||||
locker.Unlock()
|
||||
if !jxutils.IsFakeID(sku.JdID) {
|
||||
if globals.EnableStoreWrite {
|
||||
if !jxutils.IsEmptyID(sku.JdID) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if err = api.JdAPI.UpdateSkuBaseInfo(utils.Int2Str(skuName.ID), utils.Int2Str(sku.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted)); err != nil {
|
||||
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 11004 {
|
||||
err = nil
|
||||
@@ -740,7 +742,7 @@ func TransformJdSpu2Sku(ctx *jxcontext.Context, skuNameIDs []int, count int, isA
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil && globals.EnableStoreWrite {
|
||||
if err == nil && globals.EnableJdStoreWrite {
|
||||
if err = api.JdAPI.UpdateSpu(utils.Int2Str(skuName.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusOffline)); err == nil {
|
||||
err = api.JdAPI.UpdateSpu(utils.Int2Str(skuName.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted))
|
||||
} else if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 11035 {
|
||||
@@ -777,7 +779,7 @@ func TransformJdSpu2Sku(ctx *jxcontext.Context, skuNameIDs []int, count int, isA
|
||||
rootTask.AddChild(subTask).Run()
|
||||
if _, err = subTask.GetResult(0); err == nil {
|
||||
if len(skuIDs) > 0 {
|
||||
if _, err = dao.SetStoreSkuSyncStatus(db, model.VendorIDJD, -1, skuIDs, model.SyncFlagModifiedMask|model.SyncFlagPriceMask|model.SyncFlagSaleMask); err == nil {
|
||||
if _, err = dao.SetStoreSkuSyncStatus(db, model.VendorIDJD, nil, skuIDs, model.SyncFlagStoreSkuModifiedMask); err == nil {
|
||||
// time.Sleep(20 * time.Second)
|
||||
// _, err = cms.CurVendorSync.SyncStoresSkus(ctx, db, []int{model.VendorIDJD}, nil, skuIDs, false, isContinueWhenError)
|
||||
}
|
||||
@@ -960,3 +962,29 @@ func RetrieveEbaiShopLicence(ctx *jxcontext.Context, isAsync, isContinueWhenErro
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func RefreshMtpsWaybillFee(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
var waybillList []*model.Waybill
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &waybillList, `
|
||||
SELECT *
|
||||
FROM waybill
|
||||
WHERE status_time > '2019-04-01' AND waybill_vendor_id = 102 AND desired_fee = 0
|
||||
`); err == nil {
|
||||
globals.SugarLogger.Debugf("RefreshMtpsWaybillFee, count:%d", len(waybillList))
|
||||
rootTask := tasksch.NewParallelTask("RefreshMtpsWaybillFee", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
bill := batchItemList[0].(*model.Waybill)
|
||||
bill.DesiredFee, _ = delivery.CalculateBillDeliveryFee(bill)
|
||||
_, err = dao.UpdateEntity(db, bill, "DesiredFee")
|
||||
return nil, err
|
||||
}, waybillList)
|
||||
tasksch.ManageTask(rootTask).Run()
|
||||
if !isAsync {
|
||||
_, err = rootTask.GetResult(0)
|
||||
} else {
|
||||
hint = rootTask.ID
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
@@ -45,19 +45,44 @@ func Obj2Excel(sheetList []*Obj2ExcelSheetConfig) []byte {
|
||||
} else {
|
||||
excelFile.NewSheet(sheetConfig.Title)
|
||||
}
|
||||
for index, name := range sheetConfig.CaptionList {
|
||||
excelFile.SetCellStr(sheetConfig.Title, genAxis(0, index), name)
|
||||
}
|
||||
for i := 0; i < valueInfo.Len(); i++ {
|
||||
var mapData map[string]interface{}
|
||||
if typeInfo.Kind() == reflect.Struct {
|
||||
mapData = utils.FlatMap(utils.Struct2MapByJson(valueInfo.Index(i).Interface()))
|
||||
} else {
|
||||
mapData = valueInfo.Index(i).Interface().(map[string]interface{})
|
||||
isMemberStruct := typeInfo.Kind() == reflect.Struct
|
||||
if isMemberStruct {
|
||||
var indexSlice [][]int
|
||||
name2IndexMap := utils.GetStructNameIndex(typeInfo, "json")
|
||||
for col, name := range sheetConfig.CaptionList {
|
||||
if _, ok := name2IndexMap[name]; !ok {
|
||||
panic(fmt.Sprintf("col:%s不能找到相应的数据", name))
|
||||
}
|
||||
indexSlice = append(indexSlice, name2IndexMap[name])
|
||||
excelFile.SetCellStr(sheetConfig.Title, genAxis(0, col), name)
|
||||
}
|
||||
for index, name := range sheetConfig.CaptionList {
|
||||
// globals.SugarLogger.Debug(sheetConfig.Title, " ", genAxis(i+1, index), " ", fmt.Sprintf("%v", mapData[name]))
|
||||
excelFile.SetCellStr(sheetConfig.Title, genAxis(i+1, index), fmt.Sprintf("%v", mapData[name]))
|
||||
for i := 0; i < valueInfo.Len(); i++ {
|
||||
for col, index := range indexSlice {
|
||||
excelFile.SetCellStr(sheetConfig.Title, genAxis(i+1, col), fmt.Sprint(reflect.Indirect(valueInfo.Index(i)).FieldByIndex(index).Interface()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var name2IndexMap map[string]int
|
||||
if valueInfo.Len() > 0 {
|
||||
oneData := valueInfo.Index(0).Interface().(map[string]interface{})
|
||||
name2IndexMap = make(map[string]int)
|
||||
for k := range oneData {
|
||||
name2IndexMap[k] = 1
|
||||
}
|
||||
}
|
||||
for col, name := range sheetConfig.CaptionList {
|
||||
if name2IndexMap != nil {
|
||||
if _, ok := name2IndexMap[name]; !ok {
|
||||
panic(fmt.Sprintf("col:%s不能找到相应的数据", name))
|
||||
}
|
||||
}
|
||||
excelFile.SetCellStr(sheetConfig.Title, genAxis(0, col), name)
|
||||
}
|
||||
for i := 0; i < valueInfo.Len(); i++ {
|
||||
mapData := valueInfo.Index(i).Interface().(map[string]interface{})
|
||||
for col, name := range sheetConfig.CaptionList {
|
||||
excelFile.SetCellStr(sheetConfig.Title, genAxis(i+1, col), fmt.Sprint(mapData[name]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +102,10 @@ func Excel2Slice(reader io.Reader) (contents map[string][][]string) {
|
||||
return contents
|
||||
}
|
||||
|
||||
func genAxis(row, col int) string {
|
||||
return fmt.Sprintf("%c%d", col+65, row+1)
|
||||
func genAxis(row, col int) (pos string) {
|
||||
pos, err := excelize.CoordinatesToCellName(col+1, row+1)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("err:%v", err)
|
||||
}
|
||||
return pos
|
||||
}
|
||||
|
||||
@@ -1,9 +1,47 @@
|
||||
package excel
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type XXXX struct {
|
||||
ID int64 `orm:"column(id)" json:"id"`
|
||||
VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"`
|
||||
VendorOrderID2 string `orm:"column(vendor_order_id2);size(48);index" json:"vendorOrderID2"`
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"`
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"` // 外部系统里记录的 jxstoreid
|
||||
JxStoreID int `orm:"column(jx_store_id)" json:"jxStoreID"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid
|
||||
StoreName string `orm:"size(64)" json:"storeName"`
|
||||
ShopPrice int64 `json:"shopPrice"` // 单位为分 门店标价
|
||||
SalePrice int64 `json:"salePrice"` // 单位为分 售卖价
|
||||
ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付
|
||||
Weight int `json:"weight"` // 单位为克
|
||||
ConsigneeName string `orm:"size(32)" json:"consigneeName"`
|
||||
ConsigneeMobile string `orm:"size(32)" json:"consigneeMobile"`
|
||||
ConsigneeMobile2 string `orm:"size(32)" json:"consigneeMobile2"`
|
||||
ConsigneeAddress string `orm:"size(255)" json:"consigneeAddress"`
|
||||
CoordinateType int `json:"-"`
|
||||
ConsigneeLng int `json:"-"` // 坐标 * (10的六次方)
|
||||
ConsigneeLat int `json:"-"` // 坐标 * (10的六次方)
|
||||
SkuCount int `json:"skuCount"` // 商品类别数量,即有多少种商品(注意在某些情况下,相同SKU的商品由于售价不同,也会当成不同商品在这个值里)
|
||||
GoodsCount int `json:"goodsCount"` // 商品个数
|
||||
Status int `json:"status"` // 参见OrderStatus*相关的常量定义
|
||||
VendorStatus string `orm:"size(255)" json:"vendorStatus"`
|
||||
LockStatus int `json:"lockStatus"`
|
||||
OrderSeq int `json:"orderSeq"` // 门店订单序号
|
||||
BuyerComment string `orm:"size(255)" json:"buyerComment"`
|
||||
BusinessType int `json:"businessType"`
|
||||
CancelApplyReason string `orm:"size(255)" json:"-"` // ""表示没有申请,不为null表示用户正在取消申请
|
||||
VendorWaybillID string `orm:"column(vendor_waybill_id);size(48)" json:"vendorWaybillID"`
|
||||
WaybillVendorID int `orm:"column(waybill_vendor_id)" json:"waybillVendorID"` // 表示当前承运商,-1表示还没有安排
|
||||
DeliveryFlag int8 `json:"deliveryFlag"` // 第1位为1表示禁止调度器调度三方配送
|
||||
DuplicatedCount int `json:"-"` // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的
|
||||
OriginalData string `orm:"-" json:"-"` // 只是用于传递数据
|
||||
Flag int8 `json:"flag"` //非运单调整相关的其它状态
|
||||
}
|
||||
|
||||
func TestObj2Excel(t *testing.T) {
|
||||
// kk := make([]*model.SkuName, 1)
|
||||
// kk[0] = &model.SkuName{
|
||||
@@ -24,3 +62,49 @@ func TestObj2Excel(t *testing.T) {
|
||||
}
|
||||
Obj2Excel([]*Obj2ExcelSheetConfig{cc})
|
||||
}
|
||||
|
||||
func BenchmarkObj2Excel(b *testing.B) {
|
||||
const sliceLen = 1000
|
||||
oneData := &XXXX{}
|
||||
cc := &Obj2ExcelSheetConfig{
|
||||
Title: "Title",
|
||||
CaptionList: nil,
|
||||
}
|
||||
elmType := reflect.TypeOf(oneData)
|
||||
if elmType.Kind() == reflect.Ptr {
|
||||
elmType = elmType.Elem()
|
||||
}
|
||||
for i := 0; i < elmType.NumField(); i++ {
|
||||
if jsonTag := elmType.Field(i).Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
|
||||
cc.CaptionList = append(cc.CaptionList, jsonTag)
|
||||
}
|
||||
}
|
||||
value := reflect.Indirect(reflect.ValueOf(oneData))
|
||||
for i := 0; i < elmType.NumField(); i++ {
|
||||
value2 := value.Field(i)
|
||||
if value2.Kind() == reflect.String {
|
||||
value2.SetString(elmType.Field(i).Name)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
data := make([]map[string]interface{}, sliceLen)
|
||||
for k := range data {
|
||||
data[k] = utils.Struct2MapByJson(oneData)
|
||||
}
|
||||
//*/
|
||||
|
||||
//*
|
||||
data := make([]*XXXX, 1000)
|
||||
for k := range data {
|
||||
copied := *oneData
|
||||
data[k] = &copied
|
||||
}
|
||||
//*/
|
||||
|
||||
cc.Data = data
|
||||
for i := 0; i < b.N; i++ {
|
||||
Obj2Excel([]*Obj2ExcelSheetConfig{cc})
|
||||
}
|
||||
// b.Log(utils.Format4Output(data, false))
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/auth"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
type IAuther interface {
|
||||
@@ -71,7 +70,7 @@ func New(notUsed interface{}, token string, w http.ResponseWriter, r *http.Reque
|
||||
}
|
||||
}
|
||||
if err == model.ErrTokenIsInvalid {
|
||||
if beego.BConfig.RunMode != "prod" {
|
||||
if !globals.IsProductEnv() {
|
||||
err = nil
|
||||
} else {
|
||||
errCode = model.ErrCodeTokenIsInvalid
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package jxutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -14,7 +17,9 @@ import (
|
||||
"git.rosy.net.cn/baseapi/utils/routinepool"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -27,6 +32,25 @@ type SyncMapWithTimeout struct {
|
||||
timers sync.Map
|
||||
}
|
||||
|
||||
type OrderSkuList []*model.OrderSku
|
||||
|
||||
func (l OrderSkuList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
// Less reports whether the element with
|
||||
// index i should sort before the element with index j.
|
||||
func (l OrderSkuList) Less(i, j int) bool {
|
||||
return l[i].SalePrice < l[j].SalePrice
|
||||
}
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (l OrderSkuList) Swap(i, j int) {
|
||||
tmp := l[i]
|
||||
l[i] = l[j]
|
||||
l[j] = tmp
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
routinePool = routinepool.New(1000, 1000)
|
||||
@@ -82,6 +106,13 @@ func GetSkuIDFromOrderSku(sku *model.OrderSku) (skuID int) {
|
||||
return sku.SkuID
|
||||
}
|
||||
|
||||
func GetSaleStoreIDFromAfsOrder(order *model.AfsOrder) (retVal int) {
|
||||
if order.JxStoreID > 0 {
|
||||
return order.JxStoreID
|
||||
}
|
||||
return order.StoreID
|
||||
}
|
||||
|
||||
func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID int) {
|
||||
index := strings.Index(universalOrderID, "|")
|
||||
if index != -1 {
|
||||
@@ -122,6 +153,19 @@ func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
|
||||
return vendorID
|
||||
}
|
||||
|
||||
func GetPossibleVendorIDFromAfsOrderID(afsOrderID string) (vendorID int) {
|
||||
vendorID = model.VendorIDUnknown
|
||||
if afsOrderIDInt64 := utils.Str2Int64WithDefault(afsOrderID, 0); afsOrderIDInt64 > 0 {
|
||||
orderIDLen := len(afsOrderID)
|
||||
if orderIDLen == len("22586438") {
|
||||
vendorID = model.VendorIDJD
|
||||
} else if orderIDLen == len("579557034") {
|
||||
vendorID = model.VendorIDEBAI
|
||||
}
|
||||
}
|
||||
return vendorID
|
||||
}
|
||||
|
||||
func ComposeUniversalOrderID(orderID string, vendorID int) string {
|
||||
// return fmt.Sprintf("%s|%d", orderID, vendorID)
|
||||
return orderID // 当前用长度就能区分,先不加上vendorID
|
||||
@@ -276,10 +320,7 @@ func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, sp
|
||||
skuName += "(" + comment + ")"
|
||||
}
|
||||
if maxLen > 0 {
|
||||
runeList := []rune(skuName)
|
||||
if len(runeList) > maxLen {
|
||||
skuName = string(runeList[:maxLen])
|
||||
}
|
||||
skuName = utils.LimitUTF8StringLen(skuName, maxLen)
|
||||
}
|
||||
return skuName
|
||||
}
|
||||
@@ -421,3 +462,122 @@ func HandleUserWXRemark(db *dao.DaoDB, mobile string) (err error) {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func RefreshOrderSkuRelated(order *model.GoodsOrder) *model.GoodsOrder {
|
||||
order.SkuCount = 0
|
||||
order.GoodsCount = 0
|
||||
order.SalePrice = 0
|
||||
order.VendorPrice = 0
|
||||
order.Weight = 0
|
||||
order.OrderCreatedAt = order.StatusTime
|
||||
for _, sku := range order.Skus {
|
||||
if sku.SkuID > math.MaxInt32 {
|
||||
sku.SkuID = 0
|
||||
}
|
||||
sku.OrderCreatedAt = order.OrderCreatedAt
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.VendorPrice += sku.VendorPrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
|
||||
afsOrder.SkuUserMoney = 0
|
||||
afsOrder.PmSkuSubsidyMoney = 0
|
||||
for _, orderSku := range afsOrder.Skus {
|
||||
if orderSku.SkuID > math.MaxInt32 {
|
||||
orderSku.SkuID = 0
|
||||
}
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
func RemoveSkuFromOrder(order *model.GoodsOrder, removedSkuList []*model.OrderSku) *model.GoodsOrder {
|
||||
removedSkuMap := make(map[int]*model.OrderSku)
|
||||
removedSkuMap2 := make(map[string]*model.OrderSku)
|
||||
for _, sku := range removedSkuList {
|
||||
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
|
||||
if removedSkuMap[skuID] == nil {
|
||||
removedSkuMap[skuID] = sku
|
||||
} else {
|
||||
removedSkuMap[skuID].Count += sku.Count
|
||||
}
|
||||
}
|
||||
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
|
||||
if removedSkuMap2[vendorSkuID] == nil {
|
||||
removedSkuMap2[vendorSkuID] = sku
|
||||
} else {
|
||||
removedSkuMap2[vendorSkuID].Count += sku.Count
|
||||
}
|
||||
}
|
||||
}
|
||||
var skuList []*model.OrderSku
|
||||
sort.Sort(sort.Reverse(OrderSkuList(order.Skus)))
|
||||
for _, sku := range order.Skus {
|
||||
var removedSku *model.OrderSku
|
||||
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
|
||||
removedSku = removedSkuMap[skuID]
|
||||
}
|
||||
if removedSku == nil {
|
||||
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
|
||||
removedSku = removedSkuMap2[vendorSkuID]
|
||||
}
|
||||
}
|
||||
copiedSku := *sku
|
||||
tmp := &copiedSku
|
||||
if removedSku != nil {
|
||||
if removedSku.Count >= sku.Count {
|
||||
tmp = nil
|
||||
removedSku.Count -= sku.Count
|
||||
} else {
|
||||
tmp.Count -= removedSku.Count
|
||||
removedSku.Count = 0
|
||||
}
|
||||
}
|
||||
if tmp != nil {
|
||||
skuList = append(skuList, tmp)
|
||||
}
|
||||
}
|
||||
order.Skus = skuList
|
||||
return RefreshOrderSkuRelated(order)
|
||||
}
|
||||
|
||||
func UploadExportContent(content []byte, key string) (downloadURL string, err error) {
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: 10 * 60,
|
||||
DeleteAfterDays: 1,
|
||||
}
|
||||
upToken := putPolicy.UploadToken(api.QiniuAPI)
|
||||
cfg := &storage.Config{}
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
ret := storage.PutRet{}
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, bytes.NewReader(content), int64(len(content)), &storage.PutExtra{}); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
downloadURL = ComposeQiniuResURL(key)
|
||||
}
|
||||
return downloadURL, err
|
||||
}
|
||||
|
||||
func TaskResult2Hint(resultList []interface{}) (hint string) {
|
||||
strList := make([]string, len(resultList))
|
||||
for k, v := range resultList {
|
||||
strList[k] = fmt.Sprint(v)
|
||||
}
|
||||
hint = strings.Join(strList, ",")
|
||||
return hint
|
||||
}
|
||||
|
||||
// 这个函数用于将两个整数合并为一单一int64,不要用于持久化的场景
|
||||
func Combine2Int(int1, int2 int) (outInt int64) {
|
||||
return int64(int1)*100000 + int64(int2)
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -82,9 +84,9 @@ func SplitStoreName(fullName, separator, defaultPrefix string) (prefix, bareName
|
||||
func ComposeStoreName(bareName string, vendorID int) (fullName string) {
|
||||
bareName = TrimDecorationChar(strings.Trim(bareName, "-"))
|
||||
if vendorID == model.VendorIDJD {
|
||||
fullName = "京西菜市-" + bareName
|
||||
fullName = globals.StoreName + "-" + bareName
|
||||
} else {
|
||||
fullName = "京西菜市(" + bareName + ")"
|
||||
fullName = globals.StoreName + "(" + bareName + ")"
|
||||
}
|
||||
return fullName
|
||||
}
|
||||
@@ -152,19 +154,24 @@ func Int64Map2List(int64Map map[int64]int) []int64 {
|
||||
return retVal
|
||||
}
|
||||
|
||||
// 计算SKU价格,unitPrice为一斤的单价,specQuality为质量,单位为克
|
||||
func CaculateSkuPrice(unitPrice int, specQuality float32, specUnit string, skuNameUnit string) int {
|
||||
if skuNameUnit != "份" {
|
||||
return unitPrice
|
||||
}
|
||||
func RegularizeSkuQuality(specQuality float32, specUnit string) (g int) {
|
||||
lowerSpecUnit := strings.ToLower(specUnit)
|
||||
if lowerSpecUnit == "kg" || lowerSpecUnit == "l" {
|
||||
specQuality *= 1000
|
||||
}
|
||||
price := int(math.Round(float64(float32(unitPrice) * specQuality / 500)))
|
||||
if specQuality < 250 {
|
||||
return int(specQuality)
|
||||
}
|
||||
|
||||
// 计算SKU价格,unitPrice为一斤的单价,specQuality为质量,单位为克
|
||||
func CaculateSkuPrice(unitPrice int, specQuality float32, specUnit string, skuNameUnit string) int {
|
||||
if skuNameUnit != model.SpecialUnit {
|
||||
return unitPrice
|
||||
}
|
||||
specQuality2 := RegularizeSkuQuality(specQuality, specUnit)
|
||||
price := int(math.Round(float64(unitPrice * specQuality2 / model.SpecialSpecQuality)))
|
||||
if specQuality2 < 250 {
|
||||
price = price * 110 / 100
|
||||
} else if specQuality < 500 {
|
||||
} else if specQuality2 < 500 {
|
||||
price = price * 105 / 100
|
||||
}
|
||||
if price <= 0 {
|
||||
@@ -173,35 +180,100 @@ func CaculateSkuPrice(unitPrice int, specQuality float32, specUnit string, skuNa
|
||||
return price
|
||||
}
|
||||
|
||||
// 计算SKU标准价格,CaculateSkuPrice的逆过程
|
||||
func CaculateUnitPrice(skuPrice int, specQuality float32, specUnit string, skuNameUnit string) (unitPrice int) {
|
||||
if skuNameUnit != model.SpecialUnit {
|
||||
return skuPrice
|
||||
}
|
||||
specQuality2 := RegularizeSkuQuality(specQuality, specUnit)
|
||||
unitPrice = skuPrice * model.SpecialSpecQuality / specQuality2
|
||||
if specQuality2 < 250 {
|
||||
unitPrice = unitPrice * 100 / 110
|
||||
} else if specQuality2 < 500 {
|
||||
unitPrice = unitPrice * 100 / 105
|
||||
}
|
||||
if unitPrice <= 0 {
|
||||
unitPrice = 1
|
||||
}
|
||||
return unitPrice
|
||||
}
|
||||
|
||||
func GetSliceLen(list interface{}) int {
|
||||
return reflect.ValueOf(list).Len()
|
||||
}
|
||||
|
||||
func CaculateSkuVendorPrice(price int, percentage int) int {
|
||||
storePrice := int(math.Round(float64(price*percentage) / 100))
|
||||
if storePrice < 0 {
|
||||
storePrice = 0
|
||||
func CaculateSkuVendorPrice(price, percentage, catPercentage int) int {
|
||||
if percentage <= 10 || percentage >= 400 {
|
||||
percentage = 100
|
||||
}
|
||||
return storePrice
|
||||
if catPercentage <= 10 || catPercentage >= 400 {
|
||||
catPercentage = 100
|
||||
}
|
||||
percentage = percentage * catPercentage / 100
|
||||
vendorPrice := int(math.Round(float64(price*percentage) / 100))
|
||||
if vendorPrice < 0 {
|
||||
vendorPrice = 0
|
||||
}
|
||||
return vendorPrice
|
||||
}
|
||||
|
||||
func CaculateSkuPriceFromVendor(vendorPrice, percentage, catPercentage int) int {
|
||||
if percentage <= 10 || percentage >= 400 {
|
||||
percentage = 100
|
||||
}
|
||||
if catPercentage <= 10 || catPercentage >= 400 {
|
||||
catPercentage = 100
|
||||
}
|
||||
percentage = percentage * catPercentage / 100
|
||||
price := int(math.Round(float64(vendorPrice * 100 / percentage)))
|
||||
if price < 0 {
|
||||
price = 0
|
||||
}
|
||||
return price
|
||||
}
|
||||
|
||||
func IsSkuSpecial(specQuality float32, specUnit string) bool {
|
||||
return int(specQuality) == model.SpecialSpecQuality && (specUnit == model.SpecialSpecUnit || specUnit == model.SpecialSpecUnit2)
|
||||
}
|
||||
|
||||
var lastFakeID int64
|
||||
var lastFakeIDMutex sync.RWMutex
|
||||
|
||||
// 生成一个不重复的临时ID
|
||||
func genFakeID1() int64 {
|
||||
return time.Now().UnixNano() / 1000000
|
||||
for {
|
||||
fakeID := time.Now().UnixNano() / 1000
|
||||
lastFakeIDMutex.RLock()
|
||||
if fakeID == lastFakeID {
|
||||
lastFakeIDMutex.RUnlock()
|
||||
time.Sleep(1 * time.Microsecond)
|
||||
} else {
|
||||
lastFakeIDMutex.RUnlock()
|
||||
lastFakeIDMutex.Lock()
|
||||
defer lastFakeIDMutex.Unlock()
|
||||
lastFakeID = fakeID
|
||||
return fakeID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 这个用于没有打开远程同步时的假同步,生成ID使用
|
||||
func GenFakeID() int64 {
|
||||
return genFakeID1() * 3
|
||||
}
|
||||
|
||||
func IsFakeID(id int64) bool {
|
||||
if id == 0 {
|
||||
if IsEmptyID(id) {
|
||||
return true
|
||||
}
|
||||
multiple := id / genFakeID1()
|
||||
return multiple >= 2 && multiple <= 4
|
||||
}
|
||||
|
||||
func IsEmptyID(id int64) bool {
|
||||
return id == 0
|
||||
}
|
||||
|
||||
func FormalizePageSize(pageSize int) int {
|
||||
if pageSize == 0 {
|
||||
return model.DefPageSize
|
||||
@@ -238,11 +310,7 @@ func IsLegalStoreID(id int) bool {
|
||||
|
||||
// 将规格转为重量
|
||||
func FormatSkuWeight(specQuality float32, specUnit string) int {
|
||||
lowerSpecUnit := strings.ToLower(specUnit)
|
||||
if lowerSpecUnit == "kg" || lowerSpecUnit == "l" {
|
||||
specQuality *= 1000
|
||||
}
|
||||
return int(specQuality)
|
||||
return RegularizeSkuQuality(specQuality, specUnit)
|
||||
}
|
||||
|
||||
type SkuList []*model.Sku
|
||||
@@ -284,7 +352,7 @@ func DownloadFileByURL(fileURL string) (bodyData []byte, fileMD5 string, err err
|
||||
|
||||
/////
|
||||
func GenPicFileName(suffix string) string {
|
||||
return fmt.Sprintf("%x%s", md5.Sum([]byte(utils.GetUUID()+suffix)), suffix)
|
||||
return fmt.Sprintf("image/%x%s", md5.Sum([]byte(utils.GetUUID()+suffix)), suffix)
|
||||
}
|
||||
|
||||
func GuessVendorIDFromVendorStoreID(vendorStoreID int64) (vendorID int) {
|
||||
@@ -293,7 +361,7 @@ func GuessVendorIDFromVendorStoreID(vendorStoreID int64) (vendorID int) {
|
||||
vendorID = model.VendorIDJD
|
||||
} else if vendorStoreID > 1234567 && vendorStoreID < 9876543 { // 美团外卖 2461713,7位
|
||||
vendorID = model.VendorIDMTWM
|
||||
} else if vendorStoreID > 1234567890 && vendorStoreID < 9987654321 { // 饿百 2167002607,10位
|
||||
} else if vendorStoreID > 1234567890 && vendorStoreID < 99876543210 { // 饿百 2167002607,10位,11位
|
||||
vendorID = model.VendorIDEBAI
|
||||
} else if vendorStoreID > 123456789 && vendorStoreID < 987654321 { // 微盟微商城 132091048,9位
|
||||
vendorID = model.VendorIDWSC
|
||||
@@ -306,10 +374,3 @@ func GuessVendorIDFromVendorStoreID(vendorStoreID int64) (vendorID int) {
|
||||
func GetVendorName(vendorID int) (vendorName string) {
|
||||
return model.VendorChineseNames[vendorID]
|
||||
}
|
||||
|
||||
func AddVendorInfo2Err(inErr error, vendorID int) (outErr error) {
|
||||
if inErr != nil {
|
||||
outErr = fmt.Errorf("处理平台%s, %s", model.VendorChineseNames[vendorID], inErr.Error())
|
||||
}
|
||||
return outErr
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ func SendUserMessage(userID, title, content string) (err error) {
|
||||
if len(content) > dingdingapi.MaxWorkContentLen {
|
||||
content = content[:dingdingapi.MaxWorkContentLen-4] + "..."
|
||||
}
|
||||
err = api.DingDingAPI.CorpAsyncSendSimple(auth.AuthID, content)
|
||||
if globals.IsProductEnv() {
|
||||
err = api.DingDingAPI.CorpAsyncSendSimple(auth.AuthID, content)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
const (
|
||||
testVendorOrderID = "test"
|
||||
realTestVendorOrderID = "817102016000041"
|
||||
realTestVendorOrderID = "901234567890123"
|
||||
realTestOrderVendorID = model.VendorIDJD
|
||||
)
|
||||
|
||||
@@ -27,14 +27,6 @@ func PrintOrder(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (pri
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
if vendorOrderID == realTestVendorOrderID {
|
||||
order.BuyerComment = "用户备注"
|
||||
order.ConsigneeAddress = "四川省成都市某个地方"
|
||||
order.ConsigneeLat = 30695171
|
||||
order.ConsigneeLng = 104056984
|
||||
order.ConsigneeName = "用户姓名"
|
||||
order.ConsigneeMobile = "13812345678"
|
||||
order.ConsigneeMobile2 = "13812345678"
|
||||
order.StoreName = "京西菜市-测试门店"
|
||||
order.StoreID = storeID
|
||||
order.JxStoreID = storeID
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ func RefreshConfig(configKey string, expiresTime time.Duration, configGetter fun
|
||||
}
|
||||
if handleType != 0 {
|
||||
if curConfig.Token, curConfig.Date = configGetter(); curConfig.Token == "" {
|
||||
if beego.BConfig.RunMode == "prod" {
|
||||
if globals.IsProductEnv() {
|
||||
globals.SugarLogger.Errorf("RefreshConfig %s get empty token", configKey)
|
||||
sleepDuration = errRefreshGap
|
||||
} else {
|
||||
@@ -126,7 +126,7 @@ func RefreshWeixinToken() (err error) {
|
||||
if api.WeixinAPI != nil {
|
||||
err = RefreshConfig("wechat", weixinTokenExpires, func() (token string, expireTimeStr string) {
|
||||
globals.SugarLogger.Debugf("RefreshWeixinToken RunMode:%s", beego.BConfig.RunMode)
|
||||
if globals.IsProductEnv() {
|
||||
if globals.IsProductEnv() || beego.BConfig.RunMode == "alpha" {
|
||||
if globals.IsMainProductEnv() {
|
||||
if tokenInfo, err := api.WeixinAPI.CBRetrieveToken(); err == nil {
|
||||
globals.SugarLogger.Debugf("RefreshWeixinToken tokenInfo:%s", utils.Format4Output(tokenInfo, true))
|
||||
@@ -154,7 +154,7 @@ func RefreshWeixinToken() (err error) {
|
||||
func RefreshElmToken() (err error) {
|
||||
if api.ElmAPI != nil {
|
||||
err = RefreshConfig("eleme", elmTokenExpires, func() (string, string) {
|
||||
if beego.BConfig.RunMode == "prod" {
|
||||
if globals.IsProductEnv() {
|
||||
if tokenInfo, err := api.ElmAPI.RefreshTokenIndividual(); err == nil {
|
||||
tokenInfo2 := &ElmTokenForCompatible{
|
||||
Error: "",
|
||||
@@ -183,7 +183,7 @@ func RefreshElmToken() (err error) {
|
||||
func RefreshWeimobToken() (err error) {
|
||||
if api.WeimobAPI != nil {
|
||||
err = RefreshConfig("weimob", weimobTokenExpires, func() (string, string) {
|
||||
if beego.BConfig.RunMode == "prod" {
|
||||
if globals.IsProductEnv() {
|
||||
if tokenInfo, err := api.WeimobAPI.RefreshTokenByRefreshToken(); err == nil {
|
||||
return string(utils.MustMarshal(tokenInfo)), utils.Time2Str(time.Now().Add((time.Duration(tokenInfo.ExpiresIn) - weimobTokenExpires/time.Second) * time.Second))
|
||||
}
|
||||
@@ -204,7 +204,7 @@ func RefreshDingDingToken() (err error) {
|
||||
api.DingDingAPI.RetrieveToken()
|
||||
return RefreshConfig("dingding", dingdingTokenExpires, func() (string, string) {
|
||||
globals.SugarLogger.Debugf("RefreshDingDingToken RunMode:%s", beego.BConfig.RunMode)
|
||||
if true { //beego.BConfig.RunMode == "prod" {
|
||||
if true { //globals.IsProductEnv() {
|
||||
if token, err := api.DingDingAPI.RetrieveToken(); err == nil {
|
||||
globals.SugarLogger.Debugf("RefreshDingDingToken tokenInfo:%s", token)
|
||||
return token, ""
|
||||
@@ -232,12 +232,15 @@ func SaveWeimobToken(token *weimobapi.TokenInfo) (err error) {
|
||||
func RefreshYilianyunToken() (err error) {
|
||||
return RefreshConfig("yilianyun", yilianyunTokenExpires, func() (string, string) {
|
||||
globals.SugarLogger.Debugf("RefreshYilianyunToken RunMode:%s", beego.BConfig.RunMode)
|
||||
if beego.BConfig.RunMode == "prod" {
|
||||
if tokenInfo, err := api.YilianyunAPI.RetrieveToken(); err == nil {
|
||||
return string(utils.MustMarshal(tokenInfo)), ""
|
||||
} else {
|
||||
globals.SugarLogger.Errorf("RefreshYilianyunToken RefreshToken failed with error:%v", err)
|
||||
if globals.IsProductEnv() {
|
||||
if globals.IsMainProductEnv() { // 只有京西菜市刷新易联云key
|
||||
if tokenInfo, err := api.YilianyunAPI.RetrieveToken(); err == nil {
|
||||
return string(utils.MustMarshal(tokenInfo)), ""
|
||||
} else {
|
||||
globals.SugarLogger.Errorf("RefreshYilianyunToken RefreshToken failed with error:%v", err)
|
||||
}
|
||||
}
|
||||
return api.YilianyunAPI.GetToken(), ""
|
||||
}
|
||||
return "", ""
|
||||
}, func(value string) {
|
||||
|
||||
@@ -134,13 +134,13 @@ func (task *ParallelTask) Run() {
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("ParallelTask.Run %s, subtask(job:%s, params:%s) result:%v, failed with error:%v", task.Name, utils.Format4Output(job, true), utils.Format4Output(task.params, true), result, err)
|
||||
task.locker.Lock()
|
||||
task.detailErrList = append(task.detailErrList, err)
|
||||
task.locker.Unlock()
|
||||
if !task.IsContinueWhenError { // 出错
|
||||
chanRetVal = err
|
||||
goto end
|
||||
}
|
||||
task.locker.Lock()
|
||||
task.detailErrMsgList = append(task.detailErrMsgList, err.Error())
|
||||
task.locker.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,12 +188,17 @@ func (task *ParallelTask) Run() {
|
||||
}
|
||||
}
|
||||
if taskErr != nil {
|
||||
task.OriginalErr = taskErr
|
||||
task.Err = NewTaskError(task.Name, taskErr)
|
||||
} else {
|
||||
if len(task.detailErrList) > 0 {
|
||||
task.OriginalErr = task.detailErrList[0]
|
||||
}
|
||||
task.Err = task.buildTaskErrFromDetail()
|
||||
}
|
||||
task.Result = taskResult
|
||||
task.TerminatedAt = time.Now()
|
||||
task.jobList = nil // 如果不释放,任务被管理的话,会导致内存不能释放
|
||||
task.locker.Unlock()
|
||||
globals.SugarLogger.Debugf("ParallelTask.Run %s, err:%v", task.Name, task.Err)
|
||||
close(task.subFinishChan)
|
||||
|
||||
@@ -44,13 +44,13 @@ func (task *SeqTask) Run() {
|
||||
})
|
||||
task.finishedOneJob(1, err)
|
||||
if taskErr = err; taskErr != nil {
|
||||
task.locker.Lock()
|
||||
task.detailErrList = append(task.detailErrList, err)
|
||||
task.locker.Unlock()
|
||||
globals.SugarLogger.Infof("SeqTask.Run %s step:%d failed with error:%v", task.Name, i, err)
|
||||
if !task.IsContinueWhenError {
|
||||
break
|
||||
}
|
||||
task.locker.Lock()
|
||||
task.detailErrMsgList = append(task.detailErrMsgList, err.Error())
|
||||
task.locker.Unlock()
|
||||
} else if result != nil {
|
||||
taskResult = append(taskResult, utils.Interface2Slice(result)...)
|
||||
}
|
||||
@@ -68,8 +68,12 @@ func (task *SeqTask) Run() {
|
||||
}
|
||||
}
|
||||
if taskErr != nil {
|
||||
task.OriginalErr = taskErr
|
||||
task.Err = NewTaskError(task.Name, taskErr)
|
||||
} else {
|
||||
if len(task.detailErrList) > 0 {
|
||||
task.OriginalErr = task.detailErrList[0]
|
||||
}
|
||||
task.Err = task.buildTaskErrFromDetail()
|
||||
}
|
||||
task.Result = taskResult
|
||||
|
||||
@@ -57,6 +57,8 @@ type ITask interface {
|
||||
AddChild(task ITask) ITask
|
||||
GetChildren() TaskList
|
||||
SetParent(parentTask ITask)
|
||||
GetOriginalErr() error
|
||||
GetDetailErrList() []error
|
||||
|
||||
json.Marshaler
|
||||
}
|
||||
@@ -103,15 +105,19 @@ type BaseTask struct {
|
||||
FailedJobCount int `json:"failedJobCount"`
|
||||
Status int `json:"status"`
|
||||
|
||||
Result []interface{} `json:"-"`
|
||||
Children TaskList `json:"children"`
|
||||
Err error `json:"err"`
|
||||
NoticeMsg string `json:"noticeMsg"`
|
||||
|
||||
detailErrMsgList []string
|
||||
finishChan chan struct{}
|
||||
C <-chan struct{} `json:"-"`
|
||||
params []interface{}
|
||||
quitChan chan int
|
||||
Result []interface{} `json:"-"`
|
||||
Children TaskList `json:"children"`
|
||||
Err error `json:"err"`
|
||||
OriginalErr error `json:"-"`
|
||||
|
||||
detailErrList []error
|
||||
|
||||
finishChan chan struct{}
|
||||
C <-chan struct{} `json:"-"`
|
||||
params []interface{}
|
||||
quitChan chan int
|
||||
|
||||
locker sync.RWMutex
|
||||
parent ITask
|
||||
@@ -161,7 +167,7 @@ func (t *BaseTask) GetID() string {
|
||||
|
||||
func (t *BaseTask) GetResult(duration time.Duration) (retVal []interface{}, err error) {
|
||||
if t.GetStatus() >= TaskStatusEndBegin {
|
||||
return t.Result, t.Err
|
||||
return t.Result, t.OriginalErr
|
||||
}
|
||||
if duration == 0 {
|
||||
duration = time.Hour * 10000 // duration为0表示无限等待
|
||||
@@ -171,7 +177,7 @@ func (t *BaseTask) GetResult(duration time.Duration) (retVal []interface{}, err
|
||||
case <-t.finishChan:
|
||||
t.isGetResultCalled = true
|
||||
timer.Stop()
|
||||
return t.Result, t.Err
|
||||
return t.Result, t.OriginalErr
|
||||
case <-timer.C:
|
||||
}
|
||||
return nil, ErrTaskNotFinished
|
||||
@@ -257,6 +263,30 @@ func (t *BaseTask) SetParent(parentTask ITask) {
|
||||
t.parent = parentTask
|
||||
}
|
||||
|
||||
func (t *BaseTask) SetNoticeMsg(noticeMsg string) {
|
||||
t.locker.Lock()
|
||||
defer t.locker.Unlock()
|
||||
t.NoticeMsg = noticeMsg
|
||||
}
|
||||
|
||||
func (t *BaseTask) GetNoticeMsg() string {
|
||||
t.locker.RLock()
|
||||
defer t.locker.RUnlock()
|
||||
return t.NoticeMsg
|
||||
}
|
||||
|
||||
func (t *BaseTask) GetOriginalErr() error {
|
||||
t.locker.RLock()
|
||||
defer t.locker.RUnlock()
|
||||
return t.OriginalErr
|
||||
}
|
||||
|
||||
func (t *BaseTask) GetDetailErrList() []error {
|
||||
t.locker.RLock()
|
||||
defer t.locker.RUnlock()
|
||||
return t.detailErrList
|
||||
}
|
||||
|
||||
func AddChild(parentTask ITask, task ITask) ITask {
|
||||
if parentTask != nil {
|
||||
return parentTask.AddChild(task)
|
||||
@@ -311,6 +341,10 @@ func (t *BaseTask) run(taskHandler func()) {
|
||||
taskDesc := fmt.Sprintf("你的异步任务[%s],ID[%s],开始于:%s,结束于:%s,", t.Name, t.ID, utils.Time2Str(t.CreatedAt), utils.Time2Str(t.TerminatedAt))
|
||||
if t.Err == nil {
|
||||
content = fmt.Sprintf("%s执行%s", taskDesc, TaskStatusName[t.Status])
|
||||
noticeMsg := t.GetNoticeMsg()
|
||||
if noticeMsg != "" {
|
||||
content += ",通知消息:" + noticeMsg
|
||||
}
|
||||
} else {
|
||||
if t.Status == TaskStatusFinished {
|
||||
content = fmt.Sprintf("%s执行部分失败,%s", taskDesc, t.Err.Error())
|
||||
@@ -347,8 +381,12 @@ func (t *BaseTask) setStatus(status int) {
|
||||
}
|
||||
|
||||
func (t *BaseTask) buildTaskErrFromDetail() (err error) {
|
||||
if len(t.detailErrMsgList) > 0 {
|
||||
return NewTaskError(t.Name, fmt.Errorf("总共:%d, 失败:%d, 详情:\n%s", t.TotalItemCount, t.FailedItemCount, strings.Join(t.detailErrMsgList, "\n")))
|
||||
if len(t.detailErrList) > 0 {
|
||||
strList := make([]string, len(t.detailErrList))
|
||||
for k, v := range t.detailErrList {
|
||||
strList[k] = v.Error()
|
||||
}
|
||||
return NewTaskError(t.Name, fmt.Errorf("总共:%d, 失败:%d, 详情:\n%s", t.TotalItemCount, t.FailedItemCount, strings.Join(strList, "\n")))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
@@ -49,7 +51,10 @@ const (
|
||||
WX_NORMAL_STORE_MSG_TEMPLATE_ID = "7ngcTFYiUFw66BMzIYntM1tpy-xZkJwlcCT5pVtXwtw"
|
||||
WX_CHANGE_APPROVED_TEMPLATE_ID = "gIG2olBZtQbjXmp6doNB_dESu60By5xuXYOGxksLv3Y"
|
||||
WX_CHANGE_REJECTED_TEMPLATE_ID = "tn2QXWi4HtSIwaztmtN6Bb2uzNL-jBxWltCZTDNJuYE"
|
||||
WS_ORDER_CANCLED_TEMPLATE_ID = "iFozwiCsQdMs7VTiPXoBne45jKIQkoyxdGHSeAExP9U"
|
||||
WX_ORDER_CANCLED_TEMPLATE_ID = "iFozwiCsQdMs7VTiPXoBne45jKIQkoyxdGHSeAExP9U"
|
||||
|
||||
WX_AFS_ORDER_WAIT4APPROVE_TEMPLATE_ID = "X29udtANvhX6x1Lyh-T40NGNjRXBbUj5oSBTfDhZAqU"
|
||||
WX_AFS_ORDER_STATUS_CHANGED_TEMPLATE_ID = "99T33rrXX0VboO1hljs4x8dDoLiSj3QX_rOikPHIXkg"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -305,7 +310,7 @@ func NotifyUserApplyCancel(order *model.GoodsOrder, cancelReason string) (err er
|
||||
},
|
||||
}
|
||||
storeID := jxutils.GetSaleStoreIDFromOrder(order)
|
||||
return SendMsgToStore(storeID, WS_ORDER_CANCLED_TEMPLATE_ID, "", "", data)
|
||||
return SendMsgToStore(storeID, WX_ORDER_CANCLED_TEMPLATE_ID, "", "", data)
|
||||
|
||||
}
|
||||
|
||||
@@ -347,7 +352,7 @@ func NotifySaleBill(storeID int, title, shopName, fileURL string) (err error) {
|
||||
title = "当期账单"
|
||||
}
|
||||
if shopName == "" {
|
||||
shopName = "京西菜市"
|
||||
shopName = globals.StoreName
|
||||
}
|
||||
data := map[string]interface{}{
|
||||
"first": map[string]interface{}{
|
||||
@@ -449,6 +454,54 @@ func NotifyStoreMessage(storeID, msgID, msgStatusID int, title, content string)
|
||||
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
|
||||
}
|
||||
|
||||
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": 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.CreatedAt),
|
||||
"color": venderColors[order.VendorID],
|
||||
},
|
||||
"remark": map[string]interface{}{
|
||||
"value": comment,
|
||||
"color": WX_NEW_ORDER_TEMPLATE_COLOR,
|
||||
},
|
||||
}
|
||||
storeID := jxutils.GetSaleStoreIDFromAfsOrder(afsOrder)
|
||||
err = SendMsgToStore(storeID, templateID, globals.WxBackstageHost+fmt.Sprintf("%s%d", WX_TO_ORDER_PAGE_URL, storeID), WX_MINI_TO_ORDER_PAGE_URL, data)
|
||||
return err
|
||||
}
|
||||
|
||||
func FormatDeliveryTime(order *model.GoodsOrder) string {
|
||||
var tmpTime time.Time
|
||||
if order.ExpectedDeliveredTime == utils.DefaultTimeValue {
|
||||
|
||||
135
business/model/act.go
Normal file
135
business/model/act.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
ActSkuDirectDown = 1
|
||||
ActSkuSecKill = 2
|
||||
|
||||
ActOrderBegin = 10
|
||||
ActOrderMoneyOff = 11
|
||||
ActOrderMoneyOffCoupon = 12
|
||||
ActOrderReduceFreight = 13
|
||||
ActOrderReduceFreightCoupon = 14
|
||||
)
|
||||
|
||||
const (
|
||||
ActStatusCreated = 1 // 需同步
|
||||
ActStatusCanceled = 2 // 需同步
|
||||
ActStatusEnded = 3 // 不需要同步,根据活动时间自动刷新的
|
||||
)
|
||||
|
||||
type Act struct {
|
||||
ModelIDCULD
|
||||
|
||||
Name string `orm:"size(64)" json:"name"`
|
||||
Advertising string `orm:"size(255)" json:"advertising"`
|
||||
Type int `json:"type"`
|
||||
Status int `json:"status"`
|
||||
LimitDevice int `json:"limitDevice"`
|
||||
LimitPin int `json:"limitPin"`
|
||||
LimitDaily int `json:"limitDaily"`
|
||||
LimitCount int `json:"limitCount"`
|
||||
Source string `orm:"size(255)" json:"source"`
|
||||
CreateType int `json:"createType"`
|
||||
PricePercentage int `json:"pricePercentage"` // 单品级活动才有效
|
||||
BeginAt time.Time `orm:"type(datetime);index;null" json:"beginAt"`
|
||||
EndAt time.Time `orm:"type(datetime);index;null" json:"endAt"`
|
||||
}
|
||||
|
||||
type ActMap struct {
|
||||
ModelIDCULD
|
||||
|
||||
ActID int `orm:"column(act_id)" json:"actID"`
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
|
||||
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
|
||||
SyncStatus int `orm:"default(2)" json:"syncStatus"`
|
||||
}
|
||||
|
||||
type Act2 struct {
|
||||
MapID int `orm:"column(map_id)"`
|
||||
|
||||
Act
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
|
||||
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
|
||||
SyncStatus int `orm:"default(2)" json:"syncStatus"`
|
||||
}
|
||||
|
||||
type ActOrderRule struct {
|
||||
ModelIDCULD
|
||||
|
||||
ActID int `orm:"column(act_id)" json:"actID"`
|
||||
SalePrice int64 `orm:"" json:"salePrice"` // 满的价格
|
||||
DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格
|
||||
}
|
||||
|
||||
// type ActStore struct {
|
||||
// ModelIDCULD
|
||||
|
||||
// ActID int `orm:"column(act_id)" json:"actID"`
|
||||
// StoreID int `orm:"column(store_id)" json:"storeID"`
|
||||
// }
|
||||
|
||||
type ActStoreMap struct {
|
||||
ModelIDCULD
|
||||
|
||||
ActID int `orm:"column(act_id)" json:"actID"`
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"`
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
|
||||
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
|
||||
SyncStatus int `orm:"default(2)" json:"syncStatus"`
|
||||
}
|
||||
|
||||
type ActStore2 struct {
|
||||
MapID int `orm:"column(map_id)"`
|
||||
|
||||
ActStoreMap
|
||||
|
||||
VendorStoreID string `orm:"column(vendor_store_id)" json:"vendorStoreID"`
|
||||
}
|
||||
|
||||
type ActStoreSku struct {
|
||||
ModelIDCULD
|
||||
|
||||
ActID int `orm:"column(act_id)" json:"actID"`
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"`
|
||||
SkuID int `orm:"column(sku_id)" json:"skuID"`
|
||||
|
||||
// LocalStatus int // 这个状态是多个平台的
|
||||
// RemoteStatus int // 这个状态是多个平台的
|
||||
OriginalPrice int64 `orm:"" json:"originalPrice"` // 单品级活动用,创建活动时商品的原始京西价
|
||||
PricePercentage int `orm:"" json:"pricePercentage"` // 单品级活动用,SKU级的价格比例,非0覆盖Act中的PricePercentage
|
||||
ActPrice int64 `orm:"" json:"actPrice"` // 单品级活动用,SKU级指定的价格,非0覆盖CustomPricePercentage与Act中的PricePercentage
|
||||
|
||||
Stock int `orm:"" json:"stock"` // 订单级活动用
|
||||
}
|
||||
|
||||
type ActStoreSkuMap struct {
|
||||
ModelIDCULD
|
||||
|
||||
ActID int `orm:"column(act_id)" json:"actID"`
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"`
|
||||
SkuID int `orm:"column(sku_id)" json:"skuID"`
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
|
||||
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
|
||||
SyncStatus int `orm:"default(2)" json:"syncStatus"`
|
||||
ActualActPrice int64 `orm:"" json:"actualActPrice"` // 单品级活动用,创建活动时商品的活动价格
|
||||
}
|
||||
|
||||
type ActStoreSku2 struct {
|
||||
MapID int `orm:"column(map_id)"`
|
||||
|
||||
ActStoreSku
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
|
||||
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
|
||||
SyncStatus int `orm:"default(2)" json:"syncStatus"`
|
||||
ActualActPrice int64 `orm:"" json:"actualActPrice"` // 单品级活动用,创建活动时商品的活动价格
|
||||
|
||||
VendorStoreID string `orm:"column(vendor_store_id)" json:"vendorStoreID"`
|
||||
VendorSkuID string `orm:"column(vendor_sku_id)" json:"vendorSkuID"`
|
||||
}
|
||||
@@ -12,15 +12,25 @@ const (
|
||||
|
||||
type GoodsOrderExt struct {
|
||||
GoodsOrder
|
||||
EarningPrice int64 `json:"earningPrice"` // 预估结算给门店老板的钱
|
||||
|
||||
WaybillStatus int `json:"waybillStatus"`
|
||||
CourierName string `orm:"size(32)" json:"courierName"`
|
||||
CourierMobile string `orm:"size(32)" json:"courierMobile"`
|
||||
CurrentConsigneeMobile string `orm:"-" json:"currentConsigneeMobile"`
|
||||
CourierVendorName string `json:"courierVendorName"`
|
||||
|
||||
Status2 string `json:"status2"`
|
||||
ActualFee int64 `json:"actualFee"` // 实际要支付给快递公司的费用
|
||||
DesiredFee int64 `json:"desiredFee"` // 运单总费用
|
||||
WaybillCreatedAt time.Time `orm:"type(datetime);index" json:"waybillCreatedAt"`
|
||||
WaybillFinishedAt time.Time `orm:"type(datetime)" json:"waybillFinishedAt"`
|
||||
|
||||
SkuID int `orm:"column(sku_id)" json:"skuID,omitempty"`
|
||||
SkuShopPrice int `json:"skuShopPrice,omitempty"`
|
||||
SkuSalePrice int `json:"skuSalePrice,omitempty"`
|
||||
SkuCount2 int `json:"skuCount2,omitempty"`
|
||||
SkuInfo string `json:"skuInfo,omitempty"`
|
||||
}
|
||||
|
||||
type OrderSkuExt struct {
|
||||
@@ -30,11 +40,6 @@ type OrderSkuExt struct {
|
||||
}
|
||||
|
||||
type GoodsOrderCountInfo struct {
|
||||
Status int `json:"status"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type GoodsOrderCountInfo2 struct {
|
||||
LockStatus int `json:"lockStatus"`
|
||||
Status int `json:"status"`
|
||||
Count int `json:"count"`
|
||||
@@ -61,3 +66,8 @@ type OrderFinancialExt struct {
|
||||
Skus []*OrderSkuFinancial `orm:"-" json:"skus"` // 正向订单购买商品列表
|
||||
Discounts []*OrderDiscountFinancial `orm:"-" json:"discounts"` // 正向订单享受优惠列表
|
||||
}
|
||||
|
||||
type OrderFinancialSkuExt struct {
|
||||
OrderSkuFinancial
|
||||
Image string `json:"image"`
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ const (
|
||||
VendorIDMTWM = 1
|
||||
VendorIDELM = 2
|
||||
VendorIDEBAI = 3
|
||||
VendorIDJX = 9 // 这是一个假的京西VendorID
|
||||
VendorIDWSC = 11 // 微盟微商城
|
||||
VendorIDPurchaseEnd = 11
|
||||
VendorIDJX = 99 // 这是一个假的京西VendorID
|
||||
|
||||
VendorIDDeliveryBegin = 101
|
||||
VendorIDDada = 101
|
||||
@@ -112,22 +112,34 @@ var (
|
||||
OrderStatusDeliverFailed: "投递失败",
|
||||
OrderStatusFinished: "完成",
|
||||
OrderStatusCanceled: "取消",
|
||||
|
||||
AfsOrderStatusWait4Approve: "待审核",
|
||||
AfsOrderStatusNew: "已审核",
|
||||
AfsOrderStatusWait4ReceiveGoods: "退货待确认",
|
||||
AfsOrderStatusReceivedGoods: "退货已收到",
|
||||
AfsOrderStatusFinished: "售后成功",
|
||||
AfsOrderStatusFailed: "售后失败",
|
||||
}
|
||||
WaybillStatusName = map[int]string{
|
||||
WaybillStatusUnknown: "一般事件",
|
||||
|
||||
WaybillStatusNew: "新运单",
|
||||
WaybillStatusAcceptCanceled: "取消接受",
|
||||
WaybillStatusAccepted: "已接单",
|
||||
WaybillStatusCourierArrived: "已到店",
|
||||
WaybillStatusDelivering: "配送中",
|
||||
WaybillStatusDelivered: "送达",
|
||||
WaybillStatusCanceled: "取消",
|
||||
WaybillStatusFailed: "失败",
|
||||
WaybillStatusNew: "新运单",
|
||||
WaybillStatusPending: "压单",
|
||||
WaybillStatusAcceptCanceled: "取消接受",
|
||||
WaybillStatusAccepted: "已接单",
|
||||
WaybillStatusCourierArrived: "已到店",
|
||||
WaybillStatusApplyFailedGetGoods: "取货失败待审核",
|
||||
WaybillStatusAgreeFailedGetGoods: "取货失败",
|
||||
WaybillStatusDelivering: "配送中",
|
||||
WaybillStatusDeliverFailed: "投递失败",
|
||||
WaybillStatusDelivered: "送达",
|
||||
WaybillStatusCanceled: "取消",
|
||||
WaybillStatusFailed: "失败",
|
||||
}
|
||||
OrderTypeName = map[int]string{
|
||||
OrderTypeOrder: "订单",
|
||||
OrderTypeWaybill: "运单",
|
||||
OrderTypeOrder: "订单",
|
||||
OrderTypeWaybill: "运单",
|
||||
OrderTypeAfsOrder: "售后单",
|
||||
}
|
||||
|
||||
MultiStoresVendorMap = map[int]int{
|
||||
@@ -159,11 +171,30 @@ var (
|
||||
"打印机密钥",
|
||||
},
|
||||
}
|
||||
AfsReasonTypeName = map[int]string{
|
||||
AfsReasonTypeGoodsQuality: "商品质量",
|
||||
AfsReasonTypeWrongGoods: "错误的商品",
|
||||
AfsReasonTypeMissingGoods: "缺少部分商品",
|
||||
AfsReasonTypeNoGoods: "全部商品未收到",
|
||||
AfsReasonTypeDamagedGoods: "商品有损伤",
|
||||
AfsReasonTypeGoodsQuantity: "缺斤少两",
|
||||
AfsReasonTypeAgreedByMerchant: "与商家协商一致",
|
||||
AfsReasonTypeGoodsNoSame: "商品与描述不符",
|
||||
AfsReasonWrongPurchase: "误购",
|
||||
AfsReasonNotReceivedIntime: "未在时效内送达",
|
||||
AfsReasonNotOthers: "其它",
|
||||
}
|
||||
AfsAppealTypeName = map[int]string{
|
||||
AfsAppealTypeRefund: "仅退款",
|
||||
AfsAppealTypeReturnAndRefund: "退货退款",
|
||||
AfsAppealTypeNewGoods: "重发商品",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
OrderTypeOrder = 1
|
||||
OrderTypeWaybill = 2
|
||||
OrderTypeOrder = 1
|
||||
OrderTypeWaybill = 2
|
||||
OrderTypeAfsOrder = 3
|
||||
)
|
||||
|
||||
// https://blog.csdn.net/a13570320979/article/details/51366355
|
||||
@@ -212,6 +243,14 @@ const (
|
||||
OrderStatusEndBegin = 100 // 以下的状态就是结束状态
|
||||
OrderStatusFinished = 110 // 订单已完成
|
||||
OrderStatusCanceled = 115 // 订单已取消
|
||||
OrderStatusEndEnd = 120
|
||||
|
||||
AfsOrderStatusWait4Approve = 155 // 待审核售后单
|
||||
AfsOrderStatusNew = 160 // 已审核或不需要审核售后单
|
||||
AfsOrderStatusWait4ReceiveGoods = 165 // 退款退货的,需要商家确认收到货
|
||||
AfsOrderStatusReceivedGoods = 167 // 已确认收到货
|
||||
AfsOrderStatusFinished = 180 // 售后单成功完成
|
||||
AfsOrderStatusFailed = 190 // 售后单失败
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -224,6 +263,7 @@ const (
|
||||
WaybillStatusUnknown = 0
|
||||
|
||||
WaybillStatusNew = 5
|
||||
WaybillStatusPending = 7
|
||||
WaybillStatusAcceptCanceled = 8
|
||||
WaybillStatusAccepted = 10
|
||||
WaybillStatusCourierArrived = 15 // 此状态是可选的,明确写出来是因为还是较重要的状态,但业务逻辑不应依赖此状态
|
||||
@@ -238,7 +278,6 @@ const (
|
||||
WaybillStatusDelivered = 105 // todo 这个应该改为110,与订单对应
|
||||
WaybillStatusCanceled = 115
|
||||
WaybillStatusFailed = 120 // 这个状态存在的意义是区分于WaybillStatusCanceled,比如达达平台在这种状态下再次创建运单的方式不一样
|
||||
WaybillStatusNeverSend = 125 // 这个状态指的是平台方不愿意配送,门店自己想办法。与WaybillStatusAcceptCanceled不一样,WaybillStatusAcceptCanceled可能之后还会尝试配送
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -261,6 +300,13 @@ const (
|
||||
const (
|
||||
OrderDeliveryFlagMaskScheduleDisabled = 1 // 禁止三方配送调度
|
||||
OrderDeliveryFlagMaskPurcahseDisabled = 2 // 购物平台已不配送(一般为门店配送类型本身为自配送,或已经转自配送)
|
||||
|
||||
OrderDeliveryFlagMaskDada = 16 // 创建达达运单中
|
||||
OrderDeliveryFlagMaskMtps = 32 // 创建美团配送运单中
|
||||
)
|
||||
|
||||
const (
|
||||
WaybillDeliveryFlagMaskActiveCancel = 1 // 主动取消
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -275,7 +321,42 @@ const (
|
||||
OrderFlagRefuseFailedGetGoods = 24
|
||||
|
||||
OrderFlagMaskFailedDeliver = 32
|
||||
OrderFlagMaskCallPMCourier = 64 // 取货失败后召唤平台配送
|
||||
OrderFlagMaskCallPMCourier = 64 // 取货失败后召唤平台配送
|
||||
OrderFlagMaskSetDelivered = 128 // 设置送达
|
||||
)
|
||||
|
||||
const (
|
||||
AfsOrderFlagMaskUserRefund = 3 // 门店处理售后单申请
|
||||
AfsOrderFlagAgreeUserRefund = 1 // 门店同意售后单申请
|
||||
AfsOrderFlagRefuseUserRefund = 3 // 门店拒绝售后单申请
|
||||
|
||||
AfsOrderFlagMaskReturnGoods = 4 // 门店确认收到退货
|
||||
)
|
||||
|
||||
const (
|
||||
AfsAppealTypeRefund = 1 // 仅退款
|
||||
AfsAppealTypeReturnAndRefund = 2 // 退货退款
|
||||
AfsAppealTypeNewGoods = 3 // 重发新商品(即京东到家的直赔)
|
||||
)
|
||||
|
||||
const (
|
||||
AfsReasonTypeGoodsQuality = 1 // 商品质量
|
||||
AfsReasonTypeWrongGoods = 2 // 错误的商品
|
||||
AfsReasonTypeMissingGoods = 3 // 缺少部分商品
|
||||
AfsReasonTypeNoGoods = 4 // 全部商品未收到
|
||||
AfsReasonTypeDamagedGoods = 5 // 商品有损伤
|
||||
AfsReasonTypeGoodsQuantity = 6 // 缺斤少两
|
||||
AfsReasonTypeAgreedByMerchant = 7 // 与商家协商一致
|
||||
AfsReasonTypeGoodsNoSame = 8 // 商品与描述不符
|
||||
AfsReasonWrongPurchase = 9 // 误购
|
||||
AfsReasonNotReceivedIntime = 10 // 未在时效内送达
|
||||
AfsReasonNotOthers = 0 // 其它
|
||||
)
|
||||
|
||||
const (
|
||||
AfsTypeUnknown = 0 // 未知
|
||||
AfsTypePartRefund = 1 // 部分退款
|
||||
AfsTypeFullRefund = 2 // 全额退款
|
||||
)
|
||||
|
||||
func IsPurchaseVendorExist(vendorID int) bool {
|
||||
@@ -306,9 +387,22 @@ func IsOrderMainStatus(status int) bool {
|
||||
}
|
||||
|
||||
func IsOrderFinalStatus(status int) bool {
|
||||
return status >= OrderStatusEndBegin
|
||||
return status >= OrderStatusEndBegin && status <= OrderStatusEndEnd
|
||||
}
|
||||
|
||||
func IsOrderImportantStatus(status int) bool {
|
||||
return IsOrderMainStatus(status) || IsOrderLockStatus(status) || IsOrderUnlockStatus(status)
|
||||
}
|
||||
|
||||
func WaybillVendorID2Mask(vendorID int) (mask int8) {
|
||||
if vendorID == VendorIDDada {
|
||||
mask = OrderDeliveryFlagMaskDada
|
||||
} else if vendorID == VendorIDMTPS {
|
||||
mask = OrderDeliveryFlagMaskMtps
|
||||
}
|
||||
return mask
|
||||
}
|
||||
|
||||
func IsAfsOrderFinalStatus(status int) bool {
|
||||
return status >= AfsOrderStatusFinished && status <= AfsOrderStatusFailed
|
||||
}
|
||||
|
||||
117
business/model/dao/act.go
Normal file
117
business/model/dao/act.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func GetActVendorInfo(db *DaoDB, actID int, vendorIDs []int) (actMap map[int]*model.Act2, err error) {
|
||||
sql := `
|
||||
SELECT t1.*,
|
||||
t2.id map_id, t2.vendor_id, t2.vendor_act_id, t2.sync_status
|
||||
FROM act t1
|
||||
JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ?
|
||||
WHERE t1.deleted_at = ? AND t1.id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
actID,
|
||||
}
|
||||
if len(vendorIDs) > 0 {
|
||||
sql += " AND t2.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
|
||||
sqlParams = append(sqlParams, vendorIDs)
|
||||
}
|
||||
var actList []*model.Act2
|
||||
if err = GetRows(db, &actList, sql, sqlParams...); err == nil {
|
||||
actMap = make(map[int]*model.Act2)
|
||||
for _, v := range actList {
|
||||
actMap[v.VendorID] = v
|
||||
}
|
||||
}
|
||||
return actMap, err
|
||||
}
|
||||
|
||||
func GetActStoreVendorInfo(db *DaoDB, actID int, vendorIDs, storeIDs []int) (actStoreMap map[int][]*model.ActStore2, err error) {
|
||||
sql := `
|
||||
SELECT t1.*,
|
||||
t1.id map_id,
|
||||
t2.vendor_store_id
|
||||
FROM act_store_map t1
|
||||
JOIN store_map t2 ON t2.store_id = t1.store_id AND t2.vendor_id = t1.vendor_id AND t2.deleted_at = ?
|
||||
WHERE t1.deleted_at = ? AND t1.act_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
actID,
|
||||
}
|
||||
if len(vendorIDs) > 0 {
|
||||
sql += " AND t1.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
|
||||
sqlParams = append(sqlParams, vendorIDs)
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
var actStoreList []*model.ActStore2
|
||||
if err = GetRows(db, &actStoreList, sql, sqlParams...); err == nil {
|
||||
actStoreMap = make(map[int][]*model.ActStore2)
|
||||
for _, v := range actStoreList {
|
||||
actStoreMap[v.VendorID] = append(actStoreMap[v.VendorID], v)
|
||||
}
|
||||
}
|
||||
return actStoreMap, err
|
||||
}
|
||||
|
||||
func GetActStoreSkuVendorInfo(db *DaoDB, actID int, vendorIDs, storeIDs, skuIDs []int) (actStoreSkuMap map[int][]*model.ActStoreSku2, err error) {
|
||||
sql := `
|
||||
SELECT t1.*,
|
||||
t2.id map_id, t2.vendor_id, t2.vendor_act_id, t2.sync_status,
|
||||
t3.vendor_store_id,
|
||||
CASE t2.vendor_id
|
||||
WHEN 0 THEN
|
||||
t4.jd_id
|
||||
WHEN 1 THEN
|
||||
t5.mtwm_id
|
||||
WHEN 3 THEN
|
||||
t5.ebai_id
|
||||
ELSE
|
||||
''
|
||||
END vendor_sku_id
|
||||
FROM act_store_sku t1
|
||||
JOIN act_store_sku_map t2 ON t2.act_id = t1.act_id AND t2.sku_id = t1.sku_id AND t2.store_id = t1.store_id AND t2.deleted_at = ?
|
||||
JOIN store_map t3 ON t3.store_id = t1.store_id AND t3.vendor_id = t2.vendor_id AND t3.deleted_at = ?
|
||||
JOIN sku t4 ON t4.id = t1.sku_id AND t4.deleted_at = ?
|
||||
JOIN store_sku_bind t5 ON t5.sku_id = t1.sku_id AND t5.store_id = t1.store_id AND t5.deleted_at = ?
|
||||
WHERE t1.deleted_at = ? AND t1.act_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
actID,
|
||||
}
|
||||
if len(vendorIDs) > 0 {
|
||||
sql += " AND t2.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
|
||||
sqlParams = append(sqlParams, vendorIDs)
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
var actStoreSkuList []*model.ActStoreSku2
|
||||
if err = GetRows(db, &actStoreSkuList, sql, sqlParams...); err == nil {
|
||||
actStoreSkuMap = make(map[int][]*model.ActStoreSku2)
|
||||
for _, v := range actStoreSkuList {
|
||||
actStoreSkuMap[v.VendorID] = append(actStoreSkuMap[v.VendorID], v)
|
||||
}
|
||||
}
|
||||
return actStoreSkuMap, err
|
||||
}
|
||||
@@ -58,7 +58,7 @@ func UpdateEntityByKV(db *DaoDB, item interface{}, kvs map[string]interface{}, c
|
||||
}
|
||||
|
||||
func UpdateEntityLogically(db *DaoDB, item interface{}, kvs map[string]interface{}, userName string, conditions map[string]interface{}) (num int64, err error) {
|
||||
if conditions != nil {
|
||||
if conditions != nil && refutil.IsFieldExist(item, model.FieldDeletedAt) {
|
||||
conditions = utils.MergeMaps(conditions, map[string]interface{}{
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
})
|
||||
@@ -71,7 +71,7 @@ func UpdateEntityLogically(db *DaoDB, item interface{}, kvs map[string]interface
|
||||
|
||||
// 此函数会更新同步标志
|
||||
func UpdateEntityLogicallyAndUpdateSyncStatus(db *DaoDB, item interface{}, kvs map[string]interface{}, userName string, conditions map[string]interface{}, syncStatusFieldName string, valueMask int) (num int64, err error) {
|
||||
if conditions != nil {
|
||||
if conditions != nil && refutil.IsFieldExist(item, model.FieldDeletedAt) {
|
||||
conditions = utils.MergeMaps(conditions, map[string]interface{}{
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
})
|
||||
@@ -115,6 +115,7 @@ func AddStoreCategoryMap(db *DaoDB, storeID, categoryID int, vendorID int, vendo
|
||||
StoreID: storeID,
|
||||
CategoryID: categoryID,
|
||||
MtwmSyncStatus: model.SyncFlagNewMask,
|
||||
EbaiSyncStatus: model.SyncFlagNewMask,
|
||||
WscSyncStatus: model.SyncFlagNewMask,
|
||||
}
|
||||
storeCat.DeletedAt = utils.DefaultTimeValue
|
||||
|
||||
@@ -29,12 +29,12 @@ func SetOrderPrintFlag(db *DaoDB, userName string, vendorOrderID string, vendorI
|
||||
if isPrinted {
|
||||
err = SetOrderFlag(db, userName, vendorOrderID, vendorID, model.OrderFlagMaskPrinted)
|
||||
} else {
|
||||
err = SetOrderFlag(db, userName, vendorOrderID, vendorID, ^int8(model.OrderFlagMaskPrinted))
|
||||
err = SetOrderFlag(db, userName, vendorOrderID, vendorID, ^model.OrderFlagMaskPrinted)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SetOrderFlag(db *DaoDB, userName string, vendorOrderID string, vendorID int, flag int8) (err error) {
|
||||
func SetOrderFlag(db *DaoDB, userName string, vendorOrderID string, vendorID int, flag int) (err error) {
|
||||
_, err = ExecuteSQL(db, `
|
||||
UPDATE goods_order
|
||||
SET flag = flag | ?
|
||||
@@ -43,7 +43,7 @@ func SetOrderFlag(db *DaoDB, userName string, vendorOrderID string, vendorID int
|
||||
return err
|
||||
}
|
||||
|
||||
func ClearOrderFlag(db *DaoDB, userName string, vendorOrderID string, vendorID int, flag int8) (err error) {
|
||||
func ClearOrderFlag(db *DaoDB, userName string, vendorOrderID string, vendorID int, flag int) (err error) {
|
||||
_, err = ExecuteSQL(db, `
|
||||
UPDATE goods_order
|
||||
SET flag = flag & ?
|
||||
@@ -51,3 +51,34 @@ func ClearOrderFlag(db *DaoDB, userName string, vendorOrderID string, vendorID i
|
||||
`, flag, vendorOrderID, vendorID)
|
||||
return err
|
||||
}
|
||||
|
||||
func SetAfsOrderFlag(db *DaoDB, userName string, afsOrderID string, vendorID int, flag int) (err error) {
|
||||
_, err = ExecuteSQL(db, `
|
||||
UPDATE afs_order
|
||||
SET flag = flag | ?
|
||||
WHERE afs_order_id = ? AND vendor_id = ?
|
||||
`, flag, afsOrderID, vendorID)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetAfsOrders(db *DaoDB, vendorID int, vendorOrderID, afsOrderID string) (afsOrderList []*model.AfsOrder, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM afs_order t1
|
||||
WHERE t1.vendor_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorID,
|
||||
}
|
||||
if vendorOrderID != "" {
|
||||
sql += " AND t1.vendor_order_id = ?"
|
||||
sqlParams = append(sqlParams, vendorOrderID)
|
||||
}
|
||||
if afsOrderID != "" {
|
||||
sql += " AND t1.afs_order_id = ?"
|
||||
sqlParams = append(sqlParams, afsOrderID)
|
||||
}
|
||||
sql += " ORDER BY t1.afs_order_id DESC"
|
||||
err = GetRows(db, &afsOrderList, sql, sqlParams...)
|
||||
return afsOrderList, err
|
||||
}
|
||||
|
||||
@@ -168,3 +168,7 @@ func value2Value(srcValue, dstValue reflect.Value, copyType int) {
|
||||
// func ObjNull2Normal(src, dst interface{}) {
|
||||
// copyBetweenNoramAndNullObj(src, dst, 2)
|
||||
// }
|
||||
|
||||
func IsVendorThingIDEmpty(vendorThingID string) bool {
|
||||
return vendorThingID == "" || vendorThingID == "0"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func GetSellCities(db *DaoDB, nameID int, vendorID int) (cities []*model.Place, err error) {
|
||||
@@ -52,6 +55,47 @@ func GetSkuNameByHashCode(db *DaoDB, hashCode string) (skuName *model.SkuName, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetSkus(db *DaoDB, skuIDs, nameIDs, statuss, catIDs []int) (skuList []*model.SkuAndName, err error) {
|
||||
sql := `
|
||||
SELECT t1.*, t2.name, t2.unit
|
||||
FROM sku t1
|
||||
JOIN sku_name t2 ON t2.id = t1.name_id AND t2.deleted_at = ?
|
||||
`
|
||||
sqlWhere := `
|
||||
WHERE t1.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sqlWhere += " AND t1.id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
if len(nameIDs) > 0 {
|
||||
sqlWhere += " AND t1.name_id IN (" + GenQuestionMarks(len(nameIDs)) + ")"
|
||||
sqlParams = append(sqlParams, nameIDs)
|
||||
}
|
||||
if len(statuss) > 0 {
|
||||
sqlWhere += " AND t1.status IN (" + GenQuestionMarks(len(statuss)) + ") AND t2.status IN (" + GenQuestionMarks(len(statuss)) + ")"
|
||||
sqlParams = append(sqlParams, statuss, statuss)
|
||||
}
|
||||
if len(catIDs) > 0 {
|
||||
sql += `
|
||||
JOIN sku_category t3 ON t3.id = t2.category_id
|
||||
LEFT JOIN sku_category t3p ON t3p.id = t3.parent_id
|
||||
`
|
||||
sqlWhere += " AND (t3.id IN (" + GenQuestionMarks(len(catIDs)) + ")"
|
||||
sqlWhere += " OR t3p.id IN (" + GenQuestionMarks(len(catIDs)) + ") )"
|
||||
sqlParams = append(sqlParams, catIDs, catIDs)
|
||||
}
|
||||
sql += sqlWhere
|
||||
if err = GetRows(db, &skuList, sql, sqlParams...); err == nil {
|
||||
return skuList, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetSkuNames(db *DaoDB, nameIDs []int) (skuNameList []*model.SkuName, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
@@ -70,3 +114,76 @@ func GetSkuNames(db *DaoDB, nameIDs []int) (skuNameList []*model.SkuName, err er
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetSkuByNames(db *DaoDB, nameIDs []int) (skuList []*model.Sku, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM sku t1
|
||||
WHERE t1.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if len(nameIDs) > 0 {
|
||||
sql += " AND t1.name_id IN (" + GenQuestionMarks(len(nameIDs)) + ")"
|
||||
sqlParams = append(sqlParams, nameIDs)
|
||||
}
|
||||
if err = GetRows(db, &skuList, sql, sqlParams...); err == nil {
|
||||
return skuList, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetSkuIDByNames(db *DaoDB, nameIDs []int) (skuIDs []int, err error) {
|
||||
skuList, err := GetSkuByNames(db, nameIDs)
|
||||
if err == nil {
|
||||
for _, sku := range skuList {
|
||||
skuIDs = append(skuIDs, sku.ID)
|
||||
}
|
||||
}
|
||||
return skuIDs, err
|
||||
}
|
||||
|
||||
func GetSkuByCats(db *DaoDB, catIDs []int) (skuList []*model.Sku, err error) {
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM sku t1
|
||||
JOIN sku_name t2 ON t2.id = t1.name_id
|
||||
WHERE t1.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if len(catIDs) > 0 {
|
||||
sql += " AND t2.category_id IN (" + GenQuestionMarks(len(catIDs)) + ")"
|
||||
sqlParams = append(sqlParams, catIDs)
|
||||
}
|
||||
err = GetRows(db, &skuList, sql, sqlParams...)
|
||||
globals.SugarLogger.Debugf("GetSkuByCats err:%v", err)
|
||||
return skuList, err
|
||||
}
|
||||
|
||||
func SetSkuSyncStatus(db *DaoDB, vendorID int, skuIDs []int, syncStatus int) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("SetSkuSyncStatus, vendorID:%d", vendorID)
|
||||
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql := fmt.Sprintf(`
|
||||
UPDATE sku t1
|
||||
SET t1.%s_sync_status = IF(t1.deleted_at = ?, t1.%s_sync_status | ?, 0)
|
||||
`, fieldPrefix, fieldPrefix)
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
syncStatus,
|
||||
}
|
||||
if (syncStatus & model.SyncFlagNewMask) != 0 {
|
||||
sql += fmt.Sprintf(`,
|
||||
t1.%s_id = 0
|
||||
`, fieldPrefix)
|
||||
}
|
||||
sql += " WHERE 1 = 1"
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND t1.id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
return ExecuteSQL(db, sql, sqlParams...)
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ type StoreDetail struct {
|
||||
|
||||
type StoreDetail2 struct {
|
||||
model.Store
|
||||
VendorStoreID string `orm:"column(vendor_store_id)` // 这个在GetMissingDadaStores返回中指的是到家的vendorStoreID
|
||||
DadaStoreID string `orm:"column(dada_store_id)`
|
||||
VendorStoreID string `orm:"column(vendor_store_id)"` // 这个在GetMissingDadaStores返回中指的是到家的vendorStoreID
|
||||
DadaStoreID string `orm:"column(dada_store_id)"`
|
||||
DistrictName string
|
||||
CityName string
|
||||
}
|
||||
@@ -136,8 +136,8 @@ func GetMissingDadaStores(db *DaoDB, storeID int, isMustHaveJdStore bool) (store
|
||||
t3.vendor_store_id dada_store_id
|
||||
FROM store t1
|
||||
LEFT JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND t2.deleted_at = ?
|
||||
JOIN place city ON city.code = t1.city_code
|
||||
JOIN place district ON district.code = t1.district_code
|
||||
LEFT JOIN place city ON city.code = t1.city_code
|
||||
LEFT JOIN place district ON district.code = t1.district_code
|
||||
LEFT JOIN store_courier_map t3 ON t3.store_id = t1.id AND t3.vendor_id = ? AND t3.deleted_at = ?
|
||||
WHERE t1.deleted_at = ?
|
||||
`
|
||||
@@ -181,6 +181,33 @@ func GetStoreCourierList(db *DaoDB, storeID, status int) (courierStoreList []*mo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func GetStoresMapList(db *DaoDB, vendorIDs, storeIDs []int, status int) (storeMapList []*model.StoreMap, err error) {
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM store_map t1
|
||||
WHERE t1.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if len(vendorIDs) > 0 {
|
||||
sql += " AND t1.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
|
||||
sqlParams = append(sqlParams, vendorIDs)
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if status != model.StoreStatusAll {
|
||||
sql += " AND t1.status = ?"
|
||||
sqlParams = append(sqlParams, status)
|
||||
}
|
||||
if err = GetRows(db, &storeMapList, sql, sqlParams...); err == nil {
|
||||
return storeMapList, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 此函数在检测到一个门店的所有平台状态一样,且不为StoreStatusOpened时,
|
||||
// 将平台门店状态全部改为StoreStatusOpened,则把京西门店状态改为之前那个统一的平台门店状态
|
||||
func FormalizeStoreStatus(db *DaoDB, storeID, storeStatus int) (err error) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
@@ -13,13 +14,16 @@ var (
|
||||
model.VendorIDWSC: "img_weimob",
|
||||
model.VendorIDEBAI: "img_ebai",
|
||||
}
|
||||
descImgFieldMap = map[int]string{
|
||||
model.VendorIDEBAI: "desc_img_ebai",
|
||||
}
|
||||
)
|
||||
|
||||
type SkuStoreCatInfo struct {
|
||||
model.SkuCategory
|
||||
MapID int `orm:"column(map_id)"` // 这个主要用于判断是否有store_sku_category_map
|
||||
VendorCatID string `orm:"column(vendor_cat_id)"`
|
||||
CatSyncStatus int8
|
||||
MapID int `orm:"column(map_id)"` // 这个主要用于判断是否有store_sku_category_map
|
||||
VendorCatID string `orm:"column(vendor_cat_id)"`
|
||||
StoreCatSyncStatus int8
|
||||
|
||||
ParentCatName string
|
||||
ParentMapID int `orm:"column(parent_map_id)"` // 这个主要用于判断是否有父store_sku_category_map
|
||||
@@ -27,47 +31,63 @@ type SkuStoreCatInfo struct {
|
||||
ParentCatSyncStatus int8
|
||||
}
|
||||
|
||||
type StoreCatSyncInfo struct {
|
||||
CatName string
|
||||
Seq int `json:"seq"`
|
||||
model.StoreSkuCategoryMap
|
||||
|
||||
ParentCatName string
|
||||
ParentCatID int `orm:"column(parent_cat_id)"` // 这个主要用于判断是否有父store_sku_category_map
|
||||
ParentVendorCatID string `orm:"column(parent_vendor_cat_id)"`
|
||||
ParentCatSyncStatus int8
|
||||
}
|
||||
|
||||
type StoreSkuSyncInfo struct {
|
||||
BindID int `orm:"column(bind_id)"`
|
||||
Price int64
|
||||
UnitPrice int64
|
||||
StoreSkuStatus int
|
||||
SkuSyncStatus int8
|
||||
// 平台无关的store sku信息
|
||||
BindID int `orm:"column(bind_id)"` // 换名的原因是与Sku.ID同名区别
|
||||
StoreID int `orm:"column(store_id)"`
|
||||
SkuID int `orm:"column(sku_id)"` // 这个与Sku.ID的区别是SkuID是必然存在的
|
||||
Price int64
|
||||
UnitPrice int64
|
||||
|
||||
// 平台相关的store sku信息
|
||||
StoreSkuStatus int
|
||||
StoreSkuSyncStatus int8
|
||||
VendorSkuID string `orm:"column(vendor_sku_id)"`
|
||||
|
||||
model.Sku
|
||||
VendorSkuID string `orm:"column(vendor_sku_id)"`
|
||||
|
||||
// sku_name
|
||||
Prefix string
|
||||
NameID int `orm:"column(name_id)"`
|
||||
VendorNameID string `orm:"column(vendor_name_id)"`
|
||||
Name string
|
||||
Unit string
|
||||
Img string
|
||||
Upc string
|
||||
Seq int
|
||||
|
||||
VendorVendorCatID int64 `orm:"column(vendor_vendor_cat_id)"`
|
||||
// 平台相关的图片信息
|
||||
Img string
|
||||
DescImg string
|
||||
|
||||
CatSyncStatus int8
|
||||
VendorCatID string `orm:"column(vendor_cat_id)"`
|
||||
VendorVendorCatID int64 `orm:"column(vendor_vendor_cat_id)"` // 平台商品分类(叶子结点)
|
||||
VendorVendorCatID2 int64 `orm:"column(vendor_vendor_cat_id2)"` // 平台商品分类上一级
|
||||
VendorVendorCatID3 int64 `orm:"column(vendor_vendor_cat_id3)"` // 平台商品分类再上一级
|
||||
|
||||
SkuCatSyncStatus int8
|
||||
SkuVendorCatID string `orm:"column(sku_vendor_cat_id)"`
|
||||
// sku的商家分类信息
|
||||
SkuStoreCatSyncStatus int8
|
||||
SkuVendorCatID string `orm:"column(sku_vendor_cat_id)"`
|
||||
|
||||
// sku_name的商家分类信息
|
||||
StoreCatSyncStatus int8
|
||||
VendorCatID string `orm:"column(vendor_cat_id)"`
|
||||
|
||||
CatPricePercentage int
|
||||
}
|
||||
|
||||
type MissingStoreSkuInfo struct {
|
||||
StoreID int `orm:"column(store_id)"`
|
||||
NameID int `orm:"column(name_id)"`
|
||||
SkuID int `orm:"column(sku_id)"`
|
||||
SpecQuality float32
|
||||
SpecUnit string
|
||||
Unit string
|
||||
RefPrice int
|
||||
}
|
||||
|
||||
// 单门店模式厂商适用
|
||||
// 从store_sku_bind中,得到所有依赖的商家分类信息
|
||||
func GetSkusCategories(db *DaoDB, vendorID, storeID int, skuIDs []int, level int) (cats []*SkuStoreCatInfo, err error) {
|
||||
sql := `
|
||||
SELECT DISTINCT t4.*, t5.id map_id, t5.%s_id vendor_cat_id, t5.%s_sync_status cat_sync_status, t4p.name parent_cat_name, t5p.id parent_map_id, t5p.%s_id parent_vendor_cat_id, t5p.%s_sync_status parent_cat_sync_status
|
||||
SELECT DISTINCT t4.*, t5.id map_id, t5.%s_id vendor_cat_id, t5.%s_sync_status store_cat_sync_status, t4p.name parent_cat_name, t5p.id parent_map_id, t5p.%s_id parent_vendor_cat_id, t5p.%s_sync_status parent_cat_sync_status
|
||||
FROM store_sku_bind t1
|
||||
JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ? AND t2.status = ?
|
||||
JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ? AND t3.status = ?
|
||||
@@ -86,7 +106,7 @@ func GetSkusCategories(db *DaoDB, vendorID, storeID int, skuIDs []int, level int
|
||||
LEFT JOIN store_sku_category_map t5 ON t4.id = t5.category_id AND t5.store_id = t1.store_id AND t5.deleted_at = ?
|
||||
LEFT JOIN sku_category t4p ON t4.parent_id = t4p.id
|
||||
LEFT JOIN store_sku_category_map t5p ON t4p.id = t5p.category_id AND t5p.store_id = t1.store_id AND t5p.deleted_at = ?
|
||||
WHERE t1.deleted_at = ? AND t1.store_id = ?
|
||||
WHERE t1.deleted_at = ? AND t1.store_id = ? AND t1.status = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
@@ -98,6 +118,7 @@ func GetSkusCategories(db *DaoDB, vendorID, storeID int, skuIDs []int, level int
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
model.SkuStatusNormal,
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
@@ -112,93 +133,132 @@ func GetSkusCategories(db *DaoDB, vendorID, storeID int, skuIDs []int, level int
|
||||
}
|
||||
|
||||
// 单门店模式厂商适用
|
||||
func GetStoreCategories(db *DaoDB, vendorID, storeID int, level int) (cats []*StoreCatSyncInfo, err error) {
|
||||
// 单纯的从已经创建的store_sku_category_map中,得到相关的同步信息
|
||||
func GetStoreCategories(db *DaoDB, vendorID, storeID int, level int) (cats []*SkuStoreCatInfo, err error) {
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql := fmt.Sprintf(`
|
||||
SELECT t5.*, t4.name cat_name, t4.seq, t4p.name parent_cat_name, t5p.category_id parent_cat_id, t5p.%s_id parent_vendor_cat_id, t5p.%s_sync_status parent_cat_sync_status
|
||||
SELECT t4.*,
|
||||
t5.id map_id, t5.%s_id vendor_cat_id, t5.%s_sync_status store_cat_sync_status,
|
||||
t4p.name parent_cat_name,
|
||||
t5p.id parent_map_id, t5p.%s_id parent_vendor_cat_id, t5p.%s_sync_status parent_cat_sync_status
|
||||
FROM store_sku_category_map t5
|
||||
JOIN sku_category t4 ON t5.category_id = t4.id AND t4.deleted_at = ?
|
||||
LEFT JOIN sku_category t4p ON t4.parent_id = t4p.id
|
||||
LEFT JOIN store_sku_category_map t5p ON t4p.id = t5p.category_id AND t5.store_id = t5p.store_id AND t5p.deleted_at = ?
|
||||
WHERE t5.store_id = ? AND t4.level = ? AND t5.%s_sync_status <> 0 AND t5.deleted_at = ?
|
||||
`, fieldPrefix, fieldPrefix, fieldPrefix)
|
||||
`, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix)
|
||||
if err = GetRows(db, &cats, sql, utils.DefaultTimeValue, utils.DefaultTimeValue, storeID, level, utils.DefaultTimeValue); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cats, err
|
||||
}
|
||||
|
||||
// 单门店模式厂商适用
|
||||
func GetStoreSkus(db *DaoDB, vendorID, storeID int, skuIDs []int) (skus []*StoreSkuSyncInfo, err error) {
|
||||
// 以store_sku_bind为基础来做同步,正常情况下使用
|
||||
// 单多门店模式厂商通用
|
||||
func GetStoreSkus2(db *DaoDB, vendorID, storeID int, skuIDs []int, isDirty bool) (skus []*StoreSkuSyncInfo, err error) {
|
||||
isSingleStorePF := model.MultiStoresVendorMap[vendorID] != 1
|
||||
tableName := "t1"
|
||||
if model.MultiStoresVendorMap[vendorID] == 1 { // 多店模式平台
|
||||
if !isSingleStorePF {
|
||||
tableName = "t2"
|
||||
}
|
||||
vendorSkuNameField := "0"
|
||||
if vendorID == model.VendorIDWSC {
|
||||
vendorSkuNameField = "t1.wsc_id2"
|
||||
}
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql := `
|
||||
SELECT t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, %s.%s_id vendor_sku_id, t1.%s_sync_status sku_sync_status, %s vendor_name_id,
|
||||
SELECT t1.id bind_id, t1.sku_id, t1.price, t1.unit_price, t1.status store_sku_status, %s.%s_id vendor_sku_id, t1.%s_sync_status store_sku_sync_status, %s vendor_name_id, t1.store_id,
|
||||
t2.*,
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, t3.%s img, t3.upc,
|
||||
t4.%s_category_id vendor_vendor_cat_id,
|
||||
t5.%s_sync_status cat_sync_status, t5.%s_id vendor_cat_id,
|
||||
t5sku.%s_sync_status sku_cat_sync_status, t5sku.%s_id sku_vendor_cat_id
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, IF(t3.%s <> '', t3.%s, t3.img) img, t3.upc, t3.%s desc_img,
|
||||
t4.%s_category_id vendor_vendor_cat_id, t4.%s_price_percentage cat_price_percentage
|
||||
`
|
||||
fmtParams := []interface{}{
|
||||
tableName, fieldPrefix, fieldPrefix, vendorSkuNameField, GetImgFieldName(vendorID), GetImgFieldName(vendorID), GetDescImgFieldName(vendorID),
|
||||
fieldPrefix, fieldPrefix,
|
||||
}
|
||||
if vendorID == model.VendorIDEBAI {
|
||||
sql += `,
|
||||
t4vp.vendor_category_id vendor_vendor_cat_id2, t4vp.parent_id vendor_vendor_cat_id3`
|
||||
}
|
||||
if isSingleStorePF {
|
||||
sql += `,
|
||||
t5.%s_sync_status store_cat_sync_status, t5.%s_id vendor_cat_id,
|
||||
t5sku.%s_sync_status sku_store_cat_sync_status, t5sku.%s_id sku_vendor_cat_id`
|
||||
fmtParams = append(fmtParams, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix)
|
||||
}
|
||||
sql += `
|
||||
FROM store_sku_bind t1
|
||||
LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ? AND t2.status = ?
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ? AND t3.status = ?
|
||||
JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ?
|
||||
JOIN store_sku_category_map t5 ON t4.id = t5.category_id AND t5.store_id = t1.store_id AND t5.deleted_at = ?
|
||||
LEFT JOIN store_sku_category_map t5sku ON t2.category_id = t5sku.category_id AND t5sku.store_id = t1.store_id AND t5sku.deleted_at = ?
|
||||
WHERE t1.store_id = ? AND t1.%s_sync_status <> 0
|
||||
`
|
||||
LEFT JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ?`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
model.SkuStatusNormal,
|
||||
utils.DefaultTimeValue,
|
||||
model.SkuStatusNormal,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
}
|
||||
if vendorID == model.VendorIDEBAI {
|
||||
sql += `
|
||||
LEFT JOIN sku_vendor_category t4v ON t4v.vendor_category_id = t4.%s_category_id AND t4v.vendor_id = ?
|
||||
LEFT JOIN sku_vendor_category t4vp ON t4vp.vendor_category_id = t4v.parent_id AND t4v.vendor_id = ?`
|
||||
fmtParams = append(fmtParams, fieldPrefix)
|
||||
sqlParams = append(sqlParams, vendorID, vendorID)
|
||||
}
|
||||
if isSingleStorePF {
|
||||
sql += `
|
||||
LEFT JOIN store_sku_category_map t5 ON t4.id = t5.category_id AND t5.store_id = t1.store_id AND t5.deleted_at = ?
|
||||
LEFT JOIN store_sku_category_map t5sku ON t2.category_id = t5sku.category_id AND t5sku.store_id = t1.store_id AND t5sku.deleted_at = ?`
|
||||
sqlParams = append(sqlParams, utils.DefaultTimeValue, utils.DefaultTimeValue)
|
||||
}
|
||||
sql += " WHERE t1.store_id = ?"
|
||||
sqlParams = append(sqlParams, storeID)
|
||||
if isDirty {
|
||||
sql += " AND (t1.%s_sync_status <> 0 OR (%s.%s_id <> 0 AND t3.id IS NULL))"
|
||||
fmtParams = append(fmtParams, fieldPrefix, tableName, fieldPrefix)
|
||||
} else {
|
||||
sql += " AND t1.deleted_at = ?"
|
||||
sqlParams = append(sqlParams, utils.DefaultTimeValue)
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql = fmt.Sprintf(sql, tableName, fieldPrefix, fieldPrefix, vendorSkuNameField, GetImgFieldName(vendorID), fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix)
|
||||
if !isSingleStorePF {
|
||||
sql += " AND t2.%s_id <> 0"
|
||||
fmtParams = append(fmtParams, fieldPrefix)
|
||||
}
|
||||
sql = fmt.Sprintf(sql, fmtParams...)
|
||||
sql += " ORDER BY t1.price"
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
if err = GetRows(db, &skus, sql, sqlParams...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
index := 1
|
||||
for _, sku := range skus {
|
||||
sku.Seq = index
|
||||
index++
|
||||
}
|
||||
return skus, err
|
||||
}
|
||||
|
||||
func GetStoreSkus(db *DaoDB, vendorID, storeID int, skuIDs []int) (skus []*StoreSkuSyncInfo, err error) {
|
||||
return GetStoreSkus2(db, vendorID, storeID, skuIDs, true)
|
||||
}
|
||||
|
||||
// 以sku为基础来做全同步,
|
||||
// 多门店模式厂商适用
|
||||
func GetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSyncInfo, err error) {
|
||||
globals.SugarLogger.Debugf("GetFullStoreSkus, storeID:%d, vendorID:%d", storeID, vendorID)
|
||||
|
||||
sql := `
|
||||
SELECT t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, t2.%s_id vendor_sku_id, t1.%s_sync_status sku_sync_status,
|
||||
t2.*,
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, t3.%s img,
|
||||
SELECT t1.id bind_id, t1.price, t1.unit_price, t1.status store_sku_status, t2.%s_id vendor_sku_id, t1.%s_sync_status store_sku_sync_status, t1.store_id,
|
||||
t2.*, t2.id sku_id,
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, IF(t3.%s <> '', t3.%s, t3.img) img,
|
||||
t4.%s_category_id vendor_vendor_cat_id,
|
||||
t4.%s_sync_status cat_sync_status, t4.%s_id vendor_cat_id,
|
||||
t5sku.%s_sync_status sku_cat_sync_status, t5sku.%s_id sku_vendor_cat_id
|
||||
t4.%s_sync_status store_cat_sync_status, t4.%s_id vendor_cat_id,
|
||||
t5sku.%s_sync_status sku_store_cat_sync_status, t5sku.%s_id sku_vendor_cat_id
|
||||
FROM sku t2
|
||||
LEFT JOIN store_sku_bind t1 ON t1.sku_id = t2.id AND t1.store_id = ? AND t1.deleted_at = ?
|
||||
JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ? AND t3.status = ?
|
||||
JOIN sku_category t4 ON t3.category_id = t4.id AND t4.deleted_at = ?
|
||||
LEFT JOIN sku_category t5sku ON t2.category_id = t5sku.id
|
||||
WHERE t2.deleted_at = ? AND t2.status = ?
|
||||
WHERE t2.deleted_at = ? AND t2.status = ? AND t2.%s_id <> 0
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
storeID,
|
||||
@@ -210,7 +270,8 @@ func GetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSyncInf
|
||||
model.SkuStatusNormal,
|
||||
}
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql = fmt.Sprintf(sql, fieldPrefix, fieldPrefix, GetImgFieldName(vendorID), fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix)
|
||||
sql = fmt.Sprintf(sql, fieldPrefix, fieldPrefix, GetImgFieldName(vendorID), GetImgFieldName(vendorID),
|
||||
fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix, fieldPrefix)
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||||
if err = GetRows(db, &skus, sql, sqlParams...); err != nil {
|
||||
@@ -219,53 +280,79 @@ func GetFullStoreSkus(db *DaoDB, vendorID, storeID int) (skus []*StoreSkuSyncInf
|
||||
return skus, err
|
||||
}
|
||||
|
||||
func SetStoreSkuSyncStatus(db *DaoDB, vendorID, storeID int, skuIDs []int, syncStatus int) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("SetStoreSkuSyncStatus, storeID:%d, vendorID:%d", storeID, vendorID)
|
||||
// 这个函数之前是要设置没有删除或同步标志不为0的,会导致将同步标志不为0且删除了的把标志去掉,现在改为只设置没有删除的
|
||||
func SetStoreSkuSyncStatus(db *DaoDB, vendorID int, storeIDs []int, skuIDs []int, syncStatus int) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("SetStoreSkuSyncStatus, storeIDs:%v, vendorID:%d", storeIDs, vendorID)
|
||||
|
||||
isSingleStorePF := model.MultiStoresVendorMap[vendorID] != 1
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql := fmt.Sprintf(`
|
||||
UPDATE store_sku_bind
|
||||
SET %s_sync_status = IF(deleted_at = ?, %s_sync_status | ?, 0)
|
||||
`, fieldPrefix, fieldPrefix)
|
||||
sql := `
|
||||
UPDATE store_sku_bind t1
|
||||
SET t1.%s_sync_status = t1.%s_sync_status | ?
|
||||
`
|
||||
fmtParams := []interface{}{
|
||||
fieldPrefix,
|
||||
fieldPrefix,
|
||||
}
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
syncStatus,
|
||||
}
|
||||
if (syncStatus & model.SyncFlagNewMask) != 0 {
|
||||
sql += fmt.Sprintf(`,
|
||||
%s_id = 0
|
||||
`, fieldPrefix)
|
||||
if isSingleStorePF && (syncStatus&model.SyncFlagNewMask) != 0 {
|
||||
sql += `,
|
||||
t1.%s_id = 0
|
||||
`
|
||||
fmtParams = append(fmtParams, fieldPrefix)
|
||||
}
|
||||
sql += " WHERE 1 = 1"
|
||||
if storeID > 0 {
|
||||
sql += " AND store_id = ?"
|
||||
sqlParams = append(sqlParams, storeID)
|
||||
sql += " WHERE (t1.deleted_at = ?)"
|
||||
// fmtParams = append(fmtParams, fieldPrefix)
|
||||
sqlParams = append(sqlParams, utils.DefaultTimeValue)
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
sql = fmt.Sprintf(sql, fmtParams...)
|
||||
return ExecuteSQL(db, sql, sqlParams...)
|
||||
}
|
||||
|
||||
func SetStoreCategorySyncStatus(db *DaoDB, vendorID, storeID int, catIDs []int, syncStatus int) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("SetStoreCategorySyncStatus, storeID:%d, vendorID:%d", storeID, vendorID)
|
||||
func SetStoreCategorySyncStatus(db *DaoDB, vendorID int, storeIDs []int, catIDs []int, syncStatus int) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("SetStoreCategorySyncStatus, storeIDs:%v, vendorID:%d", storeIDs, vendorID)
|
||||
|
||||
isSingleStorePF := model.MultiStoresVendorMap[vendorID] != 1
|
||||
fieldPrefix := ConvertDBFieldPrefix(model.VendorNames[vendorID])
|
||||
sql := fmt.Sprintf(`
|
||||
UPDATE store_sku_category_map
|
||||
SET %s_sync_status = %s_sync_status | ?
|
||||
WHERE deleted_at = ? AND store_id = ?
|
||||
`, fieldPrefix, fieldPrefix)
|
||||
sql := `
|
||||
UPDATE store_sku_category_map t1
|
||||
SET t1.%s_sync_status = IF(t1.deleted_at = ?, t1.%s_sync_status | ?, 0)
|
||||
`
|
||||
fmtParams := []interface{}{
|
||||
fieldPrefix,
|
||||
fieldPrefix,
|
||||
}
|
||||
sqlParams := []interface{}{
|
||||
syncStatus,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
syncStatus,
|
||||
}
|
||||
if isSingleStorePF && (syncStatus&model.SyncFlagNewMask) != 0 {
|
||||
sql += `,
|
||||
t1.%s_id = 0
|
||||
`
|
||||
fmtParams = append(fmtParams, fieldPrefix)
|
||||
}
|
||||
sql += " WHERE (t1.deleted_at = ? OR t1.%s_sync_status <> 0)"
|
||||
fmtParams = append(fmtParams, fieldPrefix)
|
||||
sqlParams = append(sqlParams, utils.DefaultTimeValue)
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if len(catIDs) > 0 {
|
||||
sql += " AND category_id IN (" + GenQuestionMarks(len(catIDs)) + ")"
|
||||
sql += " AND t1.category_id IN (" + GenQuestionMarks(len(catIDs)) + ")"
|
||||
sqlParams = append(sqlParams, catIDs)
|
||||
}
|
||||
sql = fmt.Sprintf(sql, fmtParams...)
|
||||
return ExecuteSQL(db, sql, sqlParams...)
|
||||
}
|
||||
|
||||
@@ -276,3 +363,66 @@ func GetImgFieldName(vendorID int) (fieldName string) {
|
||||
}
|
||||
return fieldName
|
||||
}
|
||||
|
||||
func GetDescImgFieldName(vendorID int) (fieldName string) {
|
||||
fieldName = descImgFieldMap[vendorID]
|
||||
if fieldName == "" {
|
||||
fieldName = "desc_img"
|
||||
}
|
||||
return fieldName
|
||||
}
|
||||
|
||||
func GetStoresSkusInfo(db *DaoDB, storeIDs, skuIDs []int) (storeSkuList []*model.StoreSkuBind, err error) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM store_sku_bind t1
|
||||
WHERE t1.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if len(skuIDs) > 0 {
|
||||
sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
err = GetRows(db, &storeSkuList, sql, sqlParams...)
|
||||
return storeSkuList, err
|
||||
}
|
||||
|
||||
func GetMissingStoreSkuFromOrder(db *DaoDB, storeIDs []int, fromTime time.Time) (storeSkuList []*MissingStoreSkuInfo, err error) {
|
||||
if time.Now().Sub(fromTime) > 24*time.Hour*60 {
|
||||
return nil, fmt.Errorf("GetMissingStoreSkuFromOrder,时间超过60天")
|
||||
}
|
||||
sql := `
|
||||
SELECT IF(t2.jx_store_id <> 0, t2.jx_store_id, t2.store_id) store_id, t4.name_id, t1.sku_id,
|
||||
t4.spec_quality, t4.spec_unit, t5.unit,
|
||||
COUNT(*) ct, CAST(AVG(IF(t1.vendor_price <> 0, t1.vendor_price, t1.sale_price)) AS SIGNED) ref_price
|
||||
FROM order_sku t1
|
||||
JOIN goods_order t2 ON t2.vendor_order_id = t1.vendor_order_id
|
||||
LEFT JOIN store_sku_bind t3 ON t3.store_id = IF(t2.jx_store_id <> 0, t2.jx_store_id, t2.store_id) AND
|
||||
t3.sku_id = t1.sku_id AND t3.deleted_at = ?
|
||||
JOIN sku t4 ON t4.id = t1.sku_id
|
||||
JOIN sku_name t5 ON t5.id = t4.name_id
|
||||
WHERE t2.status = ? AND IF(t2.jx_store_id <> 0, t2.jx_store_id, t2.store_id) > 0 AND t1.sku_id > 0 AND t1.shop_price = 0 AND
|
||||
t1.order_created_at > ? AND t3.id IS NULL
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
model.OrderStatusFinished,
|
||||
fromTime,
|
||||
}
|
||||
if len(storeIDs) > 0 {
|
||||
sql += " AND IF(t2.jx_store_id <> 0, t2.jx_store_id, t2.store_id) IN (" + GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
sql += `
|
||||
GROUP BY 1,2,3,4,5,6
|
||||
ORDER BY 1,2,3,4,5,6
|
||||
`
|
||||
err = GetRows(db, &storeSkuList, sql, sqlParams...)
|
||||
return storeSkuList, err
|
||||
}
|
||||
|
||||
@@ -45,6 +45,9 @@ const (
|
||||
|
||||
FieldVendorOrderID = "VendorOrderID"
|
||||
FieldVendorOrderID2 = "VendorOrderID2"
|
||||
|
||||
FieldActID = "ActID"
|
||||
FieldVendorActID = "VendorActID"
|
||||
)
|
||||
|
||||
type ModelIDCUL struct {
|
||||
@@ -67,16 +70,43 @@ const (
|
||||
SyncFlagModifiedMask = 1
|
||||
SyncFlagNewMask = 2
|
||||
SyncFlagDeletedMask = 4
|
||||
SyncFlagChangedMask = SyncFlagModifiedMask | SyncFlagNewMask | SyncFlagDeletedMask
|
||||
|
||||
SyncFlagSaleMask = 8
|
||||
SyncFlagPriceMask = 16
|
||||
SyncFlagSaleMask = 8 // 改了门店商品可售状态必须设置此标志
|
||||
SyncFlagPriceMask = 16 // 改了门店商品价格必须设置此标志
|
||||
SyncFlagSpecMask = 32
|
||||
|
||||
SyncFlagStoreSkuOnlyMask = SyncFlagSaleMask | SyncFlagPriceMask
|
||||
SyncFlagStoreSkuModifiedMask = SyncFlagStoreSkuOnlyMask | SyncFlagModifiedMask
|
||||
SyncFlagChangedMask = SyncFlagSpecMask | SyncFlagNewMask | SyncFlagDeletedMask | SyncFlagStoreSkuModifiedMask
|
||||
|
||||
SyncFlagStoreName = 8
|
||||
SyncFlagStoreAddress = 16
|
||||
)
|
||||
|
||||
func IsSyncStatusNew(syncStatus int) bool {
|
||||
return (syncStatus & SyncFlagNewMask) != 0
|
||||
}
|
||||
|
||||
func IsSyncStatusDelete(syncStatus int) bool {
|
||||
return (syncStatus & SyncFlagDeletedMask) != 0
|
||||
}
|
||||
|
||||
func IsSyncStatusUpdate(syncStatus int) bool {
|
||||
return (syncStatus & SyncFlagModifiedMask) != 0
|
||||
}
|
||||
|
||||
func IsSyncStatusNeedCreate(syncStatus int) bool {
|
||||
return IsSyncStatusNew(syncStatus) && !IsSyncStatusDelete(syncStatus)
|
||||
}
|
||||
|
||||
func IsSyncStatusNeedDelete(syncStatus int) bool {
|
||||
return !IsSyncStatusNew(syncStatus) && IsSyncStatusDelete(syncStatus)
|
||||
}
|
||||
|
||||
func IsSyncStatusNeedUpdate(syncStatus int) bool {
|
||||
return !IsSyncStatusNew(syncStatus) && !IsSyncStatusDelete(syncStatus) && IsSyncStatusUpdate(syncStatus)
|
||||
}
|
||||
|
||||
// const (
|
||||
// KeyJdFlag = "jdFlag"
|
||||
// KeyJdSyncedAt = "jdSyncedAt"
|
||||
|
||||
@@ -16,9 +16,12 @@ type GoodsOrder struct {
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"` // 外部系统里记录的 jxstoreid
|
||||
JxStoreID int `orm:"column(jx_store_id)" json:"jxStoreID"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid
|
||||
StoreName string `orm:"size(64)" json:"storeName"`
|
||||
ShopPrice int64 `json:"shopPrice"` // 单位为分 门店标价
|
||||
SalePrice int64 `json:"salePrice"` // 单位为分 售卖价
|
||||
ShopPrice int64 `json:"shopPrice"` // 京西价
|
||||
VendorPrice int64 `json:"vendorPrice"` // 平台价
|
||||
SalePrice int64 `json:"salePrice"` // 售卖价
|
||||
ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付
|
||||
TotalShopMoney int64 `json:"shopMoney"` // 应结金额-第三方平台结算给京西的金额(包括了所有的补贴,扣除)
|
||||
PmSubsidyMoney int64 `json:"pmSubsidyMoney"` // 平台活动补贴(订单主体活动补贴+订单单条sku补贴)1+
|
||||
Weight int `json:"weight"` // 单位为克
|
||||
ConsigneeName string `orm:"size(32)" json:"consigneeName"`
|
||||
ConsigneeMobile string `orm:"size(32)" json:"consigneeMobile"`
|
||||
@@ -30,10 +33,10 @@ type GoodsOrder struct {
|
||||
SkuCount int `json:"skuCount"` // 商品类别数量,即有多少种商品(注意在某些情况下,相同SKU的商品由于售价不同,也会当成不同商品在这个值里)
|
||||
GoodsCount int `json:"goodsCount"` // 商品个数
|
||||
Status int `json:"status"` // 参见OrderStatus*相关的常量定义
|
||||
VendorStatus string `orm:"size(255)" json:"-"`
|
||||
VendorStatus string `orm:"size(255)" json:"vendorStatus"`
|
||||
LockStatus int `json:"lockStatus"`
|
||||
LockStatusTime time.Time `orm:"type(datetime);null" json:"-"` // last lock status time
|
||||
OrderSeq int `json:"orderSeq"` // 门店订单序号
|
||||
LockStatusTime time.Time `orm:"type(datetime);null" json:"lockStatusTime"` // last lock status time
|
||||
OrderSeq int `json:"orderSeq"` // 门店订单序号
|
||||
BuyerComment string `orm:"size(255)" json:"buyerComment"`
|
||||
BusinessType int `json:"businessType"`
|
||||
ExpectedDeliveredTime time.Time `orm:"type(datetime)" json:"expectedDeliveredTime"` // 预期送达时间
|
||||
@@ -44,19 +47,12 @@ type GoodsOrder struct {
|
||||
DuplicatedCount int `json:"-"` // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的
|
||||
OrderCreatedAt time.Time `orm:"type(datetime);index" json:"orderCreatedAt"` // 这里记录的是订单生效时间,即用户支付完成(货到付款即为下单时间)
|
||||
OrderFinishedAt time.Time `orm:"type(datetime)" json:"orderFinishedAt"`
|
||||
StatusTime time.Time `orm:"type(datetime)" json:"-"` // last status time
|
||||
StatusTime time.Time `orm:"type(datetime)" json:"statusTime"` // last status time
|
||||
PickDeadline time.Time `orm:"type(datetime)" json:"pickDeadline"`
|
||||
ModelTimeInfo `json:"-"`
|
||||
OriginalData string `orm:"-" json:"-"` // 只是用于传递数据
|
||||
Skus []*OrderSku `orm:"-" json:"-"`
|
||||
Flag int8 `json:"flag"` //非运单调整相关的其它状态
|
||||
SkuPmFee int64 `json:"-"` //门店商品活动总支出
|
||||
OrderPmFee int64 `json:"-"` //门店订单活动支出
|
||||
SkuPmSubsidy int64 `json:"-"` //平台商品活动总补贴
|
||||
OrderPmSubsidy int64 `json:"-"` //平台订单活动补贴
|
||||
BoxFee int64 `json:"-"` //餐盒费
|
||||
PlatformFeeRate int16 `json:"-"` //平台费
|
||||
BillStoreFreightFee int64 `json:"-"` //需要回调,门店所承担的运费
|
||||
Flag int `json:"flag"` //非运单调整相关的其它状态
|
||||
}
|
||||
|
||||
func (o *GoodsOrder) TableUnique() [][]string {
|
||||
@@ -88,18 +84,18 @@ type OrderSku struct {
|
||||
StoreSubID int `orm:"column(store_sub_id)" json:"storeSubID"`
|
||||
StoreSubName string `orm:"size(64)" json:"storeSubName"`
|
||||
Count int `json:"count"`
|
||||
VendorSkuID string `orm:"column(vendor_sku_id);size(48)" json:"-"`
|
||||
VendorSkuID string `orm:"column(vendor_sku_id);size(48)" json:"vendorSkuID"`
|
||||
SkuID int `orm:"column(sku_id)" json:"skuID"` // 外部系统里记录的 jxskuid
|
||||
JxSkuID int `orm:"column(jx_sku_id)" json:"jxSkuID"` // 根据VendorSkuID在本地系统里查询出来的 jxskuid
|
||||
SkuName string `orm:"size(255)" json:"skuName"`
|
||||
ShopPrice int64 `json:"shopPrice"` // 门店标价
|
||||
ShopPrice int64 `json:"shopPrice"` // 京西价
|
||||
VendorPrice int64 `json:"vendorPrice"` // 平台价
|
||||
SalePrice int64 `json:"salePrice"` // 售卖价
|
||||
Weight int `json:"-"` // 单位为克
|
||||
SkuType int `json:"-"` // 当前如果为gift就为1,否则缺省为0
|
||||
PromotionType int `json:"-"` // todo 当前是用于记录京东的PromotionType(生成jxorder用),没有做转换
|
||||
EarningPrice int64 `json:"earningPrice"` // 活动商品设置,结算给门店老板的钱
|
||||
Weight int `json:"weight"` // 单位为克
|
||||
SkuType int `json:"skuType"` // 当前如果为gift就为1,否则缺省为0
|
||||
PromotionType int `json:"promotionType"` // todo 当前是用于记录京东的PromotionType(生成jxorder用),没有做转换
|
||||
OrderCreatedAt time.Time `orm:"type(datetime);index" json:"-"` // 分区考虑
|
||||
SkuPmSubsidy int64 `json:"-"` //平台商品活动补贴
|
||||
SkuPmFee int64 `json:"-"` //门店商品活动支出
|
||||
}
|
||||
|
||||
// 同样商品在一个订单中可能重复出现(比如搞活动时,相同商品价格不一样,第一个有优惠)
|
||||
@@ -124,6 +120,7 @@ type Waybill struct {
|
||||
ActualFee int64 `json:"actualFee"` // 实际要支付给快递公司的费用
|
||||
DesiredFee int64 `json:"desiredFee"` // 运单总费用
|
||||
DuplicatedCount int `json:"-"` // 重复新订单消息数,这个一般不是由于消息重发造成的(消息重发由OrderStatus过滤),一般是业务逻辑造成的
|
||||
DeliveryFlag int8 `json:"deliveryFlag"`
|
||||
WaybillCreatedAt time.Time `orm:"type(datetime);index" json:"waybillCreatedAt"`
|
||||
WaybillFinishedAt time.Time `orm:"type(datetime)" json:"waybillFinishedAt"`
|
||||
StatusTime time.Time `orm:"type(datetime)" json:"-"` // last status time
|
||||
@@ -240,3 +237,24 @@ type OrderComment struct {
|
||||
CommentUpdatedAt time.Time
|
||||
UpdatedOriginalMsg string `orm:"type(text)" json:"-"`
|
||||
}
|
||||
|
||||
// 判断是否是购买平台自有物流
|
||||
// 对于京东,饿百来说,就是其自有的物流,对于微商城来说,是达达
|
||||
func IsWaybillPlatformOwn(bill *Waybill) bool {
|
||||
return bill.OrderVendorID == bill.WaybillVendorID || IsSpecialOrderPlatformWaybill(bill)
|
||||
}
|
||||
|
||||
// 是否是特殊物流
|
||||
func IsSpecialOrderPlatformWaybill(bill *Waybill) bool {
|
||||
return (bill.OrderVendorID == VendorIDWSC && bill.WaybillVendorID == VendorIDDada)
|
||||
}
|
||||
|
||||
// 订单是否已经有了有效运单
|
||||
func IsOrderHaveWaybill(order *GoodsOrder) bool {
|
||||
return order.WaybillVendorID != VendorIDUnknown && order.VendorWaybillID != ""
|
||||
}
|
||||
|
||||
// 订单是否有自己平台的有效运单
|
||||
func IsOrderHaveOwnWaybill(order *GoodsOrder) bool {
|
||||
return order.VendorID == order.WaybillVendorID && order.VendorWaybillID != ""
|
||||
}
|
||||
|
||||
@@ -70,25 +70,40 @@ func (o *OrderDiscountFinancial) TableUnique() [][]string {
|
||||
type AfsOrder struct {
|
||||
ModelIDCUL
|
||||
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` // 关联原始订单ID
|
||||
VendorOrderID2 string `orm:"column(vendor_order_id2);size(48);index" json:"vendorOrderID2"` // 关联原始订单ID2,饿百独有
|
||||
AfsOrderID string `orm:"column(afs_order_id);size(48)" json:"afsOrderID"` // 售后订单ID
|
||||
AfsCreateAt time.Time `orm:"type(datetime);index" json:"afsCreateAt"` // 订单生成时间
|
||||
VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` // 外部系统里记录的storeid
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"` // 接口返回的京西门店ID
|
||||
JxStoreID int `orm:"column(jx_store_id)" json:"jxStoreID"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid
|
||||
SkuUserMoney int64 `json:"skuUserMoney"` // 用户支付菜品金额
|
||||
FreightUserMoney int64 `json:"freightUserMoney"` // 用户支付运费金额
|
||||
AfsFreightMoney int64 `json:"afsFreightMoney"` // 退货取件费
|
||||
BoxMoney int64 `json:"boxMoney"` // 应退包装费金额
|
||||
TongchengFreightMoney int64 `json:"tongchengFreightMoney"` // 退货单产生的同城送费用
|
||||
SkuBoxMoney int64 `json:"skuBoxMoney"` // 应退订单餐盒费
|
||||
PmSubsidyMoney int64 `json:"pmSubsidyMoney"` // 平台总补贴金额
|
||||
PmSkuSubsidyMoney int64 `json:"pmSkuSubsidyMoney"` // 平台sku补贴金额
|
||||
PmRefundMoney int64 `json:"pmRefundMoney"` // 订单取消后可能存在佣金减少,平台退回部分金额的情况
|
||||
RefundMoney int64 `json:"refundMoney"` // 平台扣款总额 1
|
||||
RefundMoneyByCal int64 `json:"refundMoneyByCal"` // 平台扣款总额-通过公式计算平台扣除京西的金额M
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` // 关联原始订单ID
|
||||
VendorOrderID2 string `orm:"column(vendor_order_id2);size(48);index" json:"vendorOrderID2"` // 关联原始订单ID2,饿百独有
|
||||
AfsOrderID string `orm:"column(afs_order_id);size(48)" json:"afsOrderID"` // 售后订单ID
|
||||
AfsCreatedAt time.Time `orm:"type(datetime);null;index" json:"afsCreatedAt"` // 售后单生成时间
|
||||
AfsFinishedAt time.Time `orm:"type(datetime);null;index" json:"afsFinishedAt"` // 售后单结束时间
|
||||
VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` // 外部系统里记录的storeid
|
||||
StoreID int `orm:"column(store_id)" json:"storeID"` // 接口返回的京西门店ID
|
||||
JxStoreID int `orm:"column(jx_store_id)" json:"jxStoreID"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid
|
||||
|
||||
// IsNeedApprove int8 `json:"isNeedApprove"` // 售后单是否需要商家审核
|
||||
Status int `json:"status"`
|
||||
VendorStatus string `orm:"size(255)" json:"vendorStatus"`
|
||||
ReasonType int8 `json:"reasonType"` // 售后原因
|
||||
VendorReasonType string `orm:"size(255)" json:"vendorReasonType"`
|
||||
ReasonDesc string `orm:"size(1024)" json:"reasonDesc"` // 售后原因描述
|
||||
ReasonImgList string `orm:"size(1024)" json:"reasonImgList"` // 售后描述图片
|
||||
AppealType int8 `json:"appealType"` // 售后方式
|
||||
VendorAppealType string `orm:"size(255)" json:"vendorAppealType"`
|
||||
Flag int `json:"flag"`
|
||||
RefundType int8 `json:"refundType"`
|
||||
RefuseReason string `orm:"size(1024)" json:"refuseReason"`
|
||||
|
||||
SkuUserMoney int64 `json:"skuUserMoney"` // 用户支付菜品金额
|
||||
FreightUserMoney int64 `json:"freightUserMoney"` // 用户支付运费金额
|
||||
AfsFreightMoney int64 `json:"afsFreightMoney"` // 退货取件费
|
||||
BoxMoney int64 `json:"boxMoney"` // 应退包装费金额
|
||||
TongchengFreightMoney int64 `json:"tongchengFreightMoney"` // 退货单产生的同城送费用
|
||||
SkuBoxMoney int64 `json:"skuBoxMoney"` // 应退订单餐盒费
|
||||
PmSubsidyMoney int64 `json:"pmSubsidyMoney"` // 平台总补贴金额
|
||||
PmSkuSubsidyMoney int64 `json:"pmSkuSubsidyMoney"` // 平台sku补贴金额
|
||||
PmRefundMoney int64 `json:"pmRefundMoney"` // 订单取消后可能存在佣金减少,平台退回部分金额的情况
|
||||
RefundMoney int64 `json:"refundMoney"` // 平台扣款总额 1
|
||||
RefundMoneyByCal int64 `json:"refundMoneyByCal"` // 平台扣款总额-通过公式计算平台扣除京西的金额M
|
||||
// JxSkuMoney int64 `json:"jxSkuMoney"` // 京西补贴金额,现阶段是平台扣京西多少钱,京西扣商家多少钱,暂不考虑撤回京西补贴
|
||||
Skus []*OrderSkuFinancial `orm:"-" json:"skus"`
|
||||
}
|
||||
@@ -102,11 +117,10 @@ func (o *AfsOrder) TableUnique() [][]string {
|
||||
type OrderSkuFinancial struct {
|
||||
ModelIDCUL
|
||||
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"` // 平台id
|
||||
VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` // 关联原始订单ID
|
||||
VendorOrderID2 string `orm:"column(vendor_order_id2);size(48);index" json:"vendorOrderID2"` // 关联原始订单ID2,饿百独有
|
||||
AfsOrderID string `orm:"column(order_financial_id);size(48)" json:"afsOrderID"` // 订单结账ID
|
||||
IsAfsOrder int8 `json:"isAfsOrder"` // 0--正向单, 1--售后单
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"` // 平台id
|
||||
VendorOrderID string `orm:"column(vendor_order_id);size(48)" json:"vendorOrderID"` // 关联原始订单ID
|
||||
AfsOrderID string `orm:"column(afs_order_id);size(48)" json:"afsOrderID"` // 售后单ID
|
||||
IsAfsOrder int8 `json:"isAfsOrder"` // 0--正向单, 1--售后单
|
||||
|
||||
// ConfirmTime time.Time `orm:"type(datetime)" json:"confirmTime"` // 订单生成/完成时间
|
||||
VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` // 外部系统里记录的storeid
|
||||
@@ -141,7 +155,8 @@ type OrderSkuFinancial struct {
|
||||
|
||||
func (o *OrderSkuFinancial) TableIndex() [][]string {
|
||||
return [][]string{
|
||||
[]string{"VendorOrderID", "VendorSkuID", "PromotionType", "IsAfsOrder", "VendorID"},
|
||||
[]string{"VendorOrderID", "VendorSkuID"},
|
||||
[]string{"AfsOrderID", "VendorSkuID"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ var (
|
||||
type Promotion struct {
|
||||
ModelIDCULD
|
||||
|
||||
VendorID int `orm:"column(vendor_id)"`
|
||||
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
|
||||
Name string `orm:"size(64)" json:"name"`
|
||||
Advertising string `orm:"size(255)" json:"advertising"`
|
||||
Type int `json:"type"`
|
||||
@@ -75,6 +75,8 @@ type PromotionSku struct {
|
||||
Price int `json:"price"` // 分,活动价,这个不是单价
|
||||
LimitSkuCount int `json:"limitSkuCount"`
|
||||
IsLock int8 `json:"isLock"` // 是否锁定门店商品信息
|
||||
|
||||
EarningPrice int `json:"earningPrice"` // 活动商品设置,结算给门店老板的钱
|
||||
}
|
||||
|
||||
func (*PromotionSku) TableUnique() [][]string {
|
||||
|
||||
@@ -89,6 +89,7 @@ var (
|
||||
SpecialUnit = "份"
|
||||
SpecialSpecQuality = 500
|
||||
SpecialSpecUnit = "g"
|
||||
SpecialSpecUnit2 = "ml"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -131,7 +132,12 @@ type SkuCategory struct {
|
||||
Type int8 `json:"type"` // 类别类型,即是普通类别还是特殊用于做活动的类别
|
||||
Seq int `json:"seq"`
|
||||
|
||||
JdCategoryID int `orm:"column(jd_category_id)" json:"jdCategoryID"` // 这个是指对应的京东商品类别
|
||||
JdPricePercentage int16 `orm:"default(100)" json:"jdPricePercentage"`
|
||||
EbaiPricePercentage int16 `orm:"default(100)" json:"ebaiPricePercentage"`
|
||||
MtwmPricePercentage int16 `orm:"default(100)" json:"mtwmPricePercentage"`
|
||||
WscPricePercentage int16 `orm:"default(100)" json:"wscPricePercentage"`
|
||||
|
||||
JdCategoryID int64 `orm:"column(jd_category_id)" json:"jdCategoryID"` // 这个是指对应的京东商品类别
|
||||
ElmCategoryID int64 `orm:"column(elm_category_id)" json:"elmCategoryID"` // 这个是指对应的饿了么商品类别
|
||||
EbaiCategoryID int64 `orm:"column(ebai_category_id)" json:"ebaiCategoryID"` // 这个是指对应的饿百商品类别
|
||||
MtwmCategoryID int64 `orm:"column(mtwm_category_id)" json:"mtwmCategoryID"` // 这个是指对应的美团外卖商品类别
|
||||
@@ -159,8 +165,9 @@ type SkuName struct {
|
||||
Prefix string `orm:"size(255)" json:"prefix"`
|
||||
Name string `orm:"size(255);index" json:"name"`
|
||||
|
||||
BrandID int `orm:"column(brand_id);default(0)" json:"brandID"` // todo,此属性暂时没有使用,且有问题,应该是不同平台都有一个brandid
|
||||
CategoryID int `orm:"column(category_id);index" json:"categoryID"` // 标准类别
|
||||
BrandID int `orm:"column(brand_id);default(0)" json:"brandID"` // todo,此属性暂时没有使用,且有问题,应该是不同平台都有一个brandid
|
||||
CategoryID int `orm:"column(category_id);index" json:"categoryID"` // 标准类别
|
||||
JdCategoryID int64 `orm:"column(jd_category_id)" json:"jdCategoryID"` // 这个是指对应的京东商品类别
|
||||
|
||||
IsGlobal int8 `orm:"default(1)" json:"isGlobal"` // 是否是全部(全国)可见,如果否的话,可见性由SkuPlace决定
|
||||
Unit string `orm:"size(8)" json:"unit"`
|
||||
@@ -176,6 +183,9 @@ type SkuName struct {
|
||||
Status int `orm:"default(1)" json:"status"` // skuname状态,取值同sku.Status
|
||||
IsSpu int8 `orm:"column(is_spu)" json:"isSpu"` // 用于指明是否SKUNAME当成SPU
|
||||
|
||||
DescImg string `orm:"size(255)" json:"descImg"` // 商品详情图片描述
|
||||
DescImgEbai string `orm:"size(255)" json:"descImgEbai"` // 饿百的商品详情图片描述RTF
|
||||
|
||||
JdID int64 `orm:"column(jd_id);null;index" json:"jdID"`
|
||||
JdSyncStatus int8 `orm:"default(2)" json:"jdSyncStatus"`
|
||||
|
||||
@@ -206,6 +216,12 @@ type Sku struct {
|
||||
LinkID int `orm:"column(link_id);null;index" json:"linkID"`
|
||||
}
|
||||
|
||||
type SkuAndName struct {
|
||||
Sku
|
||||
Name string
|
||||
Unit string
|
||||
}
|
||||
|
||||
// func (*Sku) TableUnique() [][]string {
|
||||
// return [][]string{
|
||||
// []string{"JdID", "DeletedAt"},
|
||||
|
||||
@@ -2,8 +2,9 @@ package model
|
||||
|
||||
const (
|
||||
StoreStatusAll = -9
|
||||
StoreStatusDisabled = -1
|
||||
StoreStatusClosed = 0
|
||||
StoreStatusDisabled = -2
|
||||
StoreStatusClosed = -1
|
||||
StoreStatusHaveRest = 0
|
||||
StoreStatusOpened = 1
|
||||
)
|
||||
|
||||
@@ -32,7 +33,8 @@ const (
|
||||
var (
|
||||
StoreStatusName = map[int]string{
|
||||
StoreStatusDisabled: "禁用",
|
||||
StoreStatusClosed: "休息",
|
||||
StoreStatusClosed: "长期休息",
|
||||
StoreStatusHaveRest: "临时休息",
|
||||
StoreStatusOpened: "营业中",
|
||||
}
|
||||
DeliveryRangeTypeName = map[int]string{
|
||||
@@ -62,6 +64,7 @@ var (
|
||||
"NBB": "宁波银行",
|
||||
"SPDB": "浦发银行",
|
||||
"GDB": "广发银行",
|
||||
"BOCOM": "交通银行",
|
||||
"SPAB": "平安银行",
|
||||
"BSB": "包商银行",
|
||||
"CSCB": "长沙银行",
|
||||
@@ -131,6 +134,8 @@ type Store struct {
|
||||
Status int `json:"status"`
|
||||
ChangePriceType int8 `json:"changePriceType"` // 修改价格类型,即是否需要审核
|
||||
|
||||
DeliveryType int8 `orm:"-" json:"deliveryType"` // 仅用于传值
|
||||
|
||||
PrinterVendorID int `orm:"column(printer_vendor_id);" json:"printerVendorID"`
|
||||
PrinterSN string `orm:"size(32);column(printer_sn);index" json:"printerSN"`
|
||||
PrinterKey string `orm:"size(32)" json:"printerKey"`
|
||||
@@ -138,10 +143,39 @@ type Store struct {
|
||||
IDCardFront string `orm:"size(255);column(id_card_front)" json:"idCardFront"`
|
||||
IDCardBack string `orm:"size(255);column(id_card_back)" json:"idCardBack"`
|
||||
IDCardHand string `orm:"size(255);column(id_card_hand)" json:"idCardHand"`
|
||||
Licence string `orm:"size(255)" json:"licence"`
|
||||
Licence string `orm:"size(255)" json:"licence"` // 营业执照图片
|
||||
LicenceCode string `orm:"size(32)" json:"licenceCode"`
|
||||
|
||||
DeliveryType int8 `orm:"-" json:"deliveryType"` // 仅用于传值
|
||||
LicenceType int8 `json:"licenceType"` // 营业执照类型,0:个人,1:公司
|
||||
LicenceCorpName string `orm:"size(64)" json:"licenceCorpName"` // 营业执照公司名称
|
||||
LicenceOwnerName string `orm:"size(8)" json:"licenceOwnerName"` // 法人姓名
|
||||
LicenceAddress string `orm:"size(255)" json:"licenceAddress"` // 地址
|
||||
LicenceValid string `orm:"size(32)" json:"licenceValid"` // 有效期开始
|
||||
LicenceExpire string `orm:"size(32)" json:"licenceExpire"` // 有效期结束
|
||||
|
||||
IDName string `orm:"size(8);column(id_name)" json:"idName"` // 身份证姓名
|
||||
IDCode string `orm:"size(32);column(id_code)" json:"idCode"` // 身份证号
|
||||
IDValid string `orm:"column(id_valid);size(32)" json:"idValid"` // 有效期开始
|
||||
IDExpire string `orm:"column(id_expire);size(32)" json:"idExpire"` // 有效期结束
|
||||
|
||||
Licence2Image string `orm:"size(255)" json:"licence2Image"` // 食品经营许可证
|
||||
Licence2Code string `orm:"size(32)" json:"licence2Code"` // 食品经营许可证编号
|
||||
Licence2Valid string `orm:"size(32)" json:"licence2Valid"` // 有效期开始
|
||||
Licence2Expire string `orm:"size(32)" json:"licence2Expire"` // 有效期结束
|
||||
|
||||
MarketManName string `orm:"size(8)" json:"marketManName"` // 市场负责人姓名
|
||||
MarketManPhone string `orm:"size(16)" json:"marketManPhone"` // 市场负责人电话
|
||||
JxBrandFeeFactor int `json:"jxBrandFeeFactor"` // 京西品牌费因子
|
||||
MarketAddFeeFactor int `json:"marketAddFeeFactor"` // 市场附加费因子
|
||||
|
||||
PayeeName string `orm:"size(8)" json:"payeeName"` // 收款人姓名
|
||||
PayeeAccountNo string `orm:"size(255)" json:"payeeAccountNo"` // 收款账号
|
||||
PayeeBankBranchName string `orm:"size(255)" json:"payeeBankBranchName"` // 开户银行
|
||||
PayeeBankName string `orm:"size(255)" json:"payeeBankName"` // 开户支行
|
||||
PayPercentage int `json:"payPercentage"`
|
||||
|
||||
OperatorName string `orm:"size(8)" json:"operatorName"` // 运营人姓名
|
||||
OperatorPhone string `orm:"size(16)" json:"operatorPhone"` // 运营人电话
|
||||
}
|
||||
|
||||
func (*Store) TableUnique() [][]string {
|
||||
|
||||
@@ -58,6 +58,29 @@ func (*StoreSkuCategoryMap) TableUnique() [][]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (*StoreSkuCategoryMap) TableIndex() [][]string {
|
||||
return [][]string{
|
||||
[]string{"CategoryID", "StoreID", "DeletedAt"},
|
||||
}
|
||||
}
|
||||
|
||||
// type StoreSkuCategoryMap2 struct {
|
||||
// ModelIDCULD
|
||||
|
||||
// StoreID int `orm:"column(store_id)"`
|
||||
// VendorID int `orm:"column(vendor_id)"`
|
||||
// CategoryID int `orm:"column(category_id)"`
|
||||
|
||||
// VendorCatID string `orm:"column(vendor_cat_id);size(48)" json:"vendorCatID"`
|
||||
// SyncStatus int8 `orm:"default(2)"`
|
||||
// }
|
||||
|
||||
// func (*StoreSkuCategoryMap2) TableUnique() [][]string {
|
||||
// return [][]string{
|
||||
// []string{"StoreID", "VendorID", "CategoryID", "DeletedAt"},
|
||||
// }
|
||||
// }
|
||||
|
||||
type StoreSkuBind struct {
|
||||
ModelIDCULD
|
||||
|
||||
@@ -88,6 +111,12 @@ func (*StoreSkuBind) TableUnique() [][]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (*StoreSkuBind) TableIndex() [][]string {
|
||||
return [][]string{
|
||||
[]string{"SkuID", "StoreID", "DeletedAt"},
|
||||
}
|
||||
}
|
||||
|
||||
type StoreOpRequest struct {
|
||||
ModelIDCULD // DeletedAt用于表示请求操作结束,而并不一定是删除
|
||||
|
||||
|
||||
@@ -18,7 +18,11 @@ const (
|
||||
ServerMsgPing = "ping"
|
||||
|
||||
ServerMsgNewOrder = "newOrder"
|
||||
ServerMsgFinishedPickup = "finishedPickup"
|
||||
ServerMsgKeyOrderStatusChanged = "keyOrderStatusChanged" // 重要订单状态变化
|
||||
|
||||
ServerMsgNewWait4ApproveAfsOrder = "newWait4ApproveAfsOrder"
|
||||
ServerMsgKeyAfsOrderStatusChanged = "keyAfsOrderStatusChanged" // 重要售后单状态变化
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -67,8 +71,8 @@ func routinueFunc() {
|
||||
registerMsg := msg.MsgData.(*MsgOp)
|
||||
delete(channelMap[registerMsg.StoreID], registerMsg.Chan2Listen)
|
||||
close(registerMsg.Chan2Close)
|
||||
case ServerMsgNewOrder, ServerMsgKeyOrderStatusChanged:
|
||||
globals.SugarLogger.Debugf("msghub routinueFunc, msg:%s", utils.Format4Output(msg, false))
|
||||
case ServerMsgNewOrder, ServerMsgFinishedPickup, ServerMsgKeyOrderStatusChanged, ServerMsgNewWait4ApproveAfsOrder, ServerMsgKeyAfsOrderStatusChanged:
|
||||
globals.SugarLogger.Debugf("msghub routinueFunc, msg:%s", utils.Format4Output(msg, true))
|
||||
utils.CallFuncAsync(func() {
|
||||
for chan2Send := range channelMap[msg.StoreID] {
|
||||
chan2Send <- msg
|
||||
@@ -138,7 +142,7 @@ func GetMsg(ctx *jxcontext.Context, storeID int, lastOrderTime time.Time, lastOr
|
||||
case msg2, ok := <-chan2Listen:
|
||||
timer.Stop()
|
||||
if ok {
|
||||
msg.MsgData = msg2.MsgData
|
||||
msg = msg2
|
||||
}
|
||||
case <-timer.C:
|
||||
unregisterChan(storeID, chan2Listen)
|
||||
@@ -152,7 +156,7 @@ func GetMsg(ctx *jxcontext.Context, storeID int, lastOrderTime time.Time, lastOr
|
||||
}
|
||||
|
||||
func OnNewOrder(order *model.GoodsOrder) {
|
||||
globals.SugarLogger.Debugf("msghub OnNewOrder, order:%s", utils.Format4Output(order, false))
|
||||
globals.SugarLogger.Debugf("msghub OnNewOrder, order:%s", utils.Format4Output(order, true))
|
||||
utils.CallFuncAsync(func() {
|
||||
msgChan <- &ServerMsg{
|
||||
Type: ServerMsgNewOrder,
|
||||
@@ -167,13 +171,13 @@ func OnNewOrder(order *model.GoodsOrder) {
|
||||
})
|
||||
}
|
||||
|
||||
func OnKeyOrderStatusChanged(order *model.GoodsOrder) {
|
||||
globals.SugarLogger.Debugf("msghub OnKeyOrderStatusChanged, order:%s", utils.Format4Output(order, false))
|
||||
func OnFinishedPickup(order *model.GoodsOrder) {
|
||||
globals.SugarLogger.Debugf("msghub OnFinishedPickup, order:%s", utils.Format4Output(order, true))
|
||||
utils.CallFuncAsync(func() {
|
||||
msgChan <- &ServerMsg{
|
||||
Type: ServerMsgKeyOrderStatusChanged,
|
||||
Type: ServerMsgFinishedPickup,
|
||||
StoreID: jxutils.GetSaleStoreIDFromOrder(order),
|
||||
MsgData: order,
|
||||
MsgData: 1,
|
||||
// MsgData: []*model.GoodsOrderExt{
|
||||
// &model.GoodsOrderExt{
|
||||
// GoodsOrder: *order,
|
||||
@@ -182,3 +186,36 @@ func OnKeyOrderStatusChanged(order *model.GoodsOrder) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func OnKeyOrderStatusChanged(order *model.GoodsOrder) {
|
||||
globals.SugarLogger.Debugf("msghub OnKeyOrderStatusChanged, order:%s", utils.Format4Output(order, true))
|
||||
utils.CallFuncAsync(func() {
|
||||
msgChan <- &ServerMsg{
|
||||
Type: ServerMsgKeyOrderStatusChanged,
|
||||
StoreID: jxutils.GetSaleStoreIDFromOrder(order),
|
||||
MsgData: order,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func OnNewWait4ApproveAfsOrder(order *model.AfsOrder) {
|
||||
globals.SugarLogger.Debugf("msghub OnNewWait4ApproveAfsOrder, order:%s", utils.Format4Output(order, true))
|
||||
utils.CallFuncAsync(func() {
|
||||
msgChan <- &ServerMsg{
|
||||
Type: ServerMsgNewWait4ApproveAfsOrder,
|
||||
StoreID: jxutils.GetSaleStoreIDFromAfsOrder(order),
|
||||
MsgData: order,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func OnKeyAfsOrderStatusChanged(order *model.AfsOrder) {
|
||||
globals.SugarLogger.Debugf("msghub OnKeyAfsOrderStatusChanged, order:%s", utils.Format4Output(order, true))
|
||||
utils.CallFuncAsync(func() {
|
||||
msgChan <- &ServerMsg{
|
||||
Type: ServerMsgKeyAfsOrderStatusChanged,
|
||||
StoreID: jxutils.GetSaleStoreIDFromAfsOrder(order),
|
||||
MsgData: order,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func (c *DeliveryHandler) GetVendorID() int {
|
||||
func (c *DeliveryHandler) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(msg)
|
||||
}, msg.OrderID)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDDada))
|
||||
return retVal
|
||||
}
|
||||
|
||||
@@ -58,12 +58,16 @@ func (c *DeliveryHandler) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaap
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
switch msg.OrderStatus {
|
||||
case dadaapi.OrderStatusWaitingForAccept:
|
||||
order.Status = model.WaybillStatusNew
|
||||
case dadaapi.OrderStatusAccepted:
|
||||
if result, err := api.DadaAPI.QueryOrderInfo(msg.OrderID); err == nil {
|
||||
order.ActualFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["actualFee"], 0.0))
|
||||
order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["deliveryFee"], 0.0))
|
||||
}
|
||||
order.Status = model.WaybillStatusNew
|
||||
case dadaapi.OrderStatusAccepted:
|
||||
// if result, err := api.DadaAPI.QueryOrderInfo(msg.OrderID); err == nil {
|
||||
// order.ActualFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["actualFee"], 0.0))
|
||||
// order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["deliveryFee"], 0.0))
|
||||
// }
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
case dadaapi.OrderStatusDelivering:
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
@@ -99,17 +103,23 @@ func (c *DeliveryHandler) callbackMsg2Waybill(msg *dadaapi.CallbackMsg) (retVal
|
||||
return retVal
|
||||
}
|
||||
|
||||
// IDeliveryPlatformHandler
|
||||
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.CreateWaybillPolicy) (bill *model.Waybill, err error) {
|
||||
func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
|
||||
db := dao.GetDB()
|
||||
deliveryFee, addFee, err := delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
deliveryFeeInfo = &partner.WaybillFeeInfo{}
|
||||
deliveryFeeInfo.RefDeliveryFee, deliveryFeeInfo.RefAddFee, err = delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
|
||||
billParams, addParams, err := c.getBillParams(db, order)
|
||||
if err == nil {
|
||||
var result *dadaapi.CreateOrderResponse
|
||||
if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deliveryFeeInfo.DeliveryFee = jxutils.StandardPrice2Int(result.Fee)
|
||||
}
|
||||
if err = delivery.CallCreateWaybillPolicy(policy, deliveryFee, addFee, deliveryFee, order, model.VendorIDDada); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
billParams := &dadaapi.OperateOrderRequiredParams{
|
||||
return deliveryFeeInfo, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) getBillParams(db *dao.DaoDB, order *model.GoodsOrder) (billParams *dadaapi.OperateOrderRequiredParams, addParams map[string]interface{}, err error) {
|
||||
billParams = &dadaapi.OperateOrderRequiredParams{
|
||||
// ShopNo: utils.Int2Str(order.StoreID), // 当前达达的门店号与京西是一样的
|
||||
OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID),
|
||||
CargoPrice: jxutils.IntPrice2Standard(limitOrderPrice(order.ActualPayPrice)),
|
||||
@@ -121,7 +131,7 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.
|
||||
if billParams.ShopNo, err = c.getDadaShopID(order, db); err == nil {
|
||||
if billParams.CityCode, err = c.getDataCityCodeFromOrder(order, db); err == nil {
|
||||
billParams.ReceiverLng, billParams.ReceiverLat, _ = jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType)
|
||||
addParams := map[string]interface{}{
|
||||
addParams = map[string]interface{}{
|
||||
"info": fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, utils.FilterMb4(order.BuyerComment)),
|
||||
// "origin_mark": model.VendorNames[order.VendorID], // 订单来源标示(该字段可以显示在达达app订单详情页面,只支持字母,最大长度为10)
|
||||
// "origin_mark_no": fmt.Sprintf("%d", order.OrderSeq), // 订单来源编号(该字段可以显示在达达app订单详情页面,支持字母和数字,最大长度为30)
|
||||
@@ -129,11 +139,27 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.
|
||||
"cargo_weight": jxutils.IntWeight2Float(limitOrderWeight(order.Weight)),
|
||||
"cargo_num": order.GoodsCount,
|
||||
}
|
||||
}
|
||||
}
|
||||
return billParams, addParams, err
|
||||
}
|
||||
|
||||
if globals.EnableStoreWrite {
|
||||
// 达达要求第二次创建运单,调用函数不同。所以查找两天内有无相同订单号的运单
|
||||
var waybillList []*model.Waybill
|
||||
err2 := dao.GetRows(db, &waybillList, `
|
||||
// IDeliveryPlatformHandler
|
||||
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.CreateWaybillPolicy) (bill *model.Waybill, err error) {
|
||||
db := dao.GetDB()
|
||||
deliveryFee, addFee, err := delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = delivery.CallCreateWaybillPolicy(policy, deliveryFee, addFee, deliveryFee, order, model.VendorIDDada); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
billParams, addParams, err := c.getBillParams(db, order)
|
||||
if err == nil {
|
||||
if globals.EnableStoreWrite {
|
||||
// 达达要求第二次创建运单,调用函数不同。所以查找两天内有无相同订单号的运单
|
||||
var waybillList []*model.Waybill
|
||||
err2 := dao.GetRows(db, &waybillList, `
|
||||
SELECT *
|
||||
FROM waybill
|
||||
WHERE waybill_created_at > DATE_ADD(NOW(), interval -2 day)
|
||||
@@ -141,39 +167,38 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.
|
||||
AND waybill_vendor_id = ?
|
||||
ORDER BY id DESC
|
||||
`, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), model.VendorIDDada)
|
||||
var result *dadaapi.CreateOrderResponse
|
||||
if err = err2; err == nil && len(waybillList) > 0 && waybillList[0].Status != model.WaybillStatusFailed {
|
||||
globals.SugarLogger.Debugf("CreateWaybill orderID:%s len(waybillList)=%d use ReaddOrder", order.VendorOrderID, len(waybillList))
|
||||
result, err = api.DadaAPI.ReaddOrder(billParams, addParams)
|
||||
} else {
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
if false {
|
||||
result, err = api.DadaAPI.AddOrder(billParams, addParams)
|
||||
} else {
|
||||
if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dadaFee := jxutils.StandardPrice2Int(result.Fee)
|
||||
if err = delivery.CallCreateWaybillPolicy(policy, deliveryFee, addFee, dadaFee, order, model.VendorIDDada); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = api.DadaAPI.AddOrderAfterQuery(result.DeliveryNo)
|
||||
}
|
||||
}
|
||||
if err == nil && result != nil {
|
||||
bill = &model.Waybill{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
OrderVendorID: order.VendorID,
|
||||
WaybillVendorID: model.VendorIDDada,
|
||||
DesiredFee: deliveryFee,
|
||||
ActualFee: jxutils.StandardPrice2Int(result.Fee),
|
||||
}
|
||||
}
|
||||
var result *dadaapi.CreateOrderResponse
|
||||
if err = err2; err == nil && len(waybillList) > 0 && waybillList[0].Status != model.WaybillStatusFailed {
|
||||
globals.SugarLogger.Debugf("CreateWaybill orderID:%s len(waybillList)=%d use ReaddOrder", order.VendorOrderID, len(waybillList))
|
||||
result, err = api.DadaAPI.ReaddOrder(billParams, addParams)
|
||||
} else {
|
||||
err = fmt.Errorf("测试环境不能真正创建运单")
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
if false {
|
||||
result, err = api.DadaAPI.AddOrder(billParams, addParams)
|
||||
} else {
|
||||
if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dadaFee := jxutils.StandardPrice2Int(result.Fee)
|
||||
if err = delivery.CallCreateWaybillPolicy(policy, deliveryFee, addFee, dadaFee, order, model.VendorIDDada); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = api.DadaAPI.AddOrderAfterQuery(result.DeliveryNo)
|
||||
}
|
||||
}
|
||||
if err == nil && result != nil {
|
||||
bill = &model.Waybill{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
OrderVendorID: order.VendorID,
|
||||
WaybillVendorID: model.VendorIDDada,
|
||||
DesiredFee: deliveryFee,
|
||||
ActualFee: jxutils.StandardPrice2Int(result.Fee),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("测试环境不能真正创建运单")
|
||||
}
|
||||
}
|
||||
return bill, err
|
||||
|
||||
@@ -17,21 +17,33 @@ import (
|
||||
const (
|
||||
warningDistance = 10 // 公里
|
||||
warningWeight = 50 * 1000 // 克
|
||||
maxDiffFee2Mtps = 150 // 与美团配送最多差价
|
||||
maxAddFee = 300 // 最大增加费用,单位为分,超过不发三方配送了
|
||||
maxDiffFee2Mtps = 500 // 与美团配送最多差价
|
||||
maxAddFee = 200 // 最大增加费用,单位为分,超过不发三方配送了
|
||||
)
|
||||
|
||||
var (
|
||||
DefCreateWaybillPolicy = CreateWaybillPolicy(maxDiffFee2Mtps, maxAddFee)
|
||||
)
|
||||
|
||||
func NullCreateWaybillPolicy(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
func DefCreateWaybillPolicy(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) {
|
||||
if refDeliveryFee-deliveryFee > maxDiffFee2Mtps {
|
||||
errStr = fmt.Sprintf("超参考价太多, 费用:%d,参考价:%d, 最高超价:%d", deliveryFee, refDeliveryFee, maxDiffFee2Mtps)
|
||||
} else if refAddFee > maxAddFee {
|
||||
errStr = fmt.Sprintf("超基础价太多, 当前加价:%d, 最高加价:%d", refAddFee, maxAddFee)
|
||||
func CreateWaybillPolicy(maxDiffFee2Mtps2, maxAddFee2 int64) func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) {
|
||||
if maxDiffFee2Mtps2 == 0 {
|
||||
maxDiffFee2Mtps2 = maxDiffFee2Mtps
|
||||
}
|
||||
if maxAddFee2 == 0 {
|
||||
maxAddFee2 = maxAddFee
|
||||
}
|
||||
return func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) {
|
||||
if deliveryFee-refDeliveryFee > maxDiffFee2Mtps2 {
|
||||
errStr = fmt.Sprintf("超参考价太多, 费用:%d,参考价:%d, 最高超价:%d", deliveryFee, refDeliveryFee, maxDiffFee2Mtps2)
|
||||
} else if refAddFee > maxAddFee2 {
|
||||
errStr = fmt.Sprintf("超基础价太多, 当前加价:%d, 最高加价:%d", refAddFee, maxAddFee2)
|
||||
}
|
||||
return errStr
|
||||
}
|
||||
return errStr
|
||||
}
|
||||
|
||||
func AddPolicy(prevPolicy, newPolicy partner.CreateWaybillPolicy) (outPolicy partner.CreateWaybillPolicy) {
|
||||
@@ -43,11 +55,11 @@ func AddPolicy(prevPolicy, newPolicy partner.CreateWaybillPolicy) (outPolicy par
|
||||
}
|
||||
}
|
||||
|
||||
func CallCreateWaybillPolicy(policy partner.CreateWaybillPolicy, refDeliveryFee, deliveryFee, addFee int64, order *model.GoodsOrder, waybillVendorID int) (err error) {
|
||||
func CallCreateWaybillPolicy(policy partner.CreateWaybillPolicy, refDeliveryFee, refAddFee, deliveryFee int64, order *model.GoodsOrder, waybillVendorID int) (err error) {
|
||||
if policy == nil {
|
||||
policy = NullCreateWaybillPolicy
|
||||
}
|
||||
if errStr := policy(deliveryFee, deliveryFee, addFee); errStr != "" {
|
||||
if errStr := policy(refDeliveryFee, refAddFee, deliveryFee); errStr != "" {
|
||||
waybillVendorName := jxutils.GetVendorName(waybillVendorID)
|
||||
errStr = fmt.Sprintf("oderID:%s创建运单出错:%s", order.VendorOrderID, errStr)
|
||||
globals.SugarLogger.Debugf("%s CallCreateWaybillPolicy failed with %s", waybillVendorName, errStr)
|
||||
|
||||
@@ -55,7 +55,7 @@ func OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.Ca
|
||||
func (c *DeliveryHandler) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(msg)
|
||||
}, msg.OrderID)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDMTPS))
|
||||
return retVal
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func (c *DeliveryHandler) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg
|
||||
}
|
||||
order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
|
||||
retVal = mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept")
|
||||
}, msg.OrderID)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDDada))
|
||||
return retVal
|
||||
}
|
||||
|
||||
@@ -81,9 +81,10 @@ func (c *DeliveryHandler) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *m
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
switch msg.Status {
|
||||
case mtpsapi.OrderStatusWaitingForSchedule:
|
||||
order.DesiredFee, _ = delivery.CalculateBillDeliveryFee(order)
|
||||
order.Status = model.WaybillStatusNew
|
||||
case mtpsapi.OrderStatusAccepted:
|
||||
order.DesiredFee, _ = delivery.CalculateBillDeliveryFee(order)
|
||||
order.DesiredFee, _ = delivery.CalculateBillDeliveryFee(order) // 美团外卖可能会丢失新运单事件,这里补一下
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
case mtpsapi.OrderStatusPickedUp:
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
@@ -113,6 +114,18 @@ func (c *DeliveryHandler) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) (re
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
|
||||
db := dao.GetDB()
|
||||
deliveryFeeInfo = &partner.WaybillFeeInfo{}
|
||||
deliveryFeeInfo.RefDeliveryFee, deliveryFeeInfo.RefAddFee, err = delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
|
||||
if err == nil {
|
||||
if _, err = c.getMTPSShopID(order, db); err == nil {
|
||||
deliveryFeeInfo.DeliveryFee = deliveryFeeInfo.RefDeliveryFee
|
||||
}
|
||||
}
|
||||
return deliveryFeeInfo, err
|
||||
}
|
||||
|
||||
// IDeliveryPlatformHandler
|
||||
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.CreateWaybillPolicy) (bill *model.Waybill, err error) {
|
||||
db := dao.GetDB()
|
||||
@@ -167,7 +180,6 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.
|
||||
if globals.EnableStoreWrite {
|
||||
result, err2 := api.MtpsAPI.CreateOrderByShop(billParams, addParams)
|
||||
if err = err2; err == nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err)
|
||||
bill = &model.Waybill{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
OrderVendorID: order.VendorID,
|
||||
@@ -176,6 +188,8 @@ func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy partner.
|
||||
WaybillVendorID: model.VendorIDMTPS,
|
||||
DesiredFee: deliveryFee,
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("测试环境不能真正创建运单")
|
||||
|
||||
@@ -33,6 +33,12 @@ const (
|
||||
PrinterStatusOnlineAbnormal = 3
|
||||
)
|
||||
|
||||
const (
|
||||
AfsApproveTypeRefund = 1 // 退款
|
||||
AfsApproveTypeReturnGoods = 2 // 退货
|
||||
AfsApproveTypeRefused = 3 // 驳回
|
||||
)
|
||||
|
||||
const (
|
||||
PrintResultSuccess = 0
|
||||
PrintResultNoPrinter = 1
|
||||
@@ -51,10 +57,11 @@ type PrinterStatus struct {
|
||||
}
|
||||
|
||||
const (
|
||||
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
|
||||
TimerTypeByPass = 1
|
||||
TimerTypeBaseNow = 2
|
||||
TimerTypeBaseStatusTime = 3
|
||||
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
|
||||
TimerTypeByPass = 1
|
||||
TimerTypeBaseNow = 2
|
||||
TimerTypeBaseStatusTime = 3
|
||||
TimerTypeBaseOrderCreatedAt = 4
|
||||
)
|
||||
|
||||
type StatusActionParams struct {
|
||||
@@ -63,15 +70,37 @@ type StatusActionParams struct {
|
||||
TimeoutGap int // 以秒为单位的随机时间,0在GetStatusActionConfig返回时表示不修改缺省
|
||||
}
|
||||
|
||||
func (s *StatusActionParams) GetRefTimeout(statusTime time.Time) (timeout time.Duration) {
|
||||
const (
|
||||
WaybillFeeErrCodeCourierNotOpen = 1 //配送门店没有启用
|
||||
WaybillFeeErrCodeCourierNotSupported = 2 //配送门店不被系统支持
|
||||
WaybillFeeErrCodeCourierForbidden = 3 //配送门店内部禁用
|
||||
WaybillFeeErrCodeCourierOthers = 10 //其它错误
|
||||
)
|
||||
|
||||
type WaybillFeeInfo struct {
|
||||
ErrCode int `json:"errCode"`
|
||||
ErrStr string `json:"errStr"`
|
||||
RefDeliveryFee int64 `json:"refDeliveryFee"`
|
||||
RefAddFee int64 `json:"refAddFee"`
|
||||
DeliveryFee int64 `json:"deliveryFee"`
|
||||
TimeoutSecond int `json:"timeoutSecond"` // 系统会自动发运单的倒计时
|
||||
Waybill *model.Waybill `json:"waybill"`
|
||||
}
|
||||
|
||||
func (s *StatusActionParams) GetRefTimeout(statusTime time.Time, orderCreatedAt time.Time) (timeout time.Duration) {
|
||||
switch s.TimerType {
|
||||
case TimerTypeBaseNow:
|
||||
timeout = s.Timeout
|
||||
case TimerTypeBaseStatusTime:
|
||||
timeout = statusTime.Sub(time.Now()) + s.Timeout
|
||||
case TimerTypeBaseOrderCreatedAt:
|
||||
timeout = orderCreatedAt.Sub(time.Now()) + s.Timeout
|
||||
default:
|
||||
timeout = 0
|
||||
}
|
||||
if timeout < 0 {
|
||||
timeout = 0
|
||||
}
|
||||
return timeout
|
||||
}
|
||||
|
||||
@@ -100,8 +129,8 @@ var (
|
||||
type IOrderManager interface {
|
||||
SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error)
|
||||
|
||||
OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error)
|
||||
OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error)
|
||||
OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error)
|
||||
OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error)
|
||||
OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error)
|
||||
OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark string) (err error)
|
||||
|
||||
@@ -113,14 +142,25 @@ type IOrderManager interface {
|
||||
LoadOrderFinancial(vendorOrderID string, vendorID int) (order *model.OrderFinancial, err error)
|
||||
LoadOrderFinancial2(vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error)
|
||||
|
||||
UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error)
|
||||
UpdateOrderStatusAndFlag(order *model.GoodsOrder) (err error)
|
||||
UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error)
|
||||
UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error)
|
||||
|
||||
LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error)
|
||||
OnOrderComments(orderCommentList []*model.OrderComment) (err error)
|
||||
|
||||
SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error)
|
||||
SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error)
|
||||
|
||||
GetOrderWaybillInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isNotEnded bool) (bills []*model.Waybill, err error)
|
||||
|
||||
// afs order
|
||||
OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error)
|
||||
OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error)
|
||||
OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error)
|
||||
LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error)
|
||||
UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error)
|
||||
|
||||
GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int)
|
||||
}
|
||||
|
||||
type IStoreManager interface {
|
||||
@@ -132,6 +172,7 @@ type IStoreManager interface {
|
||||
// 所有非以Sync,Refresh开头的函数不用自己清理sync_status标记(VendorSync统一处理)
|
||||
|
||||
type IPurchasePlatformHandler interface {
|
||||
IPurchasePlatformPromotionHandler
|
||||
GetVendorID() int
|
||||
|
||||
GetStatusFromVendorStatus(vendorStatus string) int
|
||||
@@ -167,6 +208,16 @@ type IPurchasePlatformHandler interface {
|
||||
// order.Skus要包含原始订单中的Sku信息,removedSkuList中是要移除的Sku信息
|
||||
AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error)
|
||||
|
||||
// 售后
|
||||
// // 发起全款退款
|
||||
// RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error)
|
||||
// // 发起部分退款
|
||||
// PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error)
|
||||
// 审核售后单申请
|
||||
AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error)
|
||||
// // 确认收到退货
|
||||
ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error)
|
||||
|
||||
////////
|
||||
// Store
|
||||
ReadStore(vendorStoreID string) (store *model.Store, err error)
|
||||
@@ -184,6 +235,10 @@ type IPurchasePlatformHandler interface {
|
||||
UploadImg(ctx *jxcontext.Context, imgURL string, imgData []byte, imgName string) (imgHint string, err error)
|
||||
GetStoreStatus(ctx *jxcontext.Context, vendorStoreID string) (storeStatus int, err error)
|
||||
GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error)
|
||||
|
||||
// todo 如下两个函数需要合并一下s
|
||||
GetStoresSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeIDs []int) (storeSkuList []*model.StoreSkuBind, err error)
|
||||
GetStoreSkusInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*BareStoreSkuInfo) (outStoreSkuList []*BareStoreSkuInfo, err error)
|
||||
}
|
||||
|
||||
// db *dao.DaoDB,
|
||||
@@ -219,6 +274,7 @@ type IDeliveryPlatformHandler interface {
|
||||
CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error)
|
||||
|
||||
GetVendorID() int
|
||||
GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *WaybillFeeInfo, err error)
|
||||
}
|
||||
|
||||
type IPrinterHandler interface {
|
||||
|
||||
24
business/partner/partner_act.go
Normal file
24
business/partner/partner_act.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
type IPurchasePlatformPromotionHandler interface {
|
||||
// 如果是单品级活动,actOrderRules为空
|
||||
// 如果是订单级活动,actStoreSku可以为空(表示不限制SKU)
|
||||
CreateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error)
|
||||
UpdateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error)
|
||||
// 取消整个京西活动
|
||||
CancelAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error)
|
||||
}
|
||||
|
||||
func ActStoreSku2Map(actStoreSku []*model.ActStoreSku2) (actStoreSkuMap map[int][]*model.ActStoreSku2) {
|
||||
actStoreSkuMap = make(map[int][]*model.ActStoreSku2)
|
||||
for _, storeSku := range actStoreSku {
|
||||
actStoreSkuMap[storeSku.StoreID] = append(actStoreSkuMap[storeSku.StoreID], storeSku)
|
||||
}
|
||||
return actStoreSkuMap
|
||||
}
|
||||
89
business/partner/partner_err.go
Normal file
89
business/partner/partner_err.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
ErrCodeUnknown = 1
|
||||
ErrCodeChangePriceFailed = 100
|
||||
)
|
||||
|
||||
type ErrorWithCode struct {
|
||||
errMsg string
|
||||
intCode int
|
||||
vendorID int
|
||||
storeID int
|
||||
skuID int
|
||||
}
|
||||
|
||||
func NewErrorCode(errMsg string, code, vendorID int) *ErrorWithCode {
|
||||
retVal := &ErrorWithCode{
|
||||
errMsg: errMsg,
|
||||
intCode: code,
|
||||
vendorID: vendorID,
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) SetStoreID(storeID int) {
|
||||
e.storeID = storeID
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) SetSkuID(skuID int) {
|
||||
e.skuID = skuID
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) Error() string {
|
||||
return fmt.Sprintf("平台:%s, code:%d, %s", model.VendorChineseNames[e.VendorID()], e.intCode, e.errMsg)
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) String() string {
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) Code() int {
|
||||
return e.intCode
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) ErrMsg() string {
|
||||
return e.errMsg
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) VendorID() int {
|
||||
return e.vendorID
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) StoreID() int {
|
||||
return e.storeID
|
||||
}
|
||||
|
||||
func (e *ErrorWithCode) SkuID() int {
|
||||
return e.skuID
|
||||
}
|
||||
|
||||
func IsErrChangePriceFailed(err error) *ErrorWithCode {
|
||||
if vendorErr, ok := err.(*ErrorWithCode); ok && vendorErr.Code() == ErrCodeChangePriceFailed {
|
||||
return vendorErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsErrVendorError(err error) *ErrorWithCode {
|
||||
if vendorErr, ok := err.(*ErrorWithCode); ok {
|
||||
return vendorErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddVendorInfo2Err(inErr error, vendorID int) (outErr error) {
|
||||
outErr = inErr
|
||||
if inErr != nil {
|
||||
if IsErrVendorError(inErr) == nil {
|
||||
outErr = NewErrorCode(inErr.Error(), ErrCodeUnknown, vendorID)
|
||||
}
|
||||
}
|
||||
return outErr
|
||||
}
|
||||
82
business/partner/partner_store_sku.go
Normal file
82
business/partner/partner_store_sku.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
const (
|
||||
FuncCreateStoreSkus = 1
|
||||
FuncDeleteStoreSkus = 2
|
||||
FuncUpdateStoreSkusStatus = 3
|
||||
FuncUpdateStoreSkusPrice = 4
|
||||
FuncUpdateStoreSkus = 5
|
||||
)
|
||||
|
||||
type BareStoreSkuInfo struct {
|
||||
SkuID int `json:"skuID,omitempty"`
|
||||
VendorSkuID string `json:"vendorSkuID,omitempty"`
|
||||
NameID int `json:"nameID,omitempty"`
|
||||
VendorNameID string `json:"vendorNameID,omitempty"`
|
||||
|
||||
Price int64 `json:"price,omitempty"`
|
||||
Status int `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
type BareStoreSkuInfoList []*BareStoreSkuInfo
|
||||
|
||||
func (l BareStoreSkuInfoList) GetVendorSkuIDList() (vendorSkuIDList []string) {
|
||||
for _, v := range l {
|
||||
if !dao.IsVendorThingIDEmpty(v.VendorSkuID) {
|
||||
vendorSkuIDList = append(vendorSkuIDList, v.VendorSkuID)
|
||||
}
|
||||
}
|
||||
return vendorSkuIDList
|
||||
}
|
||||
|
||||
func (l BareStoreSkuInfoList) GetVendorSkuIDIntList() (vendorSkuIDIntList []int64) {
|
||||
for _, v := range l {
|
||||
if !dao.IsVendorThingIDEmpty(v.VendorSkuID) {
|
||||
vendorSkuIDIntList = append(vendorSkuIDIntList, utils.Str2Int64(v.VendorSkuID))
|
||||
}
|
||||
}
|
||||
return vendorSkuIDIntList
|
||||
}
|
||||
|
||||
func (l BareStoreSkuInfoList) GetSkuIDList() (skuIDList []int) {
|
||||
for k, v := range l {
|
||||
if v.SkuID > 0 {
|
||||
skuIDList[k] = v.SkuID
|
||||
}
|
||||
}
|
||||
return skuIDList
|
||||
}
|
||||
|
||||
type BareCategoryInfo struct {
|
||||
VendorCatID string `json:"vendorCatID"`
|
||||
|
||||
Level int `json:"level"`
|
||||
Name string `json:"name"`
|
||||
Seq int `json:"seq,omitempty"`
|
||||
Children []*BareCategoryInfo `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
type IPurchasePlatformStoreSkuHandler interface {
|
||||
GetStoreSkusBatchSize(funcID int) int
|
||||
|
||||
CreateStoreSkus(ctx *jxcontext.Context, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (err error)
|
||||
DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*BareStoreSkuInfo) (err error)
|
||||
UpdateStoreSkusStatus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*BareStoreSkuInfo) (err error)
|
||||
UpdateStoreSkusPrice(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*BareStoreSkuInfo) (err error)
|
||||
}
|
||||
|
||||
type ISingleStoreStoreSkuHandler interface {
|
||||
IPurchasePlatformStoreSkuHandler
|
||||
|
||||
ReadStoreCategory(ctx *jxcontext.Context, vendorStoreID string) (cats []*BareCategoryInfo, err error)
|
||||
CreateStoreSkuCategory(ctx *jxcontext.Context, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error)
|
||||
UpdateStoreSkuCategory(ctx *jxcontext.Context, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error)
|
||||
DeleteStoreSkuCategory(ctx *jxcontext.Context, vendorStoreID, vendorCatID string) (err error)
|
||||
UpdateStoreSkus(ctx *jxcontext.Context, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (err error)
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
orderFmt := `
|
||||
<CB>京西菜市</CB><BR><BR>
|
||||
<CB>%s</CB><BR><BR>
|
||||
<C>手机买菜上京西</C><BR>
|
||||
<C>极速到家送惊喜</C><BR>
|
||||
--------------------------------<BR>
|
||||
@@ -59,6 +59,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
品名 数量 单价 小计<BR>
|
||||
--------------------------------<BR>`
|
||||
orderParams := []interface{}{
|
||||
globals.StoreName,
|
||||
utils.Time2Str(order.OrderCreatedAt),
|
||||
utils.Time2Str(expectedDeliveryTime),
|
||||
order.VendorOrderID,
|
||||
@@ -84,7 +85,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
<C><L><BOLD>商品质量问题请联系:</BOLD></L><BR></C>
|
||||
<C><L><BOLD>%s:%s</BOLD></L><BR></C><BR>
|
||||
<BR>
|
||||
更多信息请关注官方微信: 京西菜市<BR>
|
||||
更多信息请关注官方微信: %s<BR>
|
||||
<BR>
|
||||
<BR><BR>
|
||||
--------------------------------<BR>
|
||||
@@ -92,7 +93,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
<BR><BR>
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel)
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
orderFmt := `
|
||||
<big> 京西菜市**
|
||||
<big> %s**
|
||||
手机买菜上京西*
|
||||
极速到家送惊喜*
|
||||
------------------------------*
|
||||
@@ -58,6 +58,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
--------------------------------*
|
||||
`
|
||||
orderParams := []interface{}{
|
||||
globals.StoreName,
|
||||
utils.Time2Str(order.OrderCreatedAt),
|
||||
utils.Time2Str(expectedDeliveryTime),
|
||||
order.VendorOrderID,
|
||||
@@ -82,16 +83,80 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
<S020>商品质量问题请联系:*
|
||||
<S020>%s:%s*
|
||||
*
|
||||
更多信息请关注官方微信: 京西菜市*
|
||||
更多信息请关注官方微信: %s*
|
||||
--------------------------------
|
||||
--------------------------------
|
||||
*<BEEP13500,3,2,1>*
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel)
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), escapeString4Printer(orderParams)...)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContent2(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
orderFmt := `
|
||||
|7 %s
|
||||
|5 手机买菜上京西
|
||||
|5 极速到家送惊喜
|
||||
|5--------------------------------
|
||||
|5下单时间: %s
|
||||
|5预计送达: %s
|
||||
|5订单编号: %s
|
||||
|5
|
||||
|7%s\#%d
|
||||
|5
|
||||
|2%s
|
||||
|5客户: %s
|
||||
|5电话: %s
|
||||
|5地址: %s
|
||||
|5
|
||||
|5客户备注:
|
||||
|7%s
|
||||
|5
|
||||
|6实际支付: %s
|
||||
|5
|
||||
|5商品明细:
|
||||
|5品名 数量 单价 小计
|
||||
|5--------------------------------
|
||||
`
|
||||
orderParams := []interface{}{
|
||||
globals.StoreName,
|
||||
utils.Time2Str(order.OrderCreatedAt),
|
||||
utils.Time2Str(expectedDeliveryTime),
|
||||
order.VendorOrderID,
|
||||
jxutils.GetVendorName(order.VendorID),
|
||||
order.OrderSeq,
|
||||
order.VendorOrderID,
|
||||
order.ConsigneeName,
|
||||
order.ConsigneeMobile,
|
||||
order.ConsigneeAddress,
|
||||
order.BuyerComment,
|
||||
jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice),
|
||||
}
|
||||
for _, sku := range order.Skus {
|
||||
orderFmt += `|5%s`
|
||||
orderFmt += `|5%8s%10s%10s`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count)))
|
||||
}
|
||||
orderFmt += `
|
||||
|5
|
||||
|6共%d种%d件商品
|
||||
|5--------------------------------
|
||||
|5商品质量问题请联系:
|
||||
|5%s:%s
|
||||
|5
|
||||
|5更多信息请关注官方微信: %s
|
||||
|5--------------------------------
|
||||
|5--------------------------------
|
||||
`
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(orderFmt, escapeString4Printer(orderParams)...)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetVendorID() int {
|
||||
return model.VendorIDXiaoWM
|
||||
}
|
||||
@@ -131,10 +196,20 @@ func (c *PrinterHandler) GetPrinterStatus(ctx *jxcontext.Context, printerNumber,
|
||||
|
||||
func (c *PrinterHandler) PrintOrder(ctx *jxcontext.Context, store *model.Store, order *model.GoodsOrder) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("xiaowm PrintOrderByOrder orderID:%s", order.VendorOrderID)
|
||||
content := c.getOrderContent(order, store.Tel1)
|
||||
var content string
|
||||
if isV500(store.PrinterSN) {
|
||||
content = c.getOrderContent2(order, store.Tel1)
|
||||
} else {
|
||||
content = c.getOrderContent(order, store.Tel1)
|
||||
}
|
||||
return c.PrintMsg(ctx, store.PrinterSN, store.PrinterKey, order.VendorOrderID, content)
|
||||
}
|
||||
|
||||
func isV500(printerNo string) bool {
|
||||
printerNoNum := utils.Str2Int64WithDefault("1"+printerNo, 0)
|
||||
return printerNoNum > 1000000000
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RegisterPrinter(ctx *jxcontext.Context, printerNumber, notUsed, printerName string) (newID1, printerToken string, err error) {
|
||||
globals.SugarLogger.Debugf("xiaowm RegisterPrinter printerNumber:%s", printerNumber)
|
||||
if printerNumber == "" { //len(printerNumber) != len("7JizmSyiXNzkggaqU") {
|
||||
|
||||
@@ -33,7 +33,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
orderFmt := `
|
||||
<FS2><center>京西菜市</center></FS2>\n\n
|
||||
<FS2><center>%s</center></FS2>\n\n
|
||||
<center>手机买菜上京西</center>
|
||||
<center>极速到家送惊喜</center>\n
|
||||
--------------------------------
|
||||
@@ -57,6 +57,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
品名 数量 单价 小计\n
|
||||
--------------------------------\n`
|
||||
orderParams := []interface{}{
|
||||
globals.StoreName,
|
||||
utils.Time2Str(order.OrderCreatedAt),
|
||||
utils.Time2Str(expectedDeliveryTime),
|
||||
order.VendorOrderID,
|
||||
@@ -81,12 +82,12 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
--------------------------------\n
|
||||
<center><FH2>商品质量问题请联系:</FH2></center>
|
||||
<center><FH2>%s:%s</FH2></center>\n
|
||||
更多信息请关注官方微信: 京西菜市\n
|
||||
更多信息请关注官方微信: %s\n
|
||||
--------------------------------\n
|
||||
--------------------------------\n
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel)
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return strings.Replace(fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...), "\\n", "\r\n", -1)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
orderFmt := `
|
||||
<S2><C>京西菜市</C></S2><RN><RN>
|
||||
<S2><C>%s</C></S2><RN><RN>
|
||||
<C>手机买菜上京西</C>
|
||||
<C>极速到家送惊喜</C><RN>
|
||||
********************************
|
||||
@@ -58,6 +58,7 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
品名 数量 单价 小计<RN>
|
||||
********************************<RN>`
|
||||
orderParams := []interface{}{
|
||||
globals.StoreName,
|
||||
utils.Time2Str(order.OrderCreatedAt),
|
||||
utils.Time2Str(expectedDeliveryTime),
|
||||
order.VendorOrderID,
|
||||
@@ -82,12 +83,12 @@ func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel strin
|
||||
********************************<RN>
|
||||
<C><H2>商品质量问题请联系:</H2></C>
|
||||
<C><H2>%s:%s</H2></C><RN>
|
||||
更多信息请关注官方微信: 京西菜市<RN>
|
||||
更多信息请关注官方微信: %s<RN>
|
||||
********************************<RN>
|
||||
********************************<RN>
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel)
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...)
|
||||
}
|
||||
|
||||
|
||||
186
business/partner/purchase/ebai/act.go
Normal file
186
business/partner/purchase/ebai/act.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"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/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func actType2Ebai(actType int) int {
|
||||
if actType < model.ActOrderBegin {
|
||||
return ebaiapi.ActivityTypeDirectDown
|
||||
}
|
||||
return ebaiapi.ActivityTypeFullDiscount
|
||||
}
|
||||
|
||||
func actOrderRules2Ebai(actOrderRules []*model.ActOrderRule) (ebaiRules []*ebaiapi.ActivityRule) {
|
||||
for _, v := range actOrderRules {
|
||||
ebaiRules = append(ebaiRules, &ebaiapi.ActivityRule{
|
||||
Accords: int(jxutils.IntPrice2Standard(v.SalePrice)),
|
||||
Sale: int(jxutils.IntPrice2Standard(v.DeductPrice)),
|
||||
})
|
||||
}
|
||||
return ebaiRules
|
||||
}
|
||||
|
||||
func actStoreSu2Ebai4Add(oneStoreActSku []*model.ActStoreSku2) (skus []*ebaiapi.ActivitySkuInfo4Add) {
|
||||
for _, v := range oneStoreActSku {
|
||||
if model.IsSyncStatusNeedCreate(v.SyncStatus) {
|
||||
skus = append(skus, &ebaiapi.ActivitySkuInfo4Add{
|
||||
SkuID: v.VendorSkuID,
|
||||
SpecialPrice: v.ActPrice,
|
||||
})
|
||||
}
|
||||
}
|
||||
return skus
|
||||
}
|
||||
|
||||
func actStoreSu2Ebai4Update(oneStoreActSku []*model.ActStoreSku2) (skus []*ebaiapi.ActivitySkuInfo4Update) {
|
||||
for _, v := range oneStoreActSku {
|
||||
if model.IsSyncStatusNeedUpdate(v.SyncStatus) {
|
||||
skus = append(skus, &ebaiapi.ActivitySkuInfo4Update{
|
||||
ShopID: utils.Int2Str(v.StoreID),
|
||||
SkuID: v.VendorSkuID,
|
||||
SpecialPrice: v.ActPrice,
|
||||
})
|
||||
}
|
||||
}
|
||||
return skus
|
||||
}
|
||||
|
||||
func actStoreSu2Ebai4Delete(oneStoreActSku []*model.ActStoreSku2) (skus []string) {
|
||||
for _, v := range oneStoreActSku {
|
||||
if model.IsSyncStatusNeedDelete(v.SyncStatus) {
|
||||
skus = append(skus, v.VendorSkuID)
|
||||
}
|
||||
}
|
||||
return skus
|
||||
}
|
||||
|
||||
func act2EbaiActivity(act *model.Act2, actOrderRules []*model.ActOrderRule) (activity *ebaiapi.ActivityInfo) {
|
||||
activity = &ebaiapi.ActivityInfo{
|
||||
ActivityName: act.Name,
|
||||
ActivityType: actType2Ebai(act.Type),
|
||||
StartTime: act.BeginAt.Unix(),
|
||||
EndTime: act.EndAt.Unix(),
|
||||
ActivityDesc: act.Advertising,
|
||||
ShowCategory: act.Name,
|
||||
PromotionSkuDesc: act.Name,
|
||||
Rule: actOrderRules2Ebai(actOrderRules),
|
||||
}
|
||||
return activity
|
||||
}
|
||||
|
||||
func createOneShopAct(shopID string, activity *ebaiapi.ActivityInfo, oneStoreActSku []*model.ActStoreSku2) (ebaiActIDStr string, err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
ebaiActID, err := api.EbaiAPI.ActivityCreate(shopID, 0, 0, activity)
|
||||
if err == nil {
|
||||
ebaiActIDStr = utils.Int64ToStr(ebaiActID)
|
||||
_, err = ActivitySkuAddBatch(ebaiActID, shopID, 0, activity.ActivityType, actStoreSu2Ebai4Add(oneStoreActSku), false)
|
||||
}
|
||||
} else {
|
||||
ebaiActIDStr = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
}
|
||||
return ebaiActIDStr, err
|
||||
}
|
||||
|
||||
func ActivitySkuAddBatch(activityID int64, shopID string, baiduShopID int64, activityType int, skuList []*ebaiapi.ActivitySkuInfo4Add, isSkuIDCustom bool) (successIDs []string, err error) {
|
||||
return api.EbaiAPI.ActivitySkuAddBatch(activityID, shopID, baiduShopID, activityType, skuList, isSkuIDCustom)
|
||||
}
|
||||
|
||||
func ActivitySkuDeleteBatch(activityID int64, shopID string, baiduShopID int64, skuIDs []string, isSkuIDCustom bool) (successIDs []string, err error) {
|
||||
return api.EbaiAPI.ActivitySkuDeleteBatch(activityID, shopID, baiduShopID, skuIDs, isSkuIDCustom)
|
||||
}
|
||||
|
||||
func ActivitySkuUpdateBatch(activityID int64, actSkuInfoList []*ebaiapi.ActivitySkuInfo4Update) (faildInfoList []string, err error) {
|
||||
return api.EbaiAPI.ActivitySkuUpdateBatch(activityID, actSkuInfoList)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CreateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
activity := act2EbaiActivity(act, actOrderRules)
|
||||
if act.Type < model.ActOrderBegin {
|
||||
actStoreSkuMap := partner.ActStoreSku2Map(actStoreSku)
|
||||
task := tasksch.NewParallelTask("ebai CreateAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
store := batchItemList[0].(*model.ActStore2)
|
||||
store.VendorActID, err = createOneShopAct(utils.Int2Str(store.StoreID), activity, actStoreSkuMap[store.StoreID])
|
||||
return nil, err
|
||||
}, actStoreMap)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
if act.Type < model.ActOrderBegin {
|
||||
actStoreSkuMap := partner.ActStoreSku2Map(actStoreSku)
|
||||
if len(actStoreMap2Remove) > 0 {
|
||||
if err = c.CancelAct(ctx, parentTask, act, actStoreMap2Remove, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range actStoreMap2Remove {
|
||||
delete(actStoreSkuMap, v.StoreID)
|
||||
}
|
||||
}
|
||||
if len(actStoreMap2Add) > 0 {
|
||||
if err = c.CreateAct(ctx, parentTask, act, actOrderRules, actStoreMap2Add, actStoreSku); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range actStoreMap2Add {
|
||||
delete(actStoreSkuMap, v.StoreID)
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("ebai UpdateAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
v := batchItemList[0].(*model.ActStore2)
|
||||
if storeSkus := actStoreSkuMap[v.StoreID]; storeSkus != nil {
|
||||
if list := actStoreSu2Ebai4Delete(storeSkus); len(list) > 0 {
|
||||
if _, err = ActivitySkuDeleteBatch(utils.Str2Int64(v.VendorActID), utils.Int2Str(v.StoreID), 0, list, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if list := actStoreSu2Ebai4Add(storeSkus); len(list) > 0 {
|
||||
if _, err = ActivitySkuAddBatch(utils.Str2Int64(v.VendorActID), utils.Int2Str(v.StoreID), 0, actType2Ebai(act.Type), list, false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if list := actStoreSu2Ebai4Update(storeSkus); len(list) > 0 {
|
||||
if _, err = ActivitySkuUpdateBatch(utils.Str2Int64(v.VendorActID), list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, actStoreMap2Update)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
if act.Type < model.ActOrderBegin {
|
||||
task := tasksch.NewParallelTask("ebai DeleteAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
v := batchItemList[0].(*model.ActStore2)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ActivityDisable(utils.Str2Int64(v.VendorActID), utils.Int2Str(v.StoreID), 0, 0)
|
||||
}
|
||||
return nil, err
|
||||
}, actStoreMap)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -19,10 +19,8 @@ func OnCallbackMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse
|
||||
}
|
||||
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDEBAI))
|
||||
}
|
||||
if msg.Cmd == ebaiapi.CmdOrderPartRefund || msg.Cmd == ebaiapi.CmdOrderUserCancel || msg.Cmd == ebaiapi.CmdOrderDeliveryStatus {
|
||||
utils.CallFuncAsync(func() {
|
||||
OnFinancialMsg(msg)
|
||||
})
|
||||
if /*msg.Cmd == ebaiapi.CmdOrderPartRefund || msg.Cmd == ebaiapi.CmdOrderUserCancel || */ msg.Cmd == ebaiapi.CmdOrderDeliveryStatus {
|
||||
response = CurPurchaseHandler.OnFinancialMsg(msg)
|
||||
} else if msg.Cmd == ebaiapi.CmdShopMsgPush {
|
||||
response = CurPurchaseHandler.onShopMsgPush(msg)
|
||||
}
|
||||
@@ -31,7 +29,11 @@ func OnCallbackMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse
|
||||
}
|
||||
|
||||
func GetOrderIDFromMsg(msg *ebaiapi.CallbackMsg) string {
|
||||
if orderID := msg.Body["order_id"]; orderID != nil {
|
||||
return GetOrderIDFromMap(msg.Body)
|
||||
}
|
||||
|
||||
func GetOrderIDFromMap(orderMap map[string]interface{}) string {
|
||||
if orderID := orderMap["order_id"]; orderID != nil {
|
||||
if tryOrderID, ok := orderID.(string); ok {
|
||||
return tryOrderID
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func init() {
|
||||
|
||||
func EbaiBusStatus2JxStatus(ebaiStatus int) int {
|
||||
if ebaiStatus == ebaiapi.ShopBusStatusHaveRest || ebaiStatus == ebaiapi.ShopBusStatusSuspended {
|
||||
return model.StoreStatusClosed
|
||||
return model.StoreStatusHaveRest
|
||||
}
|
||||
return model.StoreStatusOpened
|
||||
}
|
||||
|
||||
@@ -9,25 +9,33 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) OnFinancialMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
utils.CallFuncAsync(func() {
|
||||
response = p.onFinancialMsg(msg)
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
// 存储饿百退款订单结账信息
|
||||
func OnFinancialMsg(msg *ebaiapi.CallbackMsg) (err error) {
|
||||
func (p *PurchaseHandler) onFinancialMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
var err error
|
||||
if msg.Cmd == ebaiapi.CmdOrderPartRefund { // 部分退款处理
|
||||
if utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["status"])) == ebaiapi.OrderPartRefundSuccess {
|
||||
if int(utils.MustInterface2Int64(msg.Body["status"])) == ebaiapi.OrderPartRefundSuccess {
|
||||
// 获取到部分退款订单id
|
||||
afsOrderID := utils.Interface2String(msg.Body["order_id"])
|
||||
afsOrderID := GetOrderIDFromMsg(msg)
|
||||
// 处理部分退款信息
|
||||
orderData, err2 := api.EbaiAPI.OrderPartrefundGet(afsOrderID)
|
||||
orderData, err2 := api.EbaiAPI.OrderPartRefundGet(afsOrderID)
|
||||
if err = err2; err == nil {
|
||||
afsOrder := CurPurchaseHandler.AfsOrderDetail2Financial(orderData)
|
||||
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(afsOrder)
|
||||
}
|
||||
}
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel { // 全额退款处理
|
||||
messageType := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
if utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["cancel_type"])) == ebaiapi.OrderUserCancelTypeAfterSale &&
|
||||
messageType := int(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
if int(utils.MustInterface2Int64(msg.Body["cancel_type"])) == ebaiapi.OrderUserCancelTypeAfterSale &&
|
||||
(messageType == ebaiapi.OrderUserCancelCSAgreed || messageType == ebaiapi.OrderUserCancelMerchantAgreed) {
|
||||
globals.SugarLogger.Debug(utils.Interface2String(msg.Body["order_id"])) // 获得退款订单ID,去本地数据库拿?饿百消息推送只给了订单号,但是没有查询全额退款的接口,只有部分退款才可以查询
|
||||
afsOrderID := utils.Interface2String(msg.Body["order_id"])
|
||||
afsOrderID := GetOrderIDFromMsg(msg)
|
||||
// 获得退款订单ID,去本地数据库拿?饿百消息推送只给了订单号,但是没有查询全额退款的接口,只有部分退款才可以查询
|
||||
orderFinancial, err := partner.CurOrderManager.LoadOrderFinancial(afsOrderID, model.VendorIDEBAI)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debug(utils.Format4Output(orderFinancial, false))
|
||||
@@ -45,15 +53,15 @@ func OnFinancialMsg(msg *ebaiapi.CallbackMsg) (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, msg.Cmd)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.OrderFinancial, msg *ebaiapi.CallbackMsg) (afsOrder *model.AfsOrder) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
AfsOrderID: utils.Interface2String(msg.Body["order_id"]),
|
||||
VendorOrderID: utils.Interface2String(msg.Body["order_id"]),
|
||||
AfsCreateAt: utils.Timestamp2Time(msg.Timestamp),
|
||||
AfsOrderID: GetOrderIDFromMsg(msg),
|
||||
VendorOrderID: GetOrderIDFromMsg(msg),
|
||||
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
|
||||
// BoxMoney: orderFinancial.BoxMoney, // 饿百的餐盒费已经拆分到单条Sku里面,退款时直接计算用户支付sku金额就好了
|
||||
// SkuBoxMoney: orderFinancial.SkuBoxMoney,
|
||||
FreightUserMoney: orderFinancial.FreightMoney,
|
||||
@@ -78,10 +86,9 @@ func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.Orde
|
||||
}
|
||||
for _, sku := range orderFinancial.Skus {
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
VendorOrderID2: sku.VendorOrderID2,
|
||||
AfsOrderID: sku.VendorOrderID,
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
AfsOrderID: sku.VendorOrderID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
StoreID: afsOrder.StoreID,
|
||||
@@ -106,8 +113,8 @@ func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.Orde
|
||||
func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interface{}) (afsOrder *model.AfsOrder) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
AfsOrderID: utils.Interface2String(orderData["order_id"]),
|
||||
VendorOrderID: utils.Interface2String(orderData["order_id"]),
|
||||
AfsOrderID: GetOrderIDFromMap(orderData),
|
||||
VendorOrderID: GetOrderIDFromMap(orderData),
|
||||
}
|
||||
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
|
||||
if err == nil {
|
||||
@@ -125,7 +132,7 @@ func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interfac
|
||||
afsOrder.PmRefundMoney = orderFinancial.PmMoney - utils.MustInterface2Int64(orderData["commission"])
|
||||
} else {
|
||||
// 此处应该报错
|
||||
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrderFinancial", afsOrder.VendorOrderID)
|
||||
// globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrderFinancial", afsOrder.VendorOrderID)
|
||||
err = nil
|
||||
}
|
||||
if orderData["refund_detail"] != nil {
|
||||
@@ -149,7 +156,7 @@ func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interfac
|
||||
afsOrder.PmSubsidyMoney += orderSkuFinancial.PmSubsidyMoney
|
||||
}
|
||||
if len(refundDetail) > 0 {
|
||||
afsOrder.AfsCreateAt = getTimeFromInterface(refundDetail[0].(map[string]interface{})["apply_time"])
|
||||
afsOrder.AfsCreatedAt = getTimeFromInterface(refundDetail[0].(map[string]interface{})["apply_time"])
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, orderID:%s have no refund_detail", afsOrder.VendorOrderID)
|
||||
}
|
||||
@@ -168,7 +175,7 @@ func (p *PurchaseHandler) OnOrderDetail(result map[string]interface{}, operation
|
||||
// func (p *PurchaseHandler) GetTrueEbaiOrder(result1 map[string]interface{}) (result2 map[string]interface{}) {
|
||||
// order := result1["order"].(map[string]interface{})
|
||||
// if utils.MustInterface2Int64(order["down_flag"]) == 1 {
|
||||
// result, err := api.EbaiAPI.OrderGet(utils.Interface2String(order["order_id"]))
|
||||
// result, err := api.EbaiAPI.OrderGet(GetOrderIDFromMap(order))
|
||||
// if err == nil {
|
||||
// return p.GetTrueEbaiOrder(result)
|
||||
// }
|
||||
@@ -181,7 +188,7 @@ func (p *PurchaseHandler) OrderDetail2Financial(result map[string]interface{}) (
|
||||
VendorID: model.VendorIDEBAI,
|
||||
}
|
||||
order1 := result["order"].(map[string]interface{})
|
||||
orderFinancial.VendorOrderID = utils.Interface2String(order1["order_id"])
|
||||
orderFinancial.VendorOrderID = GetOrderIDFromMap(order1)
|
||||
orderFinancial.VendorOrderID2 = utils.Interface2String(order1["eleme_order_id"])
|
||||
// orderFinancial.DeliveryConfirmTime = getTimeFromInterface(order1["finished_time"])
|
||||
orderFinancial.TotalDiscountMoney = utils.MustInterface2Int64(order1["discount_fee"])
|
||||
@@ -224,9 +231,8 @@ func (p *PurchaseHandler) OrderDetail2Financial(result map[string]interface{}) (
|
||||
for _, y := range x.([]interface{}) {
|
||||
product := y.(map[string]interface{})
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
VendorOrderID2: orderFinancial.VendorOrderID2,
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
// OrderFinancialID: orderFinancial.VendorOrderID,
|
||||
// ConfirmTime: getTimeFromInterface(order1["create_time"]),
|
||||
VendorStoreID: utils.Interface2String(shop["baidu_shop_id"]),
|
||||
|
||||
@@ -27,7 +27,7 @@ func TestOnFinancialMsg(t *testing.T) {
|
||||
// msg.Body["type"] = json.Number("40")
|
||||
// msg.Body["cancel_type"] = json.Number("2")
|
||||
|
||||
res := OnFinancialMsg(msg)
|
||||
res := CurPurchaseHandler.onAfsOrderMsg(msg)
|
||||
fmt.Println(res)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
@@ -19,7 +21,8 @@ import (
|
||||
|
||||
const (
|
||||
// acceptOrderDelay = 180 * time.Second
|
||||
pickupOrderDelay = 260 * time.Second
|
||||
// pickupOrderDelay = 260 * time.Second
|
||||
pickupOrderDelay = 1 * time.Second
|
||||
|
||||
callDeliveryDelay = 10 * time.Minute
|
||||
callDeliveryDelayGap = 30
|
||||
@@ -34,6 +37,7 @@ const (
|
||||
|
||||
var (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
ebaiapi.CmdOrderCreate: model.OrderStatusNew,
|
||||
ebaiapi.OrderStatusNew: model.OrderStatusNew,
|
||||
fakeAcceptOrder: model.OrderStatusAccepted,
|
||||
ebaiapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
|
||||
@@ -46,6 +50,11 @@ var (
|
||||
fakeUserApplyCancel: model.OrderStatusApplyCancel,
|
||||
fakeUserUndoApplyCancel: model.OrderStatusUndoApplyCancel,
|
||||
}
|
||||
|
||||
skuActTypeMap = map[string]int{
|
||||
ebaiapi.OrderSkuDiscountTypeZhe: 1,
|
||||
ebaiapi.OrderSkuDiscountTypeReduce: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) GetStatusFromVendorStatus(vendorStatus string) int {
|
||||
@@ -68,6 +77,65 @@ func (p *PurchaseHandler) getOrder(vendorOrderID string) (order *model.GoodsOrde
|
||||
return order, result, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetOrder4PartRefund(vendorOrderID string) (order *model.GoodsOrder, err error) {
|
||||
taskIDs := []int{1, 2}
|
||||
var (
|
||||
err1, err2 error
|
||||
result1, result2 map[string]interface{}
|
||||
)
|
||||
task := tasksch.NewParallelTask("GetOrder4PartRefund", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
taskID := batchItemList[0].(int)
|
||||
if taskID == 1 {
|
||||
result1, err1 = api.EbaiAPI.OrderGet(vendorOrderID)
|
||||
} else if taskID == 2 {
|
||||
result2, err2 = api.EbaiAPI.OrderPartRefundGet(vendorOrderID)
|
||||
}
|
||||
return nil, nil
|
||||
}, taskIDs)
|
||||
task.Run()
|
||||
task.GetResult(0)
|
||||
if err1 == nil {
|
||||
order = p.Map2Order(result1)
|
||||
if err2 == nil {
|
||||
order.Skus = p.partRefund2OrderDetailSkuList(utils.Interface2String(result2["order_id"]), result2["order_detail"])
|
||||
order.ActualPayPrice = utils.MustInterface2Int64(result2["user_fee"])
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
} else if err2Ext, ok := err2.(*utils.ErrorWithCode); !ok || err2Ext.IntCode() != ebaiapi.ErrOrderIsNotPartRefund {
|
||||
err = err2
|
||||
}
|
||||
} else {
|
||||
err = err1
|
||||
}
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) partRefund2OrderDetailSkuList(orderID string, orderDetail2 interface{}) (skuList []*model.OrderSku) {
|
||||
orderDetail := orderDetail2.([]interface{})
|
||||
for _, product2 := range orderDetail {
|
||||
product := product2.(map[string]interface{})
|
||||
skuName := product["name"].(string)
|
||||
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
|
||||
number := int(utils.MustInterface2Int64(product["number"]))
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDEBAI,
|
||||
Count: number,
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
|
||||
VendorSkuID: utils.Interface2String(product[ebaiapi.KeySkuID]),
|
||||
SkuName: skuName,
|
||||
// Weight: int(utils.Interface2Int64WithDefault(product["total_weight"], 0)) / number, // 退单这里的total_weight有BUG,这里的total_weight还是没有退单时的值
|
||||
VendorPrice: utils.MustInterface2Int64(product["product_price"]),
|
||||
}
|
||||
sku.SalePrice, _, sku.StoreSubName = getSkuSalePrice(product)
|
||||
if sku.Weight == 0 {
|
||||
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
|
||||
}
|
||||
skuList = append(skuList, sku)
|
||||
}
|
||||
return skuList
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
result := orderData
|
||||
shopMap := result["shop"].(map[string]interface{})
|
||||
@@ -93,7 +161,7 @@ func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo
|
||||
StatusTime: getTimeFromInterface(orderMap["create_time"]),
|
||||
OriginalData: string(utils.MustMarshal(result)),
|
||||
ActualPayPrice: utils.MustInterface2Int64(orderMap["user_fee"]),
|
||||
Skus: []*model.OrderSku{},
|
||||
TotalShopMoney: utils.MustInterface2Int64(orderMap["shop_fee"]),
|
||||
}
|
||||
if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) {
|
||||
order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 饿百要求在5分钟内拣货,不然订单会被取消
|
||||
@@ -134,33 +202,58 @@ func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo
|
||||
product := product2.(map[string]interface{})
|
||||
skuName := product["product_name"].(string)
|
||||
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
|
||||
productAmount := int(utils.MustInterface2Int64(product["product_amount"]))
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: model.VendorIDEBAI,
|
||||
Count: int(utils.MustInterface2Int64(product["product_amount"])),
|
||||
Count: productAmount,
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
|
||||
VendorSkuID: utils.Interface2String(product["baidu_product_id"]),
|
||||
SkuName: skuName,
|
||||
Weight: jxutils.FormatSkuWeight(specQuality, specUnit), // 订单信息里没有重量,只有名字里尝试找
|
||||
SalePrice: utils.MustInterface2Int64(product["product_price"]),
|
||||
// PromotionType: int(utils.MustInterface2Int64(product["promotionType"])),
|
||||
Weight: int(utils.Interface2Int64WithDefault(product["total_weight"], 0)) / productAmount,
|
||||
VendorPrice: utils.MustInterface2Int64(product["product_price"]),
|
||||
}
|
||||
var baiduRate int64
|
||||
sku.SalePrice, baiduRate, sku.StoreSubName = getSkuSalePrice(product)
|
||||
order.PmSubsidyMoney += baiduRate
|
||||
if sku.Weight == 0 {
|
||||
sku.Weight = 222 // 如果名字里找不到缺省给半斤左右的一个特别值
|
||||
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
|
||||
}
|
||||
// if product["isGift"].(bool) {
|
||||
// sku.SkuType = 1
|
||||
// }
|
||||
order.Skus = append(order.Skus, sku)
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
// setOrederDetailFee(result, order)
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
return order
|
||||
}
|
||||
|
||||
func getSkuSalePrice(product map[string]interface{}) (salePrice, baiduRate int64, vendorActType string) {
|
||||
var product2 *ebaiapi.OrderProductInfo
|
||||
if err := utils.Map2StructByJson(product, &product2, true); err != nil {
|
||||
return utils.MustInterface2Int64(product["product_price"]), 0, ""
|
||||
}
|
||||
return getSkuSalePrice2(product2)
|
||||
}
|
||||
|
||||
func getSkuSalePrice2(product *ebaiapi.OrderProductInfo) (salePrice, baiduRate int64, vendorActType string) {
|
||||
salePrice = int64(product.ProductPrice)
|
||||
if product.ProductSubsidy != nil {
|
||||
for _, v := range product.ProductSubsidy.DiscountDetail {
|
||||
if skuActTypeMap[v.Type] == 1 {
|
||||
skuCount := product.ProductAmount
|
||||
if skuCount == 0 {
|
||||
skuCount = product.Number
|
||||
}
|
||||
salePrice -= int64(math.Round(float64(v.BaiduRate+v.ShopRate) / float64(skuCount))) // 饿百同一SKU的优惠与非优惠没有拆开,平均摊销处理
|
||||
vendorActType = v.Type
|
||||
}
|
||||
baiduRate += int64(v.BaiduRate)
|
||||
}
|
||||
}
|
||||
return salePrice, baiduRate, vendorActType
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
if isAcceptIt {
|
||||
@@ -239,24 +332,38 @@ func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName
|
||||
|
||||
//
|
||||
func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
|
||||
if ebaiapi.CmdOrderCreate == msg.Cmd {
|
||||
retVal = c.onOrderNew(msg)
|
||||
if c.isAfsMsg(msg) {
|
||||
retVal = c.OnAfsOrderMsg(msg)
|
||||
} else {
|
||||
status := c.callbackMsg2Status(msg)
|
||||
var err error
|
||||
if status != nil {
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
|
||||
return nil
|
||||
}
|
||||
if ebaiapi.CmdOrderCreate == msg.Cmd {
|
||||
retVal = c.onOrderNew(msg, status)
|
||||
} else {
|
||||
var err error
|
||||
if status != nil {
|
||||
if status.Status == model.OrderStatusAdjust {
|
||||
var order *model.GoodsOrder
|
||||
if order, err = c.GetOrder4PartRefund(GetOrderIDFromMsg(msg)); err == nil {
|
||||
err = partner.CurOrderManager.OnOrderAdjust(order, status)
|
||||
}
|
||||
} else {
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
}
|
||||
}
|
||||
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
|
||||
}
|
||||
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderNew(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
func (c *PurchaseHandler) onOrderNew(msg *ebaiapi.CallbackMsg, orderStatus *model.OrderStatus) (response *ebaiapi.CallbackResponse) {
|
||||
vendorOrderID := GetOrderIDFromMsg(msg)
|
||||
order, orderMap, err := c.getOrder(vendorOrderID)
|
||||
if err == nil {
|
||||
if err = partner.CurOrderManager.OnOrderNew(order, order.VendorStatus); err == nil {
|
||||
if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.OnOrderDetail(orderMap, partner.CreatedPeration)
|
||||
})
|
||||
@@ -279,27 +386,24 @@ func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderSta
|
||||
VendorStatus: msg.Cmd,
|
||||
}
|
||||
if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||||
msgType := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
cancelType := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["cancel_type"]))
|
||||
orderStatus.Remark = utils.Interface2String(msg.Body["cancel_reason"])
|
||||
orderStatus.VendorStatus = msg.Cmd + "-" + msgType
|
||||
if additionReason := utils.Interface2String(msg.Body["addition_reason"]); additionReason != "" {
|
||||
orderStatus.Remark += ",额外原因:" + additionReason
|
||||
}
|
||||
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"]))
|
||||
orderStatus.Remark = buildFullReason(utils.Interface2String(msg.Body["cancel_reason"]), utils.Interface2String(msg.Body["addition_reason"]))
|
||||
orderStatus.VendorStatus = msg.Cmd + "-" + utils.Int2Str(msgType)
|
||||
if cancelType == ebaiapi.OrderUserCancelTypeBeforeSale {
|
||||
if msgType == ebaiapi.OrderUserCancelApply {
|
||||
if msgType == ebaiapi.OrderUserCancelApply ||
|
||||
msgType == ebaiapi.OrderUserCancelCSIntervene {
|
||||
orderStatus.VendorStatus = fakeUserApplyCancel
|
||||
} else if msgType == ebaiapi.OrderUserCancelInvalid {
|
||||
} else if msgType == ebaiapi.OrderUserCancelInvalid ||
|
||||
msgType == ebaiapi.OrderUserCancelMerchantRefused ||
|
||||
msgType == ebaiapi.OrderUserCancelCSRefused {
|
||||
orderStatus.VendorStatus = fakeUserUndoApplyCancel
|
||||
}
|
||||
}
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||||
msgType := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
status := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["status"]))
|
||||
orderStatus.Remark = utils.Interface2String(msg.Body["reason"])
|
||||
if additionReason := utils.Interface2String(msg.Body["addition_reason"]); additionReason != "" {
|
||||
orderStatus.Remark += ",额外原因:" + additionReason
|
||||
}
|
||||
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
status := int(utils.MustInterface2Int64(msg.Body["status"]))
|
||||
orderStatus.Remark = buildFullReason(utils.Interface2String(msg.Body["reason"]), utils.Interface2String(msg.Body["addition_reason"]))
|
||||
if msgType == ebaiapi.OrderPartRefuncTypeMerchant && status == ebaiapi.OrderPartRefundSuccess {
|
||||
orderStatus.VendorStatus = fakeOrderAdjustFinished
|
||||
}
|
||||
@@ -315,6 +419,14 @@ func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderSta
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func buildFullReason(reason, addReason string) (fullReason string) {
|
||||
fullReason = reason
|
||||
if addReason != "" {
|
||||
fullReason += ",额外原因:" + addReason
|
||||
}
|
||||
return fullReason
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *partner.StatusActionParams) {
|
||||
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusAccepted {
|
||||
params = &partner.StatusActionParams{ // PickDeadline没有设置时才有效,饿百要求在5分钟内拣货,不然订单会被取消
|
||||
@@ -398,15 +510,21 @@ func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.Goods
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
var skuList []*ebaiapi.RefundSku
|
||||
for _, sku := range removedSkuList {
|
||||
skuList = append(skuList, &ebaiapi.RefundSku{
|
||||
CustomeSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)),
|
||||
Number: utils.Int2Str(sku.Count),
|
||||
})
|
||||
// 饿百必须要确认订单后才能调整单
|
||||
if order.Status < model.OrderStatusFinishedPickup {
|
||||
err = c.PickupGoods(order, false, ctx.GetUserName())
|
||||
}
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, skuList)
|
||||
if err == nil {
|
||||
var skuList []*ebaiapi.RefundSku
|
||||
for _, sku := range removedSkuList {
|
||||
skuList = append(skuList, &ebaiapi.RefundSku{
|
||||
CustomeSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)),
|
||||
Number: utils.Int2Str(sku.Count),
|
||||
})
|
||||
}
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, skuList)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
189
business/partner/purchase/ebai/order_afs.go
Normal file
189
business/partner/purchase/ebai/order_afs.go
Normal file
@@ -0,0 +1,189 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"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/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
AfsVendorStatus2Status4PartRefundMap = map[int]int{
|
||||
ebaiapi.OrderPartRefundApply: model.AfsOrderStatusWait4Approve,
|
||||
ebaiapi.OrderPartRefundSuccess: model.AfsOrderStatusFinished,
|
||||
ebaiapi.OrderPartRefundUserApplyArbitration: model.OrderStatusUnknown, // 是否是中间状态
|
||||
ebaiapi.OrderPartRefundFailed: model.AfsOrderStatusFailed,
|
||||
ebaiapi.OrderPartRefundMerchantRefused: model.AfsOrderStatusFailed, // 是否是中间状态
|
||||
}
|
||||
AfsVendorStatus2Status4UserCancel = map[int]int{
|
||||
ebaiapi.OrderUserCancelApply: model.AfsOrderStatusWait4Approve,
|
||||
ebaiapi.OrderUserCancelCSIntervene: model.OrderStatusUnknown,
|
||||
ebaiapi.OrderUserCancelCSRefused: model.AfsOrderStatusFailed,
|
||||
ebaiapi.OrderUserCancelCSAgreed: model.AfsOrderStatusFinished,
|
||||
ebaiapi.OrderUserCancelMerchantRefused: model.AfsOrderStatusFailed,
|
||||
ebaiapi.OrderUserCancelMerchantAgreed: model.AfsOrderStatusFinished,
|
||||
ebaiapi.OrderUserCancelInvalid: model.AfsOrderStatusFailed,
|
||||
}
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) isAfsMsg(msg *ebaiapi.CallbackMsg) bool {
|
||||
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||||
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
return msgType == ebaiapi.OrderPartRefuncTypeCustomer
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||||
cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"]))
|
||||
return cancelType == ebaiapi.OrderUserCancelTypeAfterSale
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) OnAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
retVal = c.onAfsOrderMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(GetOrderIDFromMsg(msg), model.VendorIDEBAI))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
|
||||
if orderStatus := c.callbackAfsMsg2Status(msg); orderStatus != nil {
|
||||
var err error
|
||||
if orderStatus.Status == model.AfsOrderStatusWait4Approve || orderStatus.Status == model.AfsOrderStatusNew {
|
||||
var afsOrder *model.AfsOrder
|
||||
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||||
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorOrderID: orderStatus.RefVendorOrderID,
|
||||
VendorStoreID: "",
|
||||
StoreID: 0,
|
||||
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
|
||||
VendorAppealType: "",
|
||||
AppealType: model.AfsAppealTypeRefund,
|
||||
VendorReasonType: partRefundData.ReasonType,
|
||||
ReasonType: c.convertAfsReasonType(partRefundData.ReasonType),
|
||||
ReasonDesc: utils.LimitUTF8StringLen(buildFullReason(partRefundData.Reason, partRefundData.AdditionReason), 1024),
|
||||
ReasonImgList: utils.LimitUTF8StringLen(strings.Join(partRefundData.Photos, ","), 1024),
|
||||
RefundType: model.AfsTypePartRefund,
|
||||
|
||||
// FreightUserMoney: afsInfo.OrderFreightMoney,
|
||||
// AfsFreightMoney: afsInfo.AfsFreight,
|
||||
// BoxMoney: afsInfo.PackagingMoney,
|
||||
// TongchengFreightMoney: afsInfo.TongchengFreightMoney,
|
||||
// SkuBoxMoney: afsInfo.MealBoxMoney,
|
||||
}
|
||||
for _, sku := range partRefundData.RefundProducts {
|
||||
orderSku := &model.OrderSkuFinancial{
|
||||
// VendorID: model.VendorIDEBAI,
|
||||
// AfsOrderID: afsOrder.AfsOrderID,
|
||||
// VendorOrderID: afsOrder.VendorOrderID,
|
||||
// VendorStoreID: afsOrder.VendorStoreID,
|
||||
// StoreID: afsOrder.StoreID,
|
||||
// IsAfsOrder: 1,
|
||||
|
||||
Count: sku.Number,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorSkuID: sku.SkuID,
|
||||
SkuID: int(utils.Str2Int64WithDefault(sku.CustomSkuID, 0)),
|
||||
Name: sku.Name,
|
||||
UserMoney: sku.TotalRefund,
|
||||
PmSkuSubsidyMoney: sku.ShopEleRefund,
|
||||
}
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||||
}
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||||
if orderFinancial, err2 := partner.CurOrderManager.LoadOrderFinancial(orderStatus.RefVendorOrderID, model.VendorIDEBAI); err2 == nil {
|
||||
afsOrder = c.OrderFinancialDetail2Refund(orderFinancial, msg)
|
||||
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
|
||||
afsOrder.AfsOrderID = orderStatus.VendorOrderID
|
||||
afsOrder.RefundType = model.AfsTypeFullRefund
|
||||
afsOrder.AppealType = model.AfsAppealTypeRefund
|
||||
afsOrder.VendorReasonType = ""
|
||||
afsOrder.ReasonType = model.AfsReasonNotOthers
|
||||
afsOrder.ReasonDesc = utils.LimitUTF8StringLen(buildFullReason(cancelData.CancelReason, cancelData.AdditionReason), 1024)
|
||||
afsOrder.ReasonImgList = utils.LimitUTF8StringLen(strings.Join(cancelData.Pictures, ","), 1024)
|
||||
}
|
||||
}
|
||||
if afsOrder != nil {
|
||||
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
|
||||
}
|
||||
} else {
|
||||
err = partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
|
||||
}
|
||||
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) convertAfsReasonType(vendorReasonType string) int8 {
|
||||
return model.AfsReasonNotOthers
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4PartRefund(vendorStatus int) int {
|
||||
return AfsVendorStatus2Status4PartRefundMap[vendorStatus]
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4UserCancel(vendorStatus int) int {
|
||||
return AfsVendorStatus2Status4UserCancel[vendorStatus]
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackAfsMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) {
|
||||
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||||
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
|
||||
orderStatus = &model.OrderStatus{
|
||||
VendorOrderID: partRefundData.RefundID, // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: model.VendorIDEBAI,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: utils.Int64ToStr(partRefundData.OrderID),
|
||||
RefVendorID: model.VendorIDEBAI,
|
||||
VendorStatus: utils.Int2Str(partRefundData.Status),
|
||||
Status: c.GetAfsStatusFromVendorStatus4PartRefund(partRefundData.Status),
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
Remark: buildFullReason(partRefundData.Reason, partRefundData.AdditionReason),
|
||||
}
|
||||
if orderStatus.Status == model.AfsOrderStatusWait4Approve && partRefundData.Type != ebaiapi.OrderPartRefuncTypeCustomer {
|
||||
orderStatus.Status = model.AfsOrderStatusNew
|
||||
}
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||||
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
|
||||
orderStatus = &model.OrderStatus{
|
||||
VendorOrderID: utils.Int64ToStr(cancelData.OrderID), // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: model.VendorIDEBAI,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: utils.Int64ToStr(cancelData.OrderID),
|
||||
RefVendorID: model.VendorIDEBAI,
|
||||
VendorStatus: utils.Int2Str(cancelData.Type),
|
||||
Status: c.GetAfsStatusFromVendorStatus4UserCancel(cancelData.Type),
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
Remark: buildFullReason(cancelData.CancelReason, cancelData.AdditionReason),
|
||||
}
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
// 审核售后单申请
|
||||
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
err = api.EbaiAPI.OrderDisagreeRefund(order.VendorOrderID, reason)
|
||||
} else {
|
||||
err = api.EbaiAPI.OrderAgreeRefund(order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 确认收到退货
|
||||
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
|
||||
err = fmt.Errorf("内部错误,饿百平台不支持确认收到退货操作")
|
||||
return err
|
||||
}
|
||||
16
business/partner/purchase/ebai/order_test.go
Normal file
16
business/partner/purchase/ebai/order_test.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
)
|
||||
|
||||
func TestGetOrder4PartRefund(t *testing.T) {
|
||||
order, err := new(PurchaseHandler).GetOrder4PartRefund("1556529608021993938")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
t.Log(utils.Format4Output(order, false))
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
params["category1"] = ""
|
||||
params["category2"] = ""
|
||||
params["category3"] = ""
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
intVendorStoreID, err2 := api.EbaiAPI.ShopCreate(params)
|
||||
if err = err2; err == nil {
|
||||
return utils.Int64ToStr(intVendorStoreID), err
|
||||
@@ -160,7 +160,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
if err = dao.GetRows(db, &stores, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil {
|
||||
for _, store := range stores {
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(params, false))
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
shopID := 0
|
||||
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
|
||||
shopID = store.ID
|
||||
@@ -181,10 +181,10 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
}
|
||||
if err == nil {
|
||||
mergeStatus := jxutils.MergeStoreStatus(store.Status, store.EbaiStoreStatus)
|
||||
if store2.Status != mergeStatus {
|
||||
if !isStoreStatusSame(store2.Status, mergeStatus) {
|
||||
if mergeStatus == model.StoreStatusOpened {
|
||||
err = api.EbaiAPI.ShopOpen("", utils.Str2Int64(store.VendorStoreID))
|
||||
} else if mergeStatus == model.StoreStatusClosed {
|
||||
} else if mergeStatus == model.StoreStatusHaveRest || mergeStatus == model.StoreStatusClosed {
|
||||
err = api.EbaiAPI.ShopClose("", utils.Str2Int64(store.VendorStoreID))
|
||||
} else if mergeStatus == model.StoreStatusDisabled {
|
||||
err = api.EbaiAPI.ShopOffline("", utils.Str2Int64(store.VendorStoreID))
|
||||
@@ -204,10 +204,9 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// todo 饿百 开店审核通过后不允许修改商户信息
|
||||
// params := genStoreMapFromStore(store)
|
||||
// if err = api.EbaiAPI.ShopUpdate(params); err == nil {
|
||||
// }
|
||||
params := genStoreMapFromStore(store)
|
||||
if err = api.EbaiAPI.ShopUpdate(params); err == nil {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,6 +214,16 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
return err
|
||||
}
|
||||
|
||||
func isStoreStatusSame(status1, status2 int) bool {
|
||||
if status1 == model.StoreStatusClosed {
|
||||
status1 = model.StoreStatusHaveRest
|
||||
}
|
||||
if status2 == model.StoreStatusClosed {
|
||||
status2 = model.StoreStatusHaveRest
|
||||
}
|
||||
return status1 == status2
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("ebai RefreshAllStoresID")
|
||||
const batchSize = 50
|
||||
@@ -248,7 +257,7 @@ func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask
|
||||
shopIDs[k] = utils.GetUUID()
|
||||
}
|
||||
}
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopIDBatchUpdate(baiduShopIDs, shopIDs)
|
||||
}
|
||||
return nil, err
|
||||
@@ -311,7 +320,7 @@ func EbaiDeliveryRegion2Jx(deliveryRegion interface{}) string {
|
||||
func JxDeliveryRegion2Ebai(store *model.Store) (deliveryRegion interface{}) {
|
||||
rangeStr := strings.Trim(store.DeliveryRange, ";")
|
||||
if store.DeliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
if utils.Str2Int64(store.DeliveryRange) > 100 { // todo 如果小于100米,表示禁用,不更新
|
||||
if utils.Str2Int64WithDefault(store.DeliveryRange, 0) > 100 { // todo 如果小于100米,表示禁用,不更新
|
||||
rangeStr = jxutils.GetPolygonFromCircleStr(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat), utils.Str2Float64(store.DeliveryRange), 8)
|
||||
} else {
|
||||
rangeStr = ""
|
||||
@@ -363,19 +372,20 @@ func JxBusinessTime2Ebai(store *model.Store) interface{} {
|
||||
|
||||
func genStoreMapFromStore(store *tEbaiStoreInfo) map[string]interface{} {
|
||||
params := map[string]interface{}{
|
||||
"phone": store.Tel1,
|
||||
"business_time": JxBusinessTime2Ebai(&store.Store),
|
||||
}
|
||||
// if store.Tel2 != "" {
|
||||
// params["ivr_phone"] = store.Tel2
|
||||
// }
|
||||
// params["phone"] = store.Tel1
|
||||
if store.VendorStoreID != "" {
|
||||
params["baidu_shop_id"] = store.VendorStoreID
|
||||
}
|
||||
if store.Tel2 != "" {
|
||||
params["ivr_phone"] = store.Tel2
|
||||
if store.SyncStatus&(model.SyncFlagNewMask /*|model.SyncFlagStoreName*/) != 0 {
|
||||
params["name"] = jxutils.ComposeStoreName(store.Name, model.VendorIDEBAI)
|
||||
}
|
||||
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
|
||||
// params["name"] = jxutils.ComposeStoreName(store.Name, model.VendorIDEBAI)
|
||||
}
|
||||
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 {
|
||||
// todo 饿百 开店审核通过后不允许修改商户信息
|
||||
if store.SyncStatus&(model.SyncFlagNewMask /*|model.SyncFlagStoreAddress*/) != 0 {
|
||||
params["longitude"] = jxutils.IntCoordinate2Standard(store.Lng)
|
||||
params["latitude"] = jxutils.IntCoordinate2Standard(store.Lat)
|
||||
params["address"] = store.Address
|
||||
@@ -415,7 +425,7 @@ func (c *PurchaseHandler) onShopMsgPush(msg *ebaiapi.CallbackMsg) (response *eba
|
||||
if int(utils.ForceInterface2Int64(msg.Body["business_ele"])) == 1 {
|
||||
storeStatus = model.StoreStatusOpened
|
||||
} else {
|
||||
storeStatus = model.StoreStatusClosed
|
||||
storeStatus = model.StoreStatusHaveRest
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
@@ -423,3 +433,11 @@ func (c *PurchaseHandler) onShopMsgPush(msg *ebaiapi.CallbackMsg) (response *eba
|
||||
}
|
||||
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetShopHealthInfo(vendorShopID string) (shopHealthInfo map[string]interface{}, err error) {
|
||||
result, err := api.EbaiAPI.GetShopHealthByDetail(utils.Str2Int64(vendorShopID))
|
||||
if err == nil {
|
||||
shopHealthInfo = utils.Struct2FlatMap(result)
|
||||
}
|
||||
return shopHealthInfo, err
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
@@ -23,7 +25,6 @@ const (
|
||||
type tStoreSkuFullInfo struct {
|
||||
model.StoreSkuBind
|
||||
|
||||
SkuID int `orm:"column(sku_id)"`
|
||||
NameID int `orm:"column(name_id)"`
|
||||
|
||||
SpecQuality float32 `json:"specQuality"`
|
||||
@@ -31,14 +32,15 @@ type tStoreSkuFullInfo struct {
|
||||
Weight int `json:"weight"` // 重量/质量,单位为克,当相应的SkuName的SpecUnit为g或kg时,必须等于SpecQuality
|
||||
SkuStatus int
|
||||
|
||||
Prefix string `orm:"size(255)" json:"prefix"`
|
||||
Name string `orm:"size(255);index" json:"name"`
|
||||
Comment string `orm:"size(255)" json:"comment"`
|
||||
IsGlobal int8 `orm:"default(1)" json:"isGlobal"` // 是否是全部(全国)可见,如果否的话,可见性由SkuPlace决定
|
||||
Unit string `orm:"size(8)" json:"unit"`
|
||||
Img string `orm:"size(255)" json:"img"`
|
||||
PlaceStr string
|
||||
Upc string
|
||||
Prefix string `orm:"size(255)" json:"prefix"`
|
||||
Name string `orm:"size(255);index" json:"name"`
|
||||
Comment string `orm:"size(255)" json:"comment"`
|
||||
IsGlobal int8 `orm:"default(1)" json:"isGlobal"` // 是否是全部(全国)可见,如果否的话,可见性由SkuPlace决定
|
||||
Unit string `orm:"size(8)" json:"unit"`
|
||||
Img string `orm:"size(255)" json:"img"`
|
||||
PlaceStr string
|
||||
Upc string
|
||||
DescImgEbai string
|
||||
|
||||
CatName string `orm:"size(255)"`
|
||||
|
||||
@@ -54,7 +56,8 @@ type tStoreSkuFullInfo struct {
|
||||
EbaiCat2ID int64 `orm:"column(ebai_cat2_id)"`
|
||||
EbaiCat3ID int64 `orm:"column(ebai_cat3_id)"`
|
||||
|
||||
PricePercentage int
|
||||
PricePercentage int
|
||||
CatPricePercentage int
|
||||
}
|
||||
|
||||
type tStoreCatInfo struct {
|
||||
@@ -80,23 +83,23 @@ var (
|
||||
|
||||
func (p *PurchaseHandler) getDirtyStoreSkus(db *dao.DaoDB, storeID int, skuIDs []int) (storeSkuInfoList []*tStoreSkuFullInfo, err error) {
|
||||
sql := `
|
||||
SELECT t8.price_percentage, t1.*, t2.id sku_id, t2.spec_quality, t2.spec_unit, t2.weight, t2.status sku_status,
|
||||
t3.id name_id, t3.prefix, t3.name, t2.comment, t3.is_global, t3.unit, IF(t3.img_ebai <> '', t3.img_ebai, t3.img) img, t3.upc,
|
||||
t4.name cat_name,
|
||||
SELECT t8.price_percentage, t1.*, t2.spec_quality, t2.spec_unit, t2.weight, t2.status sku_status,
|
||||
t3.id name_id, t3.prefix, t3.name, t2.comment, t3.is_global, t3.unit, IF(t3.img_ebai <> '', t3.img_ebai, t3.img) img, t3.upc, t3.desc_img_ebai,
|
||||
t4.name cat_name, t4.ebai_price_percentage cat_price_percentage,
|
||||
t4.id cat_id, t4.level cat_level, t5.ebai_id cat_ebai_id,
|
||||
t4p.id parent_cat_id, t5p.ebai_id parent_cat_ebai_id, t5p.ebai_sync_status parent_cat_ebai_sync_status,
|
||||
cat1.vendor_category_id ebai_cat3_id, cat2.vendor_category_id ebai_cat2_id, cat2.parent_id ebai_cat1_id
|
||||
FROM store_sku_bind t1
|
||||
LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ? AND t2.status = ?
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ? AND t3.status = ?
|
||||
JOIN sku_category t4 ON t3.category_id = t4.id
|
||||
LEFT JOIN sku_category t4 ON t3.category_id = t4.id
|
||||
LEFT JOIN sku_category t4p ON t4p.id = t4.parent_id
|
||||
LEFT JOIN store_sku_category_map t5 ON t5.store_id = t1.store_id AND t5.category_id = t4.id AND t5.deleted_at = ?
|
||||
LEFT JOIN store_sku_category_map t5p ON t5p.store_id = t1.store_id AND t5p.category_id = t4p.id AND t5p.deleted_at = ?
|
||||
LEFT JOIN sku_vendor_category cat1 ON t4.ebai_category_id = cat1.vendor_category_id AND cat1.vendor_id = ?
|
||||
LEFT JOIN sku_vendor_category cat2 ON cat1.parent_id = cat2.vendor_category_id AND cat1.vendor_id = ?
|
||||
JOIN store_map t8 ON t8.store_id = t1.store_id AND t8.vendor_id = ? AND t8.deleted_at = ?
|
||||
WHERE t1.store_id = ? AND (t1.ebai_sync_status <> 0)
|
||||
WHERE t1.store_id = ? AND (t1.ebai_sync_status <> 0 OR (t1.ebai_id <> 0 AND t3.id IS NULL))
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
@@ -115,7 +118,7 @@ func (p *PurchaseHandler) getDirtyStoreSkus(db *dao.DaoDB, storeID int, skuIDs [
|
||||
sql += " AND t1.sku_id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlParams = append(sqlParams, skuIDs)
|
||||
}
|
||||
sql += " ORDER BY t1.price"
|
||||
sql += " ORDER BY t1.price DESC"
|
||||
err = dao.GetRows(db, &storeSkuInfoList, sql, sqlParams...)
|
||||
return storeSkuInfoList, err
|
||||
}
|
||||
@@ -123,7 +126,7 @@ func (p *PurchaseHandler) getDirtyStoreSkus(db *dao.DaoDB, storeID int, skuIDs [
|
||||
func (p *PurchaseHandler) createCatByStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, db *dao.DaoDB, storeID int, storeSkuInfoList []*tStoreSkuFullInfo) (num int64, err error) {
|
||||
catList2Add := make(map[int]int)
|
||||
for _, storeSku := range storeSkuInfoList {
|
||||
if storeSku.SkuID != 0 && storeSku.EbaiSyncStatus&(model.SyncFlagNewMask|model.SyncFlagModifiedMask) != 0 {
|
||||
if storeSku.CatID != 0 && storeSku.EbaiSyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreSkuModifiedMask) != 0 && storeSku.Status == model.SkuStatusNormal {
|
||||
if storeSku.ParentCatEbaiID == 0 && storeSku.ParentCatID != 0 {
|
||||
catList2Add[storeSku.ParentCatID] = 1
|
||||
}
|
||||
@@ -164,7 +167,7 @@ func (p *PurchaseHandler) FullSyncStoreSkus(ctx *jxcontext.Context, parentTask t
|
||||
_, err = p.setStoreSkuSyncStatus(ctx, db, storeID, nil, model.SyncFlagNewMask)
|
||||
case 2:
|
||||
if err = p.DeleteRemoteCategories(ctx, rootTask, storeID, nil); err == nil {
|
||||
_, err = dao.SetStoreCategorySyncStatus(db, model.VendorIDEBAI, storeID, nil, model.SyncFlagNewMask)
|
||||
_, err = dao.SetStoreCategorySyncStatus(db, model.VendorIDEBAI, []int{storeID}, nil, model.SyncFlagNewMask)
|
||||
}
|
||||
case 3:
|
||||
err = p.SyncLocalStoreCategory(db, storeID, userName)
|
||||
@@ -202,7 +205,7 @@ func (p *PurchaseHandler) DeleteRemoteStoreSkus(ctx *jxcontext.Context, parentTa
|
||||
_, err = p.setStoreSkuSyncStatus(ctx, db, storeID, nil, model.SyncFlagNewMask)
|
||||
case 2:
|
||||
if err = p.DeleteRemoteCategories(ctx, rootTask, storeID, nil); err == nil {
|
||||
_, err = dao.SetStoreCategorySyncStatus(db, model.VendorIDEBAI, storeID, nil, model.SyncFlagNewMask)
|
||||
_, err = dao.SetStoreCategorySyncStatus(db, model.VendorIDEBAI, []int{storeID}, nil, model.SyncFlagNewMask)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
@@ -248,34 +251,65 @@ func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasks
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeSku := batchItemList[0].(*tStoreSkuFullInfo)
|
||||
updateFields := []string{model.FieldEbaiSyncStatus}
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if storeSku.SkuID == 0 || storeSku.EbaiSyncStatus&model.SyncFlagDeletedMask != 0 {
|
||||
if storeSku.EbaiSyncStatus&model.SyncFlagNewMask == 0 && storeSku.EbaiID != 0 {
|
||||
if storeSku.NameID == 0 || storeSku.EbaiSyncStatus&model.SyncFlagDeletedMask != 0 {
|
||||
if storeSku.EbaiSyncStatus&model.SyncFlagNewMask == 0 && !jxutils.IsEmptyID(storeSku.EbaiID) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.SkuDelete(strStoreID, utils.Int64ToStr(storeSku.EbaiID))
|
||||
err = ignoreNoSkuErr(err)
|
||||
}
|
||||
} else if storeSku.EbaiSyncStatus&model.SyncFlagNewMask != 0 {
|
||||
}
|
||||
if err == nil {
|
||||
if utils.IsTimeZero(storeSku.DeletedAt) {
|
||||
storeSku.DeletedAt = time.Now()
|
||||
updateFields = append(updateFields, model.FieldDeletedAt)
|
||||
}
|
||||
storeSku.EbaiID = 0
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
}
|
||||
} else {
|
||||
if storeSku.EbaiSyncStatus&model.SyncFlagNewMask != 0 {
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(genSkuParamsFromStoreSkuInfo(storeSku), false))
|
||||
// todo 适当处理重复(即已经创建)的情况
|
||||
if storeSku.EbaiID, err = api.EbaiAPI.SkuCreate(strStoreID, storeSku.SkuID, genSkuParamsFromStoreSkuInfo(storeSku)); err == nil {
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
} else if storeSku.EbaiID = ebaiapi.GetEbaiSkuIDFromError(err); storeSku.EbaiID > 0 {
|
||||
// globals.SugarLogger.Debugf("SyncStoreSkus test storeSku.EbaiID:%d, err:%v", storeSku.EbaiID, err)
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
_, err = api.EbaiAPI.SkuUpdate(strStoreID, storeSku.EbaiID, genSkuParamsFromStoreSkuInfo(storeSku))
|
||||
mergedStoreSkuStatus := jxutils.MergeSkuStatus(storeSku.SkuStatus, storeSku.Status)
|
||||
if mergedStoreSkuStatus == model.SkuStatusNormal { // 待创建且不可售的,暂不新建
|
||||
if storeSku.Img != "" {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
storeSku.EbaiID, err = api.EbaiAPI.SkuCreate(strStoreID, storeSku.SkuID, genSkuParamsFromStoreSkuInfo(storeSku))
|
||||
} else {
|
||||
storeSku.EbaiID = jxutils.GenFakeID()
|
||||
}
|
||||
if err == nil {
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
} else if storeSku.EbaiID = ebaiapi.GetEbaiSkuIDFromError(err); storeSku.EbaiID > 0 {
|
||||
// globals.SugarLogger.Debugf("SyncStoreSkus test storeSku.EbaiID:%d, err:%v", storeSku.EbaiID, err)
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
err = skuUpdate(strStoreID, storeSku)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("SKUANME%d:%s没有图片,同步失败", storeSku.NameID, storeSku.Name)
|
||||
}
|
||||
} else {
|
||||
updateFields = nil
|
||||
}
|
||||
} else if storeSku.EbaiSyncStatus&model.SyncFlagModifiedMask != 0 {
|
||||
if jxutils.IsFakeID(storeSku.EbaiID) {
|
||||
} else if storeSku.EbaiSyncStatus&model.SyncFlagStoreSkuModifiedMask != 0 {
|
||||
if jxutils.IsEmptyID(storeSku.EbaiID) {
|
||||
err = fmt.Errorf("京西数据异常,修改一个没有创建的饿百商品:%d, store:%s", storeSku.SkuID, strStoreID)
|
||||
} else {
|
||||
if _, err = api.EbaiAPI.SkuUpdate(strStoreID, storeSku.EbaiID, genSkuParamsFromStoreSkuInfo(storeSku)); err == nil {
|
||||
// err = api.EbaiAPI.SkuShopCategoryMap(strStoreID, storeSku.EbaiID, utils.Int64ToStr(storeSku.CatEbaiID))
|
||||
if storeSku.Img != "" {
|
||||
err = skuUpdate(strStoreID, storeSku)
|
||||
} else {
|
||||
err = fmt.Errorf("SKUANME%d:%s没有图片,同步失败", storeSku.NameID, storeSku.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
storeSku.EbaiSyncStatus = 0
|
||||
_, err = dao.UpdateEntity(nil, &storeSku.StoreSkuBind, updateFields...)
|
||||
if len(updateFields) > 0 {
|
||||
storeSku.EbaiSyncStatus = 0
|
||||
_, err = dao.UpdateEntity(nil, &storeSku.StoreSkuBind, updateFields...)
|
||||
}
|
||||
} else if isErrModifyPrice(err) {
|
||||
err = partner.NewErrorCode(err.Error(), partner.ErrCodeChangePriceFailed, model.VendorIDEBAI)
|
||||
}
|
||||
return nil, err
|
||||
}, storeSkuInfoList)
|
||||
@@ -291,9 +325,58 @@ func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasks
|
||||
return rootTask.ID, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetAllRemoteSkus(ctx *jxcontext.Context, storeID int, parentTask tasksch.ITask) (skus []map[string]interface{}, err error) {
|
||||
func ignoreNoSkuErr(err error) error {
|
||||
if err != nil {
|
||||
if codeErr, ok := err.(*utils.ErrorWithCode); ok {
|
||||
if codeErr.IntCode() == 1 {
|
||||
for _, v := range []string{"SKU不存在或者已经被删除", "sku_id与shop_id不匹配"} {
|
||||
if strings.Index(codeErr.ErrMsg(), v) > 0 {
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func skuUpdate(strStoreID string, storeSku *tStoreSkuFullInfo) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if _, err = api.EbaiAPI.SkuUpdate(strStoreID, storeSku.EbaiID, genSkuParamsFromStoreSkuInfo(storeSku)); err != nil {
|
||||
// 如果是改价错误,尝试把价格标志去掉再同步
|
||||
if isErrModifyPrice(err) {
|
||||
storeSku.EbaiSyncStatus = storeSku.EbaiSyncStatus & ^model.SyncFlagPriceMask
|
||||
if storeSku.EbaiSyncStatus != 0 {
|
||||
if _, err2 := api.EbaiAPI.SkuUpdate(strStoreID, storeSku.EbaiID, genSkuParamsFromStoreSkuInfo(storeSku)); err2 != nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isErrModifyPrice(err error) bool {
|
||||
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 1 {
|
||||
for _, v := range []string{
|
||||
"无法修改价格",
|
||||
"sku_参加营销活动",
|
||||
} {
|
||||
if strings.Index(errExt.ErrMsg(), v) >= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetAllRemoteSkus(ctx *jxcontext.Context, storeID int, parentTask tasksch.ITask) (skus []*ebaiapi.SkuInfo, err error) {
|
||||
globals.SugarLogger.Debugf("ebai GetAllRemoteSkus storeID:%d, userName:%s", storeID, ctx.GetUserName())
|
||||
page1, err := api.EbaiAPI.SkuList(utils.Int2Str(storeID), utils.Params2Map("pagesize", MaxPageSize))
|
||||
page1, err := api.EbaiAPI.SkuList(utils.Int2Str(storeID), &ebaiapi.SkuListParams{
|
||||
PageSize: MaxPageSize,
|
||||
})
|
||||
if err == nil {
|
||||
skus = append(skus, page1.List...)
|
||||
if page1.Pages > 1 {
|
||||
@@ -303,9 +386,9 @@ func (p *PurchaseHandler) GetAllRemoteSkus(ctx *jxcontext.Context, storeID int,
|
||||
}
|
||||
task := tasksch.NewParallelTask("GetAllRemoteSkus", nil, ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
callParams := map[string]interface{}{
|
||||
"pagesize": MaxPageSize,
|
||||
"page": batchItemList[0],
|
||||
callParams := &ebaiapi.SkuListParams{
|
||||
PageSize: MaxPageSize,
|
||||
Page: batchItemList[0].(int),
|
||||
}
|
||||
pageSku, err2 := api.EbaiAPI.SkuList(utils.Int2Str(storeID), callParams)
|
||||
if err2 == nil {
|
||||
@@ -318,7 +401,7 @@ func (p *PurchaseHandler) GetAllRemoteSkus(ctx *jxcontext.Context, storeID int,
|
||||
result, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
for _, v := range result {
|
||||
skus = append(skus, v.(map[string]interface{}))
|
||||
skus = append(skus, v.(*ebaiapi.SkuInfo))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,7 +417,7 @@ func (p *PurchaseHandler) DeleteRemoteSkus(ctx *jxcontext.Context, parentTask ta
|
||||
if err = err2; err == nil {
|
||||
vendorSkuIDs = make([]string, len(result))
|
||||
for k, v := range result {
|
||||
vendorSkuIDs[k] = utils.Interface2String(v[ebaiapi.KeySkuID])
|
||||
vendorSkuIDs[k] = utils.Int64ToStr(v.SkuID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +427,7 @@ func (p *PurchaseHandler) DeleteRemoteSkus(ctx *jxcontext.Context, parentTask ta
|
||||
for k, v := range batchItemList {
|
||||
strList[k] = v.(string)
|
||||
}
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.SkuDelete(utils.Int2Str(storeID), strings.Join(strList, ","))
|
||||
}
|
||||
return nil, err
|
||||
@@ -369,7 +452,7 @@ func (p *PurchaseHandler) DeleteRemoteCategories(ctx *jxcontext.Context, parentT
|
||||
}
|
||||
task := tasksch.NewParallelTask("DeleteRemoteCategories", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopCategoryDelete(strStoreID, batchItemList[0].(int64))
|
||||
}
|
||||
return nil, err
|
||||
@@ -385,11 +468,12 @@ func (p *PurchaseHandler) RefreshStoresAllSkusID(ctx *jxcontext.Context, parentT
|
||||
|
||||
///////////
|
||||
func genSkuParamsFromStoreSkuInfo(storeSku *tStoreSkuFullInfo) (params map[string]interface{}) {
|
||||
price := jxutils.CaculateSkuVendorPrice(storeSku.Price, storeSku.PricePercentage)
|
||||
price := jxutils.CaculateSkuVendorPrice(storeSku.Price, storeSku.PricePercentage, storeSku.CatPricePercentage)
|
||||
params = map[string]interface{}{
|
||||
"name": jxutils.ComposeSkuName(storeSku.Prefix, storeSku.Name, storeSku.Comment, storeSku.Unit, storeSku.SpecQuality, storeSku.SpecUnit, 0),
|
||||
"name": utils.LimitMixedStringLen(jxutils.ComposeSkuName(storeSku.Prefix, storeSku.Name, storeSku.Comment, storeSku.Unit, storeSku.SpecQuality, storeSku.SpecUnit, 0), ebaiapi.MaxSkuNameByteCount),
|
||||
"left_num": model.MaxStoreSkuStockQty,
|
||||
"category_id": storeSku.CatEbaiID,
|
||||
"predict_cat": 0, // 不使用推荐类目
|
||||
"cat1_id": getEbaiCat(storeSku.EbaiCat1ID, 1),
|
||||
"cat2_id": getEbaiCat(storeSku.EbaiCat2ID, 2),
|
||||
"cat3_id": getEbaiCat(storeSku.EbaiCat3ID, 3),
|
||||
@@ -401,6 +485,9 @@ func genSkuParamsFromStoreSkuInfo(storeSku *tStoreSkuFullInfo) (params map[strin
|
||||
},
|
||||
},
|
||||
}
|
||||
if storeSku.DescImgEbai != "" {
|
||||
params["rtf"] = storeSku.DescImgEbai
|
||||
}
|
||||
if storeSku.EbaiSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0 {
|
||||
params["sale_price"] = price
|
||||
params["market_price"] = price
|
||||
@@ -516,18 +603,23 @@ func (p *PurchaseHandler) SyncStoreCategory(ctx *jxcontext.Context, parentTask t
|
||||
updateFields := []string{model.FieldEbaiSyncStatus}
|
||||
catInfo := batchItemList[0].(*tStoreCatInfo)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(catInfo, false))
|
||||
if globals.EnableStoreWrite && globals.EnableEbaiStoreWrite {
|
||||
if catInfo.EbaiSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除
|
||||
if catInfo.EbaiSyncStatus&model.SyncFlagNewMask == 0 && catInfo.EbaiID != 0 {
|
||||
if catInfo.EbaiSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除
|
||||
if catInfo.EbaiSyncStatus&model.SyncFlagNewMask == 0 && catInfo.EbaiID != 0 {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopCategoryDelete(strStoreID, catInfo.EbaiID)
|
||||
}
|
||||
} else if catInfo.EbaiSyncStatus&model.SyncFlagNewMask != 0 { // 新增
|
||||
ebaiID, err2 := api.EbaiAPI.ShopCategoryCreate(strStoreID, catInfo.ParentEbaiID, formatName(catInfo.Name), jxCatSeq2Ebai(catInfo.Seq))
|
||||
if err = err2; err == nil {
|
||||
catInfo.EbaiID = ebaiID
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
}
|
||||
} else if catInfo.EbaiSyncStatus&model.SyncFlagModifiedMask != 0 { // 修改
|
||||
}
|
||||
} else if catInfo.EbaiSyncStatus&model.SyncFlagNewMask != 0 { // 新增
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
catInfo.EbaiID, err = api.EbaiAPI.ShopCategoryCreate(strStoreID, catInfo.ParentEbaiID, formatName(catInfo.Name), jxCatSeq2Ebai(catInfo.Seq))
|
||||
} else {
|
||||
catInfo.EbaiID = jxutils.GenFakeID()
|
||||
}
|
||||
if err == nil {
|
||||
updateFields = append(updateFields, model.FieldEbaiID)
|
||||
}
|
||||
} else if catInfo.EbaiSyncStatus&model.SyncFlagModifiedMask != 0 { // 修改
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopCategoryUpdate(strStoreID, catInfo.EbaiID, formatName(catInfo.Name), jxCatSeq2Ebai(catInfo.Seq))
|
||||
}
|
||||
}
|
||||
@@ -603,7 +695,7 @@ func (p *PurchaseHandler) updateLocalCatAsNew(db *dao.DaoDB, localCatMap map[str
|
||||
|
||||
func (p *PurchaseHandler) setStoreSkuSyncStatus(ctx *jxcontext.Context, db *dao.DaoDB, storeID int, skuIDs []int, syncStatus int) (num int64, err error) {
|
||||
globals.SugarLogger.Debugf("ebai setStoreSkuSyncStatus storeID:%d, userName:%s", storeID, ctx.GetUserName())
|
||||
return dao.SetStoreSkuSyncStatus(db, model.VendorIDEBAI, storeID, skuIDs, syncStatus)
|
||||
return dao.SetStoreSkuSyncStatus(db, model.VendorIDEBAI, []int{storeID}, skuIDs, syncStatus)
|
||||
}
|
||||
|
||||
func formatName(name string) string {
|
||||
@@ -614,3 +706,7 @@ func formatName(name string) string {
|
||||
func jxCatSeq2Ebai(seq int) int {
|
||||
return 10000 - seq
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoresSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeIDs []int) (storeSkuList []*model.StoreSkuBind, err error) {
|
||||
return storeSkuList, err
|
||||
}
|
||||
|
||||
248
business/partner/purchase/ebai/store_sku2.go
Normal file
248
business/partner/purchase/ebai/store_sku2.go
Normal file
@@ -0,0 +1,248 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"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/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
minBatchSize = 5 // 使用batch相关的API最少的处理数量,因为饿百批处理API的调用频率限制得更低
|
||||
)
|
||||
|
||||
// 门店分类
|
||||
func (p *PurchaseHandler) ReadStoreCategory(ctx *jxcontext.Context, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
|
||||
remoteCats, err := api.EbaiAPI.ShopCategoryGet(vendorStoreID)
|
||||
if err == nil {
|
||||
cats = convertVendorCatList(remoteCats)
|
||||
}
|
||||
return cats, err
|
||||
}
|
||||
|
||||
func convertVendorCatList(remoteCats []*ebaiapi.CategoryInfo) (cats []*partner.BareCategoryInfo) {
|
||||
for _, rCat := range remoteCats {
|
||||
cat := &partner.BareCategoryInfo{
|
||||
VendorCatID: utils.Int64ToStr(rCat.CategoryID),
|
||||
Name: rCat.Name,
|
||||
Level: rCat.Level,
|
||||
Seq: jxCatSeq2Ebai(rCat.Rank),
|
||||
Children: convertVendorCatList(rCat.Children),
|
||||
}
|
||||
cats = append(cats, cat)
|
||||
}
|
||||
return cats
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStoreSkuCategory(ctx *jxcontext.Context, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||||
var vendorCatID int64
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
vendorCatID, err = api.EbaiAPI.ShopCategoryCreate(vendorStoreID, utils.Str2Int64WithDefault(storeCat.ParentVendorCatID, 0), storeCat.Name, jxCatSeq2Ebai(storeCat.Seq))
|
||||
} else {
|
||||
vendorCatID = jxutils.GenFakeID()
|
||||
}
|
||||
storeCat.VendorCatID = utils.Int64ToStr(vendorCatID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkuCategory(ctx *jxcontext.Context, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopCategoryUpdate(vendorStoreID, utils.Str2Int64WithDefault(storeCat.VendorCatID, 0), storeCat.Name, jxCatSeq2Ebai(storeCat.Seq))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStoreSkuCategory(ctx *jxcontext.Context, vendorStoreID, vendorCatID string) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopCategoryDelete(vendorStoreID, utils.Str2Int64WithDefault(vendorCatID, 0))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 门店商品
|
||||
|
||||
// 多门店平台不需要实现这个接口
|
||||
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (err error) {
|
||||
storeSku := storeSkuList[0]
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
_, err = api.EbaiAPI.SkuUpdate(vendorStoreID, utils.Str2Int64(storeSku.VendorSkuID), genSkuParamsFromStoreSkuInfo2(storeSku))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 通用
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// 对于多门店平台来说,storeSkuList中只有SkuID与VendorSkuID有意义
|
||||
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (err error) {
|
||||
storeSku := storeSkuList[0]
|
||||
var vendorSkuID int64
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
vendorSkuID, err = api.EbaiAPI.SkuCreate(vendorStoreID, storeSku.SkuID, genSkuParamsFromStoreSkuInfo2(storeSku))
|
||||
} else {
|
||||
vendorSkuID = jxutils.GenFakeID()
|
||||
}
|
||||
storeSku.VendorSkuID = utils.Int64ToStr(vendorSkuID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.BareStoreSkuInfo) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.SkuDelete(vendorStoreID, strings.Join(partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDList(), ","))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.BareStoreSkuInfo) (err error) {
|
||||
var validSkus, invalidSkus []string
|
||||
for _, storeSku := range storeSkuList {
|
||||
if storeSku.Status == model.SkuStatusNormal {
|
||||
validSkus = append(validSkus, storeSku.VendorSkuID)
|
||||
} else {
|
||||
invalidSkus = append(invalidSkus, storeSku.VendorSkuID)
|
||||
}
|
||||
}
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if len(invalidSkus) > minBatchSize {
|
||||
err = api.EbaiAPI.SkuOffline(utils.Int2Str(storeID), strings.Join(invalidSkus, ","))
|
||||
} else if len(invalidSkus) > 0 {
|
||||
for _, v := range invalidSkus {
|
||||
if err = api.EbaiAPI.SkuOfflineOne(utils.Int2Str(storeID), utils.Str2Int64(v), "", ""); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if len(validSkus) > minBatchSize {
|
||||
err = api.EbaiAPI.SkuOnline(utils.Int2Str(storeID), strings.Join(validSkus, ","))
|
||||
} else if len(validSkus) > 0 {
|
||||
for _, v := range invalidSkus {
|
||||
if err = api.EbaiAPI.SkuOnlineOne(utils.Int2Str(storeID), utils.Str2Int64(v), "", ""); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.BareStoreSkuInfo) (err error) {
|
||||
skuPriceList := make([]string, len(storeSkuList))
|
||||
for k, v := range storeSkuList {
|
||||
skuPriceList[k] = fmt.Sprintf("%s:%d", v.VendorSkuID, v.Price)
|
||||
}
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if len(skuPriceList) > minBatchSize {
|
||||
err = api.EbaiAPI.SkuPriceUpdateBatch(utils.Int2Str(storeID), strings.Join(skuPriceList, ";"), "", "")
|
||||
} else {
|
||||
for _, v := range skuPriceList {
|
||||
if err = api.EbaiAPI.SkuPriceUpdateOne(utils.Int2Str(storeID), v, "", ""); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func genSkuParamsFromStoreSkuInfo2(storeSku *dao.StoreSkuSyncInfo) (params map[string]interface{}) {
|
||||
params = map[string]interface{}{
|
||||
"name": storeSku.Name,
|
||||
"left_num": model.MaxStoreSkuStockQty,
|
||||
"category_id": utils.Str2Int64(storeSku.VendorCatID),
|
||||
"predict_cat": 0, // 不使用推荐类目
|
||||
"cat1_id": getEbaiCat(storeSku.VendorVendorCatID3, 1),
|
||||
"cat2_id": getEbaiCat(storeSku.VendorVendorCatID2, 2),
|
||||
"cat3_id": getEbaiCat(storeSku.VendorVendorCatID, 3),
|
||||
"weight": storeSku.Weight,
|
||||
"photos": []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"is_master": true,
|
||||
"url": storeSku.Img,
|
||||
},
|
||||
},
|
||||
}
|
||||
if storeSku.DescImg != "" {
|
||||
params["rtf"] = storeSku.DescImg
|
||||
}
|
||||
if storeSku.StoreSkuSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0 {
|
||||
params["sale_price"] = storeSku.Price
|
||||
params["market_price"] = storeSku.Price
|
||||
}
|
||||
if storeSku.StoreSkuSyncStatus&(model.SyncFlagSaleMask|model.SyncFlagNewMask) != 0 {
|
||||
params["status"] = jxSkuStatus2Ebai(storeSku.StoreSkuStatus)
|
||||
}
|
||||
// todo 饿百如果给的UPC是空要报错,但如果我要删除UPC怎么弄?
|
||||
if storeSku.Upc != "" {
|
||||
params["upc"] = storeSku.Upc
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.BareStoreSkuInfo) (outStoreSkuList []*partner.BareStoreSkuInfo, err error) {
|
||||
vendorSkuIDIntList := partner.BareStoreSkuInfoList(inStoreSkuList).GetVendorSkuIDIntList()
|
||||
var vendorSkuList []*ebaiapi.SkuInfo
|
||||
if len(vendorSkuIDIntList) > 1 {
|
||||
task := tasksch.NewParallelTask("获取饿百平台门店商品信息", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorSkuID := batchItemList[0].(int64)
|
||||
skuInfo, err := api.EbaiAPI.SkuList(utils.Int2Str(storeID), &ebaiapi.SkuListParams{
|
||||
SkuID: vendorSkuID,
|
||||
})
|
||||
if err == nil {
|
||||
vendorSkuList = skuInfo.List
|
||||
return skuInfo.List, nil
|
||||
}
|
||||
return nil, err
|
||||
}, vendorSkuIDIntList)
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
_, err = task.GetResult(0)
|
||||
} else if len(vendorSkuIDIntList) == 1 {
|
||||
skuInfo, err2 := api.EbaiAPI.SkuList(utils.Int2Str(storeID), &ebaiapi.SkuListParams{
|
||||
SkuID: vendorSkuIDIntList[0],
|
||||
})
|
||||
if err = err2; err == nil {
|
||||
vendorSkuList = skuInfo.List
|
||||
}
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
if err == nil {
|
||||
storeSkuMap := make(map[int64]*partner.BareStoreSkuInfo)
|
||||
for _, v := range inStoreSkuList {
|
||||
storeSkuMap[utils.Str2Int64(v.VendorSkuID)] = v
|
||||
}
|
||||
for _, skuInfo := range vendorSkuList {
|
||||
storeSku := storeSkuMap[skuInfo.SkuID]
|
||||
globals.SugarLogger.Debug(utils.Format4Output(storeSku, false))
|
||||
outStoreSkuList = append(outStoreSkuList, storeSku)
|
||||
storeSku.Price = skuInfo.SalePrice
|
||||
storeSku.Status = ebaiSkuStatus2Jx(skuInfo.Status)
|
||||
}
|
||||
}
|
||||
return outStoreSkuList, err
|
||||
}
|
||||
|
||||
func ebaiSkuStatus2Jx(ebaiSkuStatus int) (jxSkuStatus int) {
|
||||
if ebaiSkuStatus == ebaiapi.SkuStatusOnline {
|
||||
jxSkuStatus = model.SkuStatusNormal
|
||||
} else if ebaiSkuStatus == ebaiapi.SkuStatusOffline {
|
||||
jxSkuStatus = model.SkuStatusDontSale
|
||||
} else if ebaiSkuStatus == ebaiapi.SkuStatusOnline {
|
||||
jxSkuStatus = model.SkuStatusDeleted
|
||||
}
|
||||
return jxSkuStatus
|
||||
}
|
||||
@@ -18,10 +18,10 @@ var (
|
||||
ebaiapi.WaybillStatusCourierPickedup: model.WaybillStatusDelivering,
|
||||
ebaiapi.WaybillStatusDeliveryCancled: model.WaybillStatusCanceled,
|
||||
ebaiapi.WaybillStatusFinished: model.WaybillStatusDelivered,
|
||||
ebaiapi.WaybillStatusExceptional: model.WaybillStatusUnknown,
|
||||
ebaiapi.WaybillStatusExceptional: model.WaybillStatusCanceled,
|
||||
ebaiapi.WaybillStatusSelfDelivery: model.WaybillStatusUnknown,
|
||||
ebaiapi.WaybillStatusNotInDelivering: model.WaybillStatusUnknown,
|
||||
ebaiapi.WaybillStatusDeliveryRejected: model.WaybillStatusNeverSend,
|
||||
ebaiapi.WaybillStatusDontDeliver: model.WaybillStatusCanceled,
|
||||
ebaiapi.WaybillStatusDeliveryRejected: model.WaybillStatusCanceled,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
19
business/partner/purchase/elm/act.go
Normal file
19
business/partner/purchase/elm/act.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) CreateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"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/business/partner"
|
||||
)
|
||||
|
||||
@@ -186,47 +187,23 @@ func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo
|
||||
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
|
||||
Weight: int(math.Round(utils.Interface2Float64WithDefault(product["weight"], 0.0))),
|
||||
}
|
||||
if sku.VendorSkuID == "0" {
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
sku.VendorSkuID = utils.Int64ToStr(utils.MustInterface2Int64(product["id"])) // 2018-09-28日,饿了么迁移到饿百后,这个字段发生了变化
|
||||
}
|
||||
order.Skus = append(order.Skus, sku)
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
}
|
||||
setOrederDetailFee(result, order)
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
return order
|
||||
}
|
||||
|
||||
func setOrederDetailFee(result map[string]interface{}, order *model.GoodsOrder) {
|
||||
orderActivities, ok := result["orderActivities"].([]interface{})
|
||||
if ok {
|
||||
for _, value := range orderActivities {
|
||||
activity := value.(map[string]interface{})
|
||||
categoryId := utils.MustInterface2Int64(activity["categoryId"])
|
||||
restaurantPart := -jxutils.StandardPrice2Int(utils.MustInterface2Float64(activity["restaurantPart"]))
|
||||
elemePart := -jxutils.StandardPrice2Int(utils.MustInterface2Float64(activity["elemePart"]))
|
||||
if _, ok := model.ElmSkuPromotion[int(categoryId)]; ok {
|
||||
order.SkuPmFee += restaurantPart
|
||||
order.SkuPmSubsidy += elemePart
|
||||
} else {
|
||||
order.OrderPmFee += restaurantPart
|
||||
order.OrderPmSubsidy += elemePart
|
||||
}
|
||||
}
|
||||
}
|
||||
order.PlatformFeeRate = int16(utils.MustInterface2Float64(result["serviceRate"]))
|
||||
}
|
||||
|
||||
//
|
||||
func (c *PurchaseHandler) onOrderNew(msg map[string]interface{}) (response *elmapi.CallbackResponse) {
|
||||
// todo 这里应该可以直接用msg里的内容,而不用再次去查
|
||||
order, err := c.GetOrder(msg["orderId"].(string))
|
||||
if err == nil {
|
||||
order.VendorStatus = c.stateAndType2Str(order.VendorStatus, elmapi.MsgTypeOrderValid)
|
||||
err = partner.CurOrderManager.OnOrderNew(order, c.stateAndType2Str(msg["status"].(string), elmapi.MsgTypeOrderValid))
|
||||
err = partner.CurOrderManager.OnOrderNew(order, nil)
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyWriteElmOrder(order)
|
||||
// }
|
||||
|
||||
16
business/partner/purchase/elm/order_afs.go
Normal file
16
business/partner/purchase/elm/order_afs.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
// 审核售后单申请
|
||||
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// 确认收到退货
|
||||
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package elm
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) SyncStoreCategory(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync bool) (hint string, err error) {
|
||||
@@ -24,3 +26,11 @@ func (p *PurchaseHandler) FullSyncStoreSkus(ctx *jxcontext.Context, parentTask t
|
||||
func (p *PurchaseHandler) DeleteRemoteStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoresSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeIDs []int) (storeSkuList []*model.StoreSkuBind, err error) {
|
||||
return storeSkuList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.BareStoreSkuInfo) (outStoreSkuList []*partner.BareStoreSkuInfo, err error) {
|
||||
return outStoreSkuList, err
|
||||
}
|
||||
|
||||
183
business/partner/purchase/jd/act.go
Normal file
183
business/partner/purchase/jd/act.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func CreatePromotionInfos(promotionType int, name string, beginDate, endDate time.Time, outInfoId, advertising, traceId string) (infoId int64, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.CreatePromotionInfosSingle(name, beginDate, endDate, outInfoId, advertising, traceId)
|
||||
} else {
|
||||
return api.JdAPI.CreatePromotionInfosLimitTime(name, beginDate, endDate, outInfoId, advertising, traceId)
|
||||
}
|
||||
} else {
|
||||
infoId = jxutils.GenFakeID()
|
||||
}
|
||||
return infoId, err
|
||||
}
|
||||
|
||||
func CreatePromotionRules(promotionType int, infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.CreatePromotionRulesSingle(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
|
||||
} else {
|
||||
return api.JdAPI.CreatePromotionRulesLimitTime(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CreatePromotionSku(promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.CreatePromotionSkuSingle(infoId, outInfoId, skus, traceId)
|
||||
} else {
|
||||
return api.JdAPI.CreatePromotionSkuLimitTime(infoId, outInfoId, skus, traceId)
|
||||
}
|
||||
}
|
||||
return skusResult, err
|
||||
}
|
||||
|
||||
func CancelPromotionSku(promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.CancelPromotionSkuSingle(infoId, outInfoId, skus, traceId)
|
||||
} else {
|
||||
return api.JdAPI.CancelPromotionSkuLimitTime(infoId, outInfoId, skus, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ConfirmPromotion(promotionType int, infoId int64, outInfoId, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.ConfirmPromotionSingle(infoId, outInfoId, traceId)
|
||||
} else {
|
||||
return api.JdAPI.ConfirmPromotionLimitTime(infoId, outInfoId, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CancelPromotion(promotionType int, infoId int64, outInfoId, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.CancelPromotionSingle(infoId, outInfoId, traceId)
|
||||
} else {
|
||||
return api.JdAPI.CancelPromotionLimitTime(infoId, outInfoId, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AdjustPromotionTime(promotionType int, infoId int64, outInfoId string, endDate time.Time, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.AdjustPromotionTimeSingle(infoId, outInfoId, endDate, traceId)
|
||||
} else {
|
||||
return api.JdAPI.AdjustPromotionTimeLimitTime(infoId, outInfoId, endDate, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AdjustPromotionSku(promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return api.JdAPI.AdjustPromotionSkuSingle(infoId, outInfoId, skus, traceId)
|
||||
} else {
|
||||
return api.JdAPI.AdjustPromotionSkuLimitTime(infoId, outInfoId, skus, traceId)
|
||||
}
|
||||
}
|
||||
return skusResult, err
|
||||
}
|
||||
|
||||
func getTraceID(ctx *jxcontext.Context) (traceID string) {
|
||||
traceID = ctx.GetUserName() + utils.GetUUID()
|
||||
return traceID
|
||||
}
|
||||
|
||||
func storeSku2Jd(actStoreSku []*model.ActStoreSku2, handler func(syncStatus int) bool) (jdActStoreSku []*jdapi.PromotionSku) {
|
||||
for _, v := range actStoreSku {
|
||||
if handler(v.SyncStatus) {
|
||||
jdActStoreSku = append(jdActStoreSku, &jdapi.PromotionSku{
|
||||
StationNo: utils.Str2Int64(v.VendorStoreID),
|
||||
SkuID: utils.Str2Int64(v.VendorSkuID),
|
||||
PromotionPrice: v.ActPrice,
|
||||
// LimitSkuCount:0,
|
||||
})
|
||||
}
|
||||
}
|
||||
return jdActStoreSku
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CreateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
traceID := getTraceID(ctx)
|
||||
if act.Type < model.ActOrderBegin {
|
||||
outInfoID := utils.Int2Str(act.ID)
|
||||
infoID, err2 := CreatePromotionInfos(act.Type, act.Name, act.BeginAt, act.EndAt, outInfoID, act.Advertising, traceID)
|
||||
if err = err2; err == nil {
|
||||
act.VendorActID = utils.Int64ToStr(infoID)
|
||||
if err = CreatePromotionRules(act.Type, infoID, "", act.LimitDevice, act.LimitPin, act.LimitCount, act.LimitDaily, traceID); err == nil {
|
||||
if _, err = CreatePromotionSku(act.Type, infoID, "", storeSku2Jd(actStoreSku, model.IsSyncStatusNeedCreate), traceID); err == nil {
|
||||
err = ConfirmPromotion(act.Type, infoID, "", traceID)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
traceID := getTraceID(ctx)
|
||||
if act.Type < model.ActOrderBegin {
|
||||
outInfoID := utils.Int2Str(act.ID)
|
||||
if !utils.IsTimeZero(act.EndAt) {
|
||||
if err = AdjustPromotionTime(act.Type, 0, outInfoID, act.EndAt, traceID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if toBeDeleted := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(toBeDeleted) > 0 {
|
||||
if err = CancelPromotionSku(act.Type, 0, outInfoID, toBeDeleted, traceID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// if toBeAdded := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(toBeAdded) > 0 {
|
||||
// if _, err = CreatePromotionSku(act.Type, 0, outInfoID, toBeAdded, traceID); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// if toBeUpdated := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(toBeUpdated) > 0 {
|
||||
// if _, err = AdjustPromotionSku(act.Type, 0, outInfoID, toBeUpdated, traceID); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
traceID := getTraceID(ctx)
|
||||
if act.Type < model.ActOrderBegin {
|
||||
outInfoID := utils.Int2Str(act.ID)
|
||||
err = CancelPromotion(act.Type, 0, outInfoID, traceID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,42 +1,26 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
)
|
||||
|
||||
func OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if curPurchaseHandler != nil {
|
||||
if retVal = curPurchaseHandler.OnOrderMsg(msg); retVal == nil {
|
||||
retVal = jdapi.Err2CallbackResponse(errors.New("Internal Error"), "")
|
||||
}
|
||||
retVal = curPurchaseHandler.OnOrderMsg(msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if curPurchaseHandler != nil {
|
||||
if retVal = curPurchaseHandler.OnWaybillMsg(msg); retVal == nil {
|
||||
retVal = jdapi.Err2CallbackResponse(errors.New("Internal Error"), "")
|
||||
}
|
||||
retVal = curPurchaseHandler.OnWaybillMsg(msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func OnStoreMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if curPurchaseHandler != nil {
|
||||
retVal = curPurchaseHandler.onStoreMsg(msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func OnAfterSaleMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if curPurchaseHandler != nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
OnFinancialMsg(msg)
|
||||
})
|
||||
retVal = curPurchaseHandler.OnStoreMsg(msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
@@ -9,8 +9,15 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) OnFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
utils.CallFuncAsync(func() {
|
||||
retVal = p.onFinancialMsg(msg)
|
||||
})
|
||||
return retVal
|
||||
}
|
||||
|
||||
// 京东正向/退款订单类型处理--存储
|
||||
func OnFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
func (p *PurchaseHandler) onFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
var err error
|
||||
// if msg.StatusID == jdapi.OrderStatusPayFinishedSettle || msg.StatusID == jdapi.OrderStatusTipChanged || msg.StatusID == jdapi.OrderStatusSwitch2SelfSettle { // 如果是正向单
|
||||
if msg.StatusID == jdapi.OrderStatusPayFinishedSettle || msg.StatusID == jdapi.OrderStatusTipChanged || msg.StatusID == jdapi.OrderStatusAdjustSettle || msg.StatusID == jdapi.OrderStatusSwitch2SelfSettle { // 如果是正向单
|
||||
@@ -30,7 +37,7 @@ func OnFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
} else if msg.StatusID == jdapi.SaleBillStatusRefundSuccess || msg.StatusID == jdapi.SaleBillStatusSaleReturnSuccess { // 如果是退款单
|
||||
} else if msg.StatusID == jdapi.AfsServiceStateRefundSuccess || msg.StatusID == jdapi.AfsServiceStateReturnGoodsSuccess { // 如果是退款单
|
||||
orderData, err2 := api.JdAPI.GetAfsService(msg.BillID)
|
||||
if err = err2; err == nil {
|
||||
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(curPurchaseHandler.AfsOrderDetail2Financial(orderData))
|
||||
@@ -127,18 +134,20 @@ func (p *PurchaseHandler) OrderDetail2Financial(orderData map[string]interface{}
|
||||
orderFinancial.TotalDiscountMoney += discountPrice
|
||||
if xMap["orderShareRatioData"] != nil {
|
||||
orderShareRatioData, _ := utils.HTTPBody2Values([]byte(utils.Interface2String(xMap["orderShareRatioData"])), false)
|
||||
activity := &model.OrderDiscountFinancial{
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
VendorActivityID: utils.Interface2String(orderShareRatioData["promotionId"][0]),
|
||||
Type: utils.Int64ToStr(int64(discountType)),
|
||||
// ActivityName: utils.Interface2String(xMap["discountName"]),
|
||||
// ActivityMoney: discountPrice,
|
||||
// Remark: utils.Interface2String(xMap["orderShareRatioData"]),
|
||||
if promotionID := orderShareRatioData.Get("promotionId"); promotionID != "" {
|
||||
activity := &model.OrderDiscountFinancial{
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
VendorActivityID: promotionID, // utils.Interface2String(orderShareRatioData["promotionId"][0]),
|
||||
Type: utils.Int64ToStr(int64(discountType)),
|
||||
// ActivityName: utils.Interface2String(xMap["discountName"]),
|
||||
// ActivityMoney: discountPrice,
|
||||
// Remark: utils.Interface2String(xMap["orderShareRatioData"]),
|
||||
}
|
||||
orderFinancial.Discounts = append(orderFinancial.Discounts, activity)
|
||||
// 通过活动Id去取,京西活动补贴
|
||||
// orderFinancial.JxSubsidyMoney +=
|
||||
}
|
||||
orderFinancial.Discounts = append(orderFinancial.Discounts, activity)
|
||||
// 通过活动Id去取,京西活动补贴
|
||||
// orderFinancial.JxSubsidyMoney +=
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Debug(utils.Format4Output(orderFinancial.Discounts, false))
|
||||
@@ -154,7 +163,7 @@ func (p *PurchaseHandler) OrderDetail2Financial(orderData map[string]interface{}
|
||||
orderFinancial.PmSubsidyMoney = utils.Interface2Int64WithDefault(order1["platOrderGoodsDiscountMoney"], 0) + orderFinancial.PmSkuSubsidyMoney
|
||||
} else {
|
||||
if !isFromOrderDetail {
|
||||
globals.SugarLogger.Warnf("jd OrderDetail2Financial, orderID:%s is not found from api.JdAPI.OrderShoudSettlementService", orderFinancial.VendorOrderID)
|
||||
globals.SugarLogger.Warnf("jd OrderDetail2Financial, orderID:%s is not found from api.JdAPI.OrderShoudSettlementService, err:%v", orderFinancial.VendorOrderID, err)
|
||||
}
|
||||
}
|
||||
return orderFinancial, err
|
||||
@@ -168,7 +177,7 @@ func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interfac
|
||||
VendorOrderID: utils.Interface2String(orderData["orderId"]),
|
||||
VendorStoreID: utils.Interface2String(orderData["stationId"]),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["stationNumOutSystem"]), 0)),
|
||||
AfsCreateAt: utils.Timestamp2Time(utils.MustInterface2Int64(orderData["updateTime"].(map[string]interface{})["time"]) / 1000),
|
||||
AfsCreatedAt: utils.Timestamp2Time(utils.MustInterface2Int64(orderData["updateTime"].(map[string]interface{})["time"]) / 1000),
|
||||
FreightUserMoney: utils.MustInterface2Int64(orderData["orderFreightMoney"]),
|
||||
AfsFreightMoney: utils.MustInterface2Int64(orderData["afsFreight"]),
|
||||
BoxMoney: utils.MustInterface2Int64(orderData["packagingMoney"]),
|
||||
|
||||
@@ -12,6 +12,6 @@ func TestOnFinancialMsg(t *testing.T) {
|
||||
BillID: "907315020000322",
|
||||
StatusID: "330902",
|
||||
}
|
||||
res := OnFinancialMsg(msg)
|
||||
res := curPurchaseHandler.onFinancialMsg(msg)
|
||||
fmt.Println(res)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func JdStoreStatus2JxStatus(yn, closeStatus interface{}) int {
|
||||
if yn2 == 1 {
|
||||
return model.StoreStatusDisabled
|
||||
} else if closeStatus2 == 1 {
|
||||
return model.StoreStatusClosed
|
||||
return model.StoreStatusHaveRest
|
||||
}
|
||||
return model.StoreStatusOpened
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func JxStoreStatus2JdStatus(status int) (yn, closeStatus int) {
|
||||
switch status {
|
||||
case model.StoreStatusDisabled:
|
||||
return 1, 1
|
||||
case model.StoreStatusClosed:
|
||||
case model.StoreStatusHaveRest, model.StoreStatusClosed:
|
||||
return 0, 1
|
||||
default:
|
||||
return 0, 0
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
@@ -19,8 +21,8 @@ import (
|
||||
var (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
jdapi.OrderStatusPurchased: model.OrderStatusNew,
|
||||
jdapi.OrderStatusNew: model.OrderStatusNew,
|
||||
jdapi.OrderStatusWaitOutStore: model.OrderStatusAccepted,
|
||||
jdapi.StatusIDWaitOutStore: model.OrderStatusAccepted,
|
||||
jdapi.OrderStatusFinishedPickup: model.OrderStatusFinishedPickup,
|
||||
jdapi.OrderStatusDelivering: model.OrderStatusDelivering,
|
||||
jdapi.OrderStatusDelivered: model.OrderStatusFinished,
|
||||
@@ -42,38 +44,83 @@ func (c *PurchaseHandler) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if jdapi.OrderStatusNew == msg.StatusID {
|
||||
retVal = c.onOrderNew(msg)
|
||||
} else if jdapi.OrderStatusAdjust == msg.StatusID {
|
||||
retVal = c.onOrderAdjust(msg)
|
||||
status := c.callbackMsg2Status(msg)
|
||||
if jdapi.StatusIDNewOrder == msg.StatusID {
|
||||
status.Status = model.OrderStatusNew // 因为京东将事件32000与状态32000混用,事件32000可能是新订单,也可能是已接单,统一当成新订单处理
|
||||
}
|
||||
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
|
||||
return nil
|
||||
}
|
||||
if msg.MsgURL == jdapi.CallbackMsgOrderAccounting {
|
||||
retVal = c.OnFinancialMsg(msg)
|
||||
} else if msg.MsgURL == jdapi.CallbackMsgAfterSaleBillStatus {
|
||||
retVal = c.OnAfsOrderMsg(msg)
|
||||
} else {
|
||||
status := c.callbackMsg2Status(msg)
|
||||
if msg.StatusID == jdapi.OrderStatusAddComment || msg.StatusID == jdapi.OrderStatusModifyComment {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.onOrderComment2(msg)
|
||||
})
|
||||
// 新订单事件,与订单状态有点冲突
|
||||
if jdapi.StatusIDNewOrder == msg.StatusID {
|
||||
retVal = c.onOrderNew(msg, status)
|
||||
} else if jdapi.OrderStatusAdjust == msg.StatusID {
|
||||
retVal = c.onOrderAdjust(msg, status)
|
||||
} else {
|
||||
if msg.StatusID == jdapi.OrderStatusAddComment || msg.StatusID == jdapi.OrderStatusModifyComment {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.onOrderComment2(msg)
|
||||
})
|
||||
}
|
||||
err := partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyJdOrderStatusChanged(status)
|
||||
// }
|
||||
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
err := partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyJdOrderStatusChanged(status)
|
||||
// }
|
||||
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) getOrder(orderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
|
||||
globals.SugarLogger.Debugf("jd GetOrder orderID:%s", orderID)
|
||||
if orderMap, err = api.JdAPI.QuerySingleOrder(orderID); err == nil {
|
||||
order = c.Map2Order(orderMap)
|
||||
if jxutils.IsMobileFake(order.ConsigneeMobile) {
|
||||
if realMobile, err := api.JdAPI.GetRealMobile4Order(orderID, order.VendorStoreID); err == nil { // 故意强制忽略取不到真实手机号错误
|
||||
order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile)
|
||||
} else {
|
||||
// globals.SugarLogger.Warnf("jd GetOrder orderID:%s, GetRealMobile4Order failed with error:%v", orderID, err2)
|
||||
globals.SugarLogger.Debugf("jd getOrder orderID:%s", orderID)
|
||||
var (
|
||||
realMobile string
|
||||
orderSettlement *jdapi.OrderSettlementInfo
|
||||
)
|
||||
task := tasksch.NewParallelTask("jd getOrder", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
taskIndex := batchItemList[0].(int)
|
||||
switch taskIndex {
|
||||
case 0:
|
||||
orderMap, err = api.JdAPI.QuerySingleOrder(orderID)
|
||||
if err == nil {
|
||||
order = c.Map2Order(orderMap)
|
||||
realMobile, err = api.JdAPI.GetRealMobile4Order(orderID, order.VendorStoreID)
|
||||
if realMobile != "" {
|
||||
order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile)
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
orderSettlement, err = api.JdAPI.OrderShoudSettlementService2(orderID)
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1})
|
||||
task.Run()
|
||||
task.GetResult(0)
|
||||
if order != nil {
|
||||
if orderSettlement != nil {
|
||||
order.TotalShopMoney = orderSettlement.SettlementAmount
|
||||
order.PmSubsidyMoney = orderSettlement.PlatOrderGoodsDiscountMoney + orderSettlement.PlatSkuGoodsDiscountMoney
|
||||
}
|
||||
}
|
||||
// if orderMap, err = api.JdAPI.QuerySingleOrder(orderID); err == nil {
|
||||
// globals.SugarLogger.Debugf("jd getOrder2 orderID:%s", orderID)
|
||||
// order = c.Map2Order(orderMap)
|
||||
// if jxutils.IsMobileFake(order.ConsigneeMobile) {
|
||||
// if realMobile, err := api.JdAPI.GetRealMobile4Order(orderID, order.VendorStoreID); err == nil { // 故意强制忽略取不到真实手机号错误
|
||||
// globals.SugarLogger.Debugf("jd getOrder3 orderID:%s", orderID)
|
||||
// order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile)
|
||||
// } else {
|
||||
// // globals.SugarLogger.Warnf("jd GetOrder orderID:%s, GetRealMobile4Order failed with error:%v", orderID, err2)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return order, orderMap, err
|
||||
}
|
||||
|
||||
@@ -85,6 +132,8 @@ func (c *PurchaseHandler) GetOrder(orderID string) (order *model.GoodsOrder, err
|
||||
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
result := orderData
|
||||
orderID := utils.Int64ToStr(utils.MustInterface2Int64(result["orderId"]))
|
||||
globals.SugarLogger.Debugf("jd Map2Order orderID:%s", orderID)
|
||||
|
||||
const defaultStatusTimeField = "orderPurchaseTime"
|
||||
statusTimeField := defaultStatusTimeField
|
||||
if result[statusTimeField] == nil { // 814560888003021 orderPurchaseTime为空
|
||||
@@ -108,7 +157,6 @@ func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo
|
||||
StatusTime: utils.Str2Time(result[statusTimeField].(string)),
|
||||
OriginalData: string(utils.MustMarshal(result)),
|
||||
ActualPayPrice: utils.MustInterface2Int64(result["orderBuyerPayableMoney"]),
|
||||
Skus: []*model.OrderSku{},
|
||||
}
|
||||
order.Status = c.GetStatusFromVendorStatus(order.VendorStatus)
|
||||
businessTage := utils.Interface2String(result["businessTag"])
|
||||
@@ -143,8 +191,11 @@ func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo
|
||||
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(product["skuId"])),
|
||||
SkuName: product["skuName"].(string),
|
||||
Weight: jxutils.FloatWeight2Int(float32(utils.MustInterface2Float64(product["skuWeight"]))),
|
||||
VendorPrice: utils.MustInterface2Int64(product["skuStorePrice"]),
|
||||
SalePrice: utils.MustInterface2Int64(product["skuJdPrice"]),
|
||||
PromotionType: int(utils.MustInterface2Int64(product["promotionType"])),
|
||||
}
|
||||
if jdPromotionType := int(utils.MustInterface2Int64(product["promotionType"])); jdPromotionType != jdapi.PromotionTypeNormal {
|
||||
sku.StoreSubName = utils.Int2Str(jdPromotionType)
|
||||
}
|
||||
if skuCostumeProperty, ok := product["skuCostumeProperty"]; ok {
|
||||
sku.SkuName += skuCostumeProperty.(string)
|
||||
@@ -153,26 +204,18 @@ func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *mo
|
||||
sku.SkuType = 1
|
||||
}
|
||||
order.Skus = append(order.Skus, sku)
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
setOrederDetailFee(result, order)
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
return order
|
||||
}
|
||||
|
||||
func setOrederDetailFee(result map[string]interface{}, order *model.GoodsOrder) {
|
||||
order.BoxFee = utils.Interface2Int64WithDefault(result["packagingMoney"], 0)
|
||||
order.PlatformFeeRate = model.JdPlatformFeeRate
|
||||
order.BillStoreFreightFee = utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0) + utils.Interface2Int64WithDefault(result["tips"], 0)
|
||||
}
|
||||
|
||||
//
|
||||
func (c *PurchaseHandler) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
|
||||
func (c *PurchaseHandler) onOrderNew(msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) (response *jdapi.CallbackResponse) {
|
||||
globals.SugarLogger.Debugf("onOrderNew orderID:%s", msg.BillID)
|
||||
order, orderMap, err := c.getOrder(msg.BillID)
|
||||
if err == nil {
|
||||
if err = partner.CurOrderManager.OnOrderNew(order, msg.StatusID); err == nil {
|
||||
globals.SugarLogger.Debugf("onOrderNew2 orderID:%s", msg.BillID)
|
||||
if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.OnOrderDetail(orderMap, partner.CreatedPeration)
|
||||
})
|
||||
@@ -181,10 +224,10 @@ func (c *PurchaseHandler) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jda
|
||||
return jdapi.Err2CallbackResponse(err, "jd onOrderNew")
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderAdjust(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse {
|
||||
func (c *PurchaseHandler) onOrderAdjust(msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) *jdapi.CallbackResponse {
|
||||
order, orderMap, err := c.getOrder(msg.BillID)
|
||||
if err == nil {
|
||||
err = partner.CurOrderManager.OnOrderAdjust(order, msg.StatusID)
|
||||
err = partner.CurOrderManager.OnOrderAdjust(order, orderStatus)
|
||||
if err == nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.OnOrderDetail(orderMap, partner.UpdatedPeration)
|
||||
@@ -233,14 +276,14 @@ func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptI
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.JdAPI.OrderAcceptOperate(order.VendorOrderID, isAcceptIt, userName)
|
||||
} else {
|
||||
c.postFakeMsg(order.VendorOrderID, jdapi.OrderStatusWaitOutStore)
|
||||
c.postFakeMsg(order.VendorOrderID, jdapi.StatusIDWaitOutStore)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
|
||||
if !isSelfDelivery && globals.EnableStoreWrite {
|
||||
if !isSelfDelivery && globals.EnableJdStoreWrite {
|
||||
_, err = api.JdAPI.OrderJDZBDelivery(order.VendorOrderID, userName)
|
||||
} else {
|
||||
c.postFakeMsg(order.VendorOrderID, jdapi.OrderStatusFinishedPickup)
|
||||
@@ -249,21 +292,21 @@ func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bo
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.ReceiveFailedAudit(order.VendorOrderID, isAcceptIt, ctx.GetUserName(), "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.UrgeDispatching(order.VendorOrderID, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.ConfirmReceiveGoods(order.VendorOrderID)
|
||||
}
|
||||
return err
|
||||
@@ -271,7 +314,7 @@ func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *mod
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = api.JdAPI.ModifySellerDelivery(order.VendorOrderID, userName)
|
||||
if err != nil {
|
||||
if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 {
|
||||
@@ -292,7 +335,7 @@ func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName s
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = api.JdAPI.DeliveryEndOrder(order.VendorOrderID, userName)
|
||||
}
|
||||
return err
|
||||
@@ -300,7 +343,7 @@ func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName
|
||||
|
||||
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = api.JdAPI.OrderSerllerDelivery(order.VendorOrderID, userName)
|
||||
}
|
||||
return err
|
||||
@@ -309,7 +352,7 @@ func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userNam
|
||||
// 京东送达接口都是一样的
|
||||
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = c.Swtich2SelfDelivered(order, userName)
|
||||
}
|
||||
return err
|
||||
@@ -321,7 +364,7 @@ func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *mode
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.OrderCancelOperate(order.VendorOrderID, isAgree, ctx.GetUserName(), reason)
|
||||
}
|
||||
return err
|
||||
@@ -333,29 +376,15 @@ func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.Goods
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
removedSkuMap := make(map[int]*model.OrderSku)
|
||||
for _, sku := range removedSkuList {
|
||||
removedSkuMap[jxutils.GetSkuIDFromOrderSku(sku)] = sku
|
||||
}
|
||||
order = jxutils.RemoveSkuFromOrder(order, removedSkuList)
|
||||
var oaosAdjustDTOList []*jdapi.OAOSAdjustDTO
|
||||
for _, sku := range order.Skus {
|
||||
skuID := jxutils.GetSkuIDFromOrderSku(sku)
|
||||
tmp := &jdapi.OAOSAdjustDTO{
|
||||
OutSkuID: utils.Int2Str(skuID),
|
||||
oaosAdjustDTOList = append(oaosAdjustDTOList, &jdapi.OAOSAdjustDTO{
|
||||
OutSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)),
|
||||
SkuCount: sku.Count,
|
||||
}
|
||||
if removedSkuMap[skuID] != nil {
|
||||
if removedSkuMap[skuID].Count >= sku.Count {
|
||||
tmp = nil
|
||||
} else {
|
||||
tmp.SkuCount -= removedSkuMap[skuID].Count
|
||||
}
|
||||
}
|
||||
if tmp != nil {
|
||||
oaosAdjustDTOList = append(oaosAdjustDTOList, tmp)
|
||||
}
|
||||
})
|
||||
}
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.AdjustOrder(order.VendorOrderID, ctx.GetUserName(), reason, oaosAdjustDTOList)
|
||||
}
|
||||
return err
|
||||
|
||||
190
business/partner/purchase/jd/order_afs.go
Normal file
190
business/partner/purchase/jd/order_afs.go
Normal file
@@ -0,0 +1,190 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"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/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
AfsVendorStatus2StatusMap = map[string]int{
|
||||
jdapi.AfsServiceStateWaiting4Audit: model.AfsOrderStatusWait4Approve, // 需要审核
|
||||
|
||||
jdapi.AfsServiceStateRefundProcessing: model.AfsOrderStatusNew,
|
||||
jdapi.AfsServiceStateWaiting4DirectCompensate: model.AfsOrderStatusNew,
|
||||
jdapi.AfsServiceStateWaiting4ReturnGoods: model.AfsOrderStatusNew,
|
||||
|
||||
jdapi.AfsServiceStateWaiting4MerchantReceiveGoods: model.AfsOrderStatusWait4ReceiveGoods,
|
||||
|
||||
jdapi.AfsServiceStateRefundSuccess: model.AfsOrderStatusFinished,
|
||||
jdapi.AfsServiceStateSolved: model.AfsOrderStatusFinished,
|
||||
jdapi.AfsServiceStateDirectCompensateSuccess: model.AfsOrderStatusFinished,
|
||||
jdapi.AfsServiceStateReturnGoodsSuccess: model.AfsOrderStatusFinished,
|
||||
|
||||
jdapi.AfsServiceStateRefundFailed: model.AfsOrderStatusFailed,
|
||||
jdapi.AfsServiceStateAuditRefused: model.AfsOrderStatusFailed,
|
||||
jdapi.AfsServiceStateUserCanceled: model.AfsOrderStatusFailed,
|
||||
jdapi.AfsServiceStateMerchantFailedReceiveGoods: model.AfsOrderStatusFailed,
|
||||
jdapi.AfsServiceStateDirectCompensateFailed: model.AfsOrderStatusFailed,
|
||||
jdapi.AfsServiceStateReturnGoodsFailed: model.AfsOrderStatusFailed,
|
||||
}
|
||||
|
||||
afsReasonTypeMap = map[int]int8{
|
||||
jdapi.AfsReasonTypeGoodsQuality: model.AfsReasonTypeGoodsQuality,
|
||||
jdapi.AfsReasonTypeWrongGoods: model.AfsReasonTypeWrongGoods,
|
||||
jdapi.AfsReasonTypeMissingGoods: model.AfsReasonTypeMissingGoods,
|
||||
jdapi.AfsReasonTypeNoGoods: model.AfsReasonTypeNoGoods,
|
||||
jdapi.AfsReasonTypeDamagedGoods: model.AfsReasonTypeDamagedGoods,
|
||||
jdapi.AfsReasonTypeGoodsQuantity: model.AfsReasonTypeGoodsQuantity,
|
||||
jdapi.AfsReasonTypeAgreedByMerchant: model.AfsReasonTypeAgreedByMerchant,
|
||||
jdapi.AfsReasonTypeGoodsSizeNoSame: model.AfsReasonTypeGoodsNoSame,
|
||||
jdapi.AfsReasonTypeGoodsColorNoSame: model.AfsReasonTypeGoodsNoSame,
|
||||
jdapi.AfsReasonWrongPurchase: model.AfsReasonWrongPurchase,
|
||||
jdapi.AfsReasonNotReceivedIntime: model.AfsReasonNotReceivedIntime,
|
||||
}
|
||||
afsAppealTypeMap = map[string]int8{
|
||||
jdapi.AfsDealTypeRefund: model.AfsAppealTypeRefund,
|
||||
jdapi.AfsDealTypeReturnGoodsRefund: model.AfsAppealTypeReturnAndRefund,
|
||||
jdapi.AfsDealTypeDirectCompensate: model.AfsAppealTypeNewGoods,
|
||||
}
|
||||
afsApproveTypeMap = map[int]int{
|
||||
partner.AfsApproveTypeRefund: jdapi.AfsApproveTypeRefund,
|
||||
partner.AfsApproveTypeReturnGoods: jdapi.AfsApproveTypeReturnGoods,
|
||||
partner.AfsApproveTypeRefused: jdapi.AfsApproveTypeRefused,
|
||||
}
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) OnAfsOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
retVal = c.onAfsOrderMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onAfsOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
afsInfo, err := api.JdAPI.GetAfsService2(msg.BillID)
|
||||
if err == nil {
|
||||
status := c.callbackAfsMsg2Status(msg, afsInfo)
|
||||
if status.Status == model.AfsOrderStatusWait4Approve || status.Status == model.AfsOrderStatusNew {
|
||||
afsOrder := c.buildAfsOrder(afsInfo)
|
||||
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, status)
|
||||
} else {
|
||||
err = partner.CurOrderManager.OnAfsOrderStatusChanged(status)
|
||||
}
|
||||
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackAfsMsg2Status(msg *jdapi.CallbackOrderMsg, afsInfo *jdapi.AfsServiceResponse) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.BillID, // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: model.VendorIDJD,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: afsInfo.OrderID,
|
||||
RefVendorID: model.VendorIDJD,
|
||||
VendorStatus: msg.StatusID,
|
||||
Status: c.GetAfsStatusFromVendorStatus(msg.StatusID),
|
||||
StatusTime: utils.Str2Time(msg.Timestamp),
|
||||
Remark: msg.Remark,
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus(vendorStatus string) int {
|
||||
if status, ok := AfsVendorStatus2StatusMap[vendorStatus]; ok {
|
||||
return status
|
||||
}
|
||||
return model.OrderStatusUnknown
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) convertAfsReasonType(vendorReasonType int) int8 {
|
||||
if status, ok := afsReasonTypeMap[vendorReasonType]; ok {
|
||||
return status
|
||||
}
|
||||
return model.AfsReasonNotOthers
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) convertAfsAppealType(vendorAppealType string) int8 {
|
||||
if status, ok := afsAppealTypeMap[vendorAppealType]; ok {
|
||||
return status
|
||||
}
|
||||
globals.SugarLogger.Warnf("jd convertAfsAppealType unknown vendorAppealType:%d", vendorAppealType)
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) buildAfsOrder(afsInfo *jdapi.AfsServiceResponse) (afsOrder *model.AfsOrder) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: model.VendorIDJD,
|
||||
AfsOrderID: afsInfo.AfsServiceOrder,
|
||||
VendorOrderID: afsInfo.OrderID,
|
||||
VendorStoreID: afsInfo.StationID,
|
||||
StoreID: int(utils.Str2Int64WithDefault(afsInfo.StationNumOutSystem, 0)),
|
||||
AfsCreatedAt: afsInfo.CreateTime.GoTime(),
|
||||
FreightUserMoney: afsInfo.OrderFreightMoney,
|
||||
AfsFreightMoney: afsInfo.AfsFreight,
|
||||
BoxMoney: afsInfo.PackagingMoney,
|
||||
TongchengFreightMoney: afsInfo.TongchengFreightMoney,
|
||||
SkuBoxMoney: afsInfo.MealBoxMoney,
|
||||
|
||||
VendorStatus: utils.Int2Str(afsInfo.AfsServiceState),
|
||||
VendorReasonType: utils.Int2Str(afsInfo.QuestionTypeCid),
|
||||
ReasonType: c.convertAfsReasonType(afsInfo.QuestionTypeCid),
|
||||
ReasonDesc: utils.LimitUTF8StringLen(afsInfo.QuestionDesc, 1024),
|
||||
ReasonImgList: utils.LimitUTF8StringLen(jdapi.ProcessQuestionPic(afsInfo.QuestionPic), 1024),
|
||||
VendorAppealType: afsInfo.ApplyDeal,
|
||||
AppealType: c.convertAfsAppealType(afsInfo.ApplyDeal),
|
||||
}
|
||||
afsOrder.Status = c.GetAfsStatusFromVendorStatus(afsOrder.VendorStatus)
|
||||
|
||||
for _, x := range afsInfo.AfsDetailList {
|
||||
orderSku := &model.OrderSkuFinancial{
|
||||
// VendorID: model.VendorIDJD,
|
||||
// AfsOrderID: afsOrder.AfsOrderID,
|
||||
// VendorOrderID: afsOrder.VendorOrderID,
|
||||
// VendorStoreID: afsOrder.VendorStoreID,
|
||||
// StoreID: afsOrder.StoreID,
|
||||
// IsAfsOrder: 1,
|
||||
|
||||
Count: x.SkuCount,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorSkuID: utils.Int64ToStr(x.WareID),
|
||||
SkuID: int(utils.Str2Int64WithDefault(x.SkuIDIsv, 0)),
|
||||
Name: x.WareName,
|
||||
UserMoney: x.AfsMoney,
|
||||
PmSkuSubsidyMoney: x.PlatPayMoney,
|
||||
}
|
||||
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
|
||||
orderSku.PmSubsidyMoney += orderSku.PmSkuSubsidyMoney
|
||||
|
||||
for _, y := range x.AfsSkuDiscountList {
|
||||
orderSku.PmSubsidyMoney += y.PlatPayMoney
|
||||
}
|
||||
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
// 审核售后单申请
|
||||
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.AfsOpenApprove(order.AfsOrderID, afsApproveTypeMap[approveType], reason, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 确认收到退货
|
||||
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.ConfirmReceipt(order.AfsOrderID, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package jd
|
||||
// 这里函数取得的信息,除了与自身实体相关的ID(比如PARENT ID),都已经转换成了本地ID了
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode/utf8"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
@@ -130,7 +131,7 @@ func (p *PurchaseHandler) ReorderCategories(db *dao.DaoDB, parentCatID int, user
|
||||
func (p *PurchaseHandler) cuSku(db *dao.DaoDB, sku *model.Sku, handler func(skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (string, error)) (err error) {
|
||||
var skuInfoExt tSkuInfoExt
|
||||
err = dao.GetRow(nil, &skuInfoExt, `
|
||||
SELECT t2.*, t3.jd_id jd_cat_id, t3.jd_category_id, t4.jd_id sku_cat_id
|
||||
SELECT t2.*, t3.jd_id jd_cat_id, IF(t2.jd_category_id > 0, t2.jd_category_id, t3.jd_category_id) jd_category_id, t4.jd_id sku_cat_id
|
||||
FROM sku t1
|
||||
JOIN sku_name t2 ON t1.name_id = t2.id
|
||||
JOIN sku_category t3 ON t2.category_id = t3.id
|
||||
@@ -164,8 +165,14 @@ func (p *PurchaseHandler) cuSku(db *dao.DaoDB, sku *model.Sku, handler func(skuE
|
||||
if addParams["sellCities"] == nil {
|
||||
addParams["sellCities"] = []int{0}
|
||||
}
|
||||
if skuInfoExt.DescImg != "" {
|
||||
addParams[jdapi.KeyProductDesc] = fmt.Sprintf(`<img src="%s" alt="一张图片" />`, skuInfoExt.DescImg)
|
||||
addParams[jdapi.KeyIfViewDesc] = 0
|
||||
} else {
|
||||
addParams[jdapi.KeyIfViewDesc] = 1
|
||||
}
|
||||
if err == nil {
|
||||
skuName := jxutils.ComposeSkuName(skuInfoExt.Prefix, skuInfoExt.Name, sku.Comment, skuInfoExt.Unit, sku.SpecQuality, sku.SpecUnit, 0)
|
||||
skuName := jxutils.ComposeSkuName(skuInfoExt.Prefix, skuInfoExt.Name, sku.Comment, skuInfoExt.Unit, sku.SpecQuality, sku.SpecUnit, jdapi.MaxSkuNameCharCount)
|
||||
skuPrice := jxutils.CaculateSkuPrice(skuInfoExt.Price, sku.SpecQuality, sku.SpecUnit, skuInfoExt.Unit)
|
||||
if skuInfoExt.Upc != "" {
|
||||
addParams[jdapi.KeyUpcCode] = skuInfoExt.Upc
|
||||
@@ -385,7 +392,7 @@ func (p *PurchaseHandler) syncSkuNameAsSpu(db *dao.DaoDB, sku *model.Sku, skuExt
|
||||
skuNameJdID := skuExt.JdID
|
||||
globals.SugarLogger.Debugf("syncSkuNameAsSpu1 sku.id=%d, bareSkuName:%s, skuName:%s, skuNameJdID:%d", sku.ID, skuExt.Name, skuName, skuNameJdID)
|
||||
spuAddParams, skuAddParams := splitAddParams(addParams)
|
||||
if !jxutils.IsFakeID(skuNameJdID) && sku.JdSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除SKU
|
||||
if !jxutils.IsEmptyID(skuNameJdID) && sku.JdSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除SKU
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.JdAPI.UpdateSkuBaseInfo(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted))
|
||||
}
|
||||
@@ -412,7 +419,7 @@ func (p *PurchaseHandler) syncSkuNameAsSpu(db *dao.DaoDB, sku *model.Sku, skuExt
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if skuExt.JdSyncStatus&model.SyncFlagNewMask != 0 && jxutils.IsFakeID(skuNameJdID) {
|
||||
} else if skuExt.JdSyncStatus&model.SyncFlagNewMask != 0 && jxutils.IsEmptyID(skuNameJdID) {
|
||||
if globals.EnableStoreWrite {
|
||||
spuName := jxutils.ComposeSpuName(skuExt.Prefix, skuExt.Name, 0)
|
||||
skus := []map[string]interface{}{
|
||||
@@ -461,7 +468,7 @@ func (p *PurchaseHandler) syncSkuNameAsSpu(db *dao.DaoDB, sku *model.Sku, skuExt
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil && !jxutils.IsFakeID(skuNameJdID) {
|
||||
if err == nil && !jxutils.IsEmptyID(skuNameJdID) {
|
||||
if sku.JdSyncStatus&model.SyncFlagNewMask != 0 { // 非首次新增SKU
|
||||
if globals.EnableStoreWrite {
|
||||
vendorSkuID2, err2 := api.JdAPI.AppendSku(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), skuName, price, jxutils.IntWeight2Float(sku.Weight), []string{skuExt.Img}, jxStatus2jdStatus(sku.Status), true, composeSkuSpec(sku.SpecQuality, sku.SpecUnit, skuExt.Unit), skuAddParams)
|
||||
|
||||
@@ -137,7 +137,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
if store.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
params["coordinatePoints"] = store.DeliveryRange
|
||||
} else {
|
||||
params["deliveryRangeRadius"] = utils.Str2Int64(store.DeliveryRange)
|
||||
params["deliveryRangeRadius"] = utils.Str2Int64WithDefault(store.DeliveryRange, 0)
|
||||
}
|
||||
}
|
||||
openTime2 := JxOperationTime2JdOperationTime(store.OpenTime2)
|
||||
@@ -147,7 +147,7 @@ func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName strin
|
||||
}
|
||||
_, params["closeStatus"] = JxStoreStatus2JdStatus(jxutils.MergeStoreStatus(store.Status, store.JdStoreStatus))
|
||||
globals.SugarLogger.Debug(utils.Format4Output(params, false))
|
||||
if globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if err = api.JdAPI.UpdateStoreInfo4Open(store.VendorStoreID, store.RealLastOperator, params); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -238,7 +238,7 @@ func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask
|
||||
if step != stepCount-1 {
|
||||
storeParams["outSystemId"] = utils.GetUUID()
|
||||
}
|
||||
if true { //globals.EnableStoreWrite {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.JdAPI.UpdateStoreInfo4Open(store.VendorStoreID, ctx.GetUserName(), storeParams)
|
||||
}
|
||||
return nil, err
|
||||
@@ -302,7 +302,7 @@ func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorStoreID s
|
||||
}
|
||||
|
||||
// 当前京东的storeCrud消息不会在门店状态改变时发送,所以意义不大,先放在这里
|
||||
func (c *PurchaseHandler) onStoreMsg(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
|
||||
func (c *PurchaseHandler) OnStoreMsg(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
|
||||
var err error
|
||||
if msg.StatusID == jdapi.StatusIDUpdateStore {
|
||||
var storeStatus int
|
||||
|
||||
@@ -3,6 +3,8 @@ package jd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
@@ -17,140 +19,137 @@ import (
|
||||
|
||||
type tStoreSkuBindExt struct {
|
||||
model.StoreSkuBind
|
||||
PricePercentage int
|
||||
VendorStoreID string `orm:"column(vendor_store_id)"`
|
||||
JdID int64 `orm:"column(jd_id)"`
|
||||
PricePercentage int
|
||||
CatPricePercentage int
|
||||
VendorStoreID string `orm:"column(vendor_store_id)"`
|
||||
JdID int64 `orm:"column(jd_id)"`
|
||||
}
|
||||
|
||||
// 京东到家,以有库存表示关注(认领)
|
||||
func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd SyncStoresSkus, storeID:%d, skuIDs:%v", storeID, skuIDs)
|
||||
sqlWhere0 := `
|
||||
WHERE (t1.jd_sync_status <> 0) AND t1.store_id = ?
|
||||
`
|
||||
sqlWhere := sqlWhere0
|
||||
sqlWhereParams := []interface{}{
|
||||
storeID,
|
||||
}
|
||||
|
||||
if len(skuIDs) > 0 {
|
||||
sqlWhere += " AND t1.sku_id IN (" + dao.GenQuestionMarks(len(skuIDs)) + ")"
|
||||
sqlWhereParams = append(sqlWhereParams, skuIDs)
|
||||
}
|
||||
|
||||
sql := `
|
||||
SELECT t3.jd_id, t1.*, t2.price_percentage, t2.vendor_store_id
|
||||
FROM store_sku_bind t1
|
||||
JOIN store_map t2 ON t1.store_id = t2.store_id AND t2.vendor_id = ? AND t2.deleted_at = ?
|
||||
JOIN sku t3 ON t1.sku_id = t3.id AND t3.deleted_at = ?
|
||||
` + sqlWhere + " ORDER BY t1.updated_at"
|
||||
var storeSkus []*tStoreSkuBindExt
|
||||
sqlParams := []interface{}{
|
||||
model.VendorIDJD,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &storeSkus, sql, append(sqlParams, sqlWhereParams...)...); err != nil {
|
||||
func (p *PurchaseHandler) syncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, db *dao.DaoDB, storeID int, storeSkus []*dao.StoreSkuSyncInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd syncStoreSkus, storeID:%d", storeID)
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJD)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
task := tasksch.NewParallelTask("SyncStoresSkus京东", tasksch.NewParallelConfig().SetBatchSize(jdapi.MaxStoreSkuBatchSize).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
batchSize := jdapi.MaxStoreSkuBatchSize
|
||||
// storeSkusLen := len(storeSkus)
|
||||
// if storeSkusLen < jdapi.MaxStoreSkuBatchSize/2 {
|
||||
// batchSize = 1
|
||||
// } else if storeSkusLen < jdapi.MaxStoreSkuBatchSize {
|
||||
// batchSize = (storeSkusLen + 1) / 2
|
||||
// } else if storeSkusLen < jdapi.MaxStoreSkuBatchSize*2 {
|
||||
// batchSize = (storeSkusLen + 2) / 3
|
||||
// }
|
||||
task := tasksch.NewParallelTask("syncStoreSkus京东", tasksch.NewParallelConfig().SetBatchSize(batchSize).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
var skuPriceInfoList []*jdapi.SkuPriceInfo
|
||||
var skuVendibilityList []*jdapi.StockVendibility
|
||||
var skuStockList []*jdapi.SkuStock
|
||||
stationNo := batchItemList[0].(*tStoreSkuBindExt).VendorStoreID
|
||||
var batchSkuIDs []int
|
||||
for _, v := range batchItemList {
|
||||
storeSku := v.(*tStoreSkuBindExt)
|
||||
alreadyAddStock := false
|
||||
if storeSku.JdSyncStatus&model.SyncFlagChangedMask != 0 {
|
||||
batchSkuIDs = append(batchSkuIDs, storeSku.SkuID)
|
||||
if storeSku.JdSyncStatus&(model.SyncFlagDeletedMask|model.SyncFlagNewMask) != 0 { // 关注或取消关注
|
||||
stock := &jdapi.SkuStock{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
StockQty: model.MaxStoreSkuStockQty,
|
||||
doWork := func(batchItemList []interface{}) (isPartialFailed bool, err error) {
|
||||
var skuPriceInfoList []*jdapi.SkuPriceInfo
|
||||
var skuVendibilityList []*jdapi.StockVendibility
|
||||
var skuStockList []*jdapi.SkuStock
|
||||
stationNo := storeDetail.VendorStoreID
|
||||
var batchBindIDs []int
|
||||
for _, v := range batchItemList {
|
||||
storeSku := v.(*dao.StoreSkuSyncInfo)
|
||||
alreadyAddStock := false
|
||||
if storeSku.StoreSkuSyncStatus&model.SyncFlagChangedMask != 0 || storeSku.BindID == 0 || storeSku.NameID == 0 {
|
||||
if storeSku.BindID > 0 {
|
||||
batchBindIDs = append(batchBindIDs, storeSku.BindID)
|
||||
}
|
||||
if storeSku.DeletedAt != utils.DefaultTimeValue {
|
||||
stock.StockQty = 0
|
||||
} else {
|
||||
alreadyAddStock = true
|
||||
}
|
||||
if stock.StockQty != 0 || !storeskulock.IsJdStoreSkuLocked(stationNo, storeSku.JdID) {
|
||||
skuStockList = append(skuStockList, stock)
|
||||
}
|
||||
}
|
||||
if storeSku.JdSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0 {
|
||||
skuPriceInfoList = append(skuPriceInfoList, &jdapi.SkuPriceInfo{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
Price: constrainPrice(jxutils.CaculateSkuVendorPrice(storeSku.Price, storeSku.PricePercentage)),
|
||||
})
|
||||
}
|
||||
if storeSku.JdSyncStatus&(model.SyncFlagSaleMask|model.SyncFlagNewMask) != 0 {
|
||||
vendibility := &jdapi.StockVendibility{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
DoSale: true,
|
||||
}
|
||||
if storeSku.Status != model.StoreSkuBindStatusNormal {
|
||||
vendibility.DoSale = false
|
||||
} else if !alreadyAddStock { // 如果是设置可售则自动将库存加满
|
||||
if storeSku.StoreSkuSyncStatus&(model.SyncFlagDeletedMask|model.SyncFlagNewMask) != 0 || storeSku.BindID == 0 || storeSku.NameID == 0 { // 关注或取消关注
|
||||
stock := &jdapi.SkuStock{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
StockQty: model.MaxStoreSkuStockQty,
|
||||
}
|
||||
skuStockList = append(skuStockList, stock)
|
||||
if storeSku.StoreSkuSyncStatus&model.SyncFlagDeletedMask != 0 || storeSku.DeletedAt != utils.DefaultTimeValue || storeSku.BindID == 0 || storeSku.NameID == 0 {
|
||||
stock.StockQty = 0
|
||||
} else {
|
||||
alreadyAddStock = true
|
||||
}
|
||||
if stock.StockQty != 0 || !storeskulock.IsJdStoreSkuLocked(stationNo, storeSku.JdID) {
|
||||
skuStockList = append(skuStockList, stock)
|
||||
}
|
||||
}
|
||||
if vendibility.DoSale || !storeskulock.IsJdStoreSkuLocked(stationNo, storeSku.JdID) {
|
||||
skuVendibilityList = append(skuVendibilityList, vendibility)
|
||||
if storeSku.StoreSkuSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0 {
|
||||
skuPriceInfoList = append(skuPriceInfoList, &jdapi.SkuPriceInfo{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
Price: constrainPrice(jxutils.CaculateSkuVendorPrice(int(storeSku.Price), int(storeDetail.PricePercentage), storeSku.CatPricePercentage)),
|
||||
})
|
||||
}
|
||||
if storeSku.StoreSkuSyncStatus&(model.SyncFlagSaleMask|model.SyncFlagNewMask) != 0 {
|
||||
vendibility := &jdapi.StockVendibility{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
DoSale: true,
|
||||
}
|
||||
if storeSku.StoreSkuStatus != model.StoreSkuBindStatusNormal {
|
||||
vendibility.DoSale = false
|
||||
} else if !alreadyAddStock { // 如果是设置可售则自动将库存加满
|
||||
stock := &jdapi.SkuStock{
|
||||
OutSkuId: utils.Int2Str(storeSku.SkuID),
|
||||
StockQty: model.MaxStoreSkuStockQty,
|
||||
}
|
||||
skuStockList = append(skuStockList, stock)
|
||||
}
|
||||
if vendibility.DoSale || !storeskulock.IsJdStoreSkuLocked(stationNo, storeSku.JdID) {
|
||||
skuVendibilityList = append(skuVendibilityList, vendibility)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
syncMask := 0
|
||||
errList := []error{}
|
||||
if globals.EnableStoreWrite {
|
||||
// todo 以下可以优化为并行操作
|
||||
globals.SugarLogger.Debug(utils.Format4Output(skuVendibilityList, false), utils.Format4Output(skuPriceInfoList, false), utils.Format4Output(skuStockList, false))
|
||||
if len(skuVendibilityList) > 0 {
|
||||
if _, err = api.JdAPI.BatchUpdateVendibility("", stationNo, skuVendibilityList, ctx.GetUserName()); err == nil {
|
||||
syncMask |= model.SyncFlagSaleMask
|
||||
} else {
|
||||
syncMask := 0
|
||||
errList := []error{}
|
||||
if globals.EnableJdStoreWrite {
|
||||
// todo 以下可以优化为并行操作
|
||||
globals.SugarLogger.Debug(utils.Format4Output(skuVendibilityList, false), utils.Format4Output(skuPriceInfoList, false), utils.Format4Output(skuStockList, false))
|
||||
if len(skuVendibilityList) > 0 {
|
||||
if _, err = api.JdAPI.BatchUpdateVendibility("", stationNo, skuVendibilityList, ctx.GetUserName()); err == nil {
|
||||
syncMask |= model.SyncFlagSaleMask
|
||||
} else {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
if (err == nil || isContinueWhenError) && len(skuStockList) > 0 {
|
||||
if _, err = api.JdAPI.BatchUpdateCurrentQtys("", stationNo, skuStockList, ctx.GetUserName()); err == nil {
|
||||
syncMask |= model.SyncFlagNewMask | model.SyncFlagDeletedMask
|
||||
} else {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
if (err == nil || isContinueWhenError) && len(skuPriceInfoList) > 0 {
|
||||
if _, err = api.JdAPI.UpdateVendorStationPrice("", stationNo, skuPriceInfoList); err == nil {
|
||||
syncMask |= model.SyncFlagPriceMask
|
||||
} else {
|
||||
isPartialFailed = isErrPartialFailed(err)
|
||||
errList = append(errList, partner.NewErrorCode(err.Error(), partner.ErrCodeChangePriceFailed, model.VendorIDJD))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errList) == 0 {
|
||||
syncMask = -1
|
||||
}
|
||||
if syncMask != 0 && len(batchBindIDs) > 0 {
|
||||
// db := dao.GetDB() // 多线程问题
|
||||
sql := `
|
||||
UPDATE store_sku_bind t1
|
||||
SET t1.jd_sync_status = t1.jd_sync_status & ?
|
||||
WHERE t1.id IN (` + dao.GenQuestionMarks(len(batchBindIDs)) + ")"
|
||||
if _, err = dao.ExecuteSQL(db, sql, ^syncMask, batchBindIDs); err != nil {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
if (err == nil || isContinueWhenError) && len(skuStockList) > 0 {
|
||||
if _, err = api.JdAPI.BatchUpdateCurrentQtys("", stationNo, skuStockList, ctx.GetUserName()); err == nil {
|
||||
syncMask |= model.SyncFlagNewMask | model.SyncFlagDeletedMask
|
||||
} else {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
if len(errList) == 1 {
|
||||
err = errList[0]
|
||||
} else if len(errList) > 1 {
|
||||
err = fmt.Errorf("%v", errList)
|
||||
}
|
||||
if (err == nil || isContinueWhenError) && len(skuPriceInfoList) > 0 {
|
||||
if _, err = api.JdAPI.UpdateVendorStationPrice("", stationNo, skuPriceInfoList); err == nil {
|
||||
syncMask |= model.SyncFlagPriceMask
|
||||
} else {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
return isPartialFailed, err
|
||||
}
|
||||
isErrPartialFailed, err := doWork(batchItemList)
|
||||
if isErrPartialFailed && len(batchItemList) > 1 {
|
||||
for _, v := range batchItemList {
|
||||
doWork([]interface{}{v})
|
||||
}
|
||||
}
|
||||
if len(errList) == 0 {
|
||||
syncMask = -1
|
||||
}
|
||||
if syncMask != 0 && len(batchSkuIDs) > 0 {
|
||||
db := dao.GetDB() // 多线程问题
|
||||
sql := `
|
||||
UPDATE store_sku_bind t1
|
||||
SET t1.jd_sync_status = t1.jd_sync_status & ?
|
||||
` + sqlWhere0 + " AND t1.sku_id IN (" + dao.GenQuestionMarks(len(batchSkuIDs)) + ")"
|
||||
if _, err = dao.ExecuteSQL(db, sql, ^syncMask, storeID, batchSkuIDs); err != nil {
|
||||
errList = append(errList, err)
|
||||
}
|
||||
}
|
||||
if len(errList) == 1 {
|
||||
err = errList[0]
|
||||
} else if len(errList) > 1 {
|
||||
err = fmt.Errorf("%v", errList)
|
||||
}
|
||||
return nil, err
|
||||
}, storeSkus)
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
@@ -160,112 +159,35 @@ func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasks
|
||||
return task.ID, err
|
||||
}
|
||||
|
||||
func isErrPartialFailed(err error) bool {
|
||||
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.Code() == jdapi.ResponseInnerCodePartialFailed {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) SyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd SyncStoresSkus, storeID:%d, skuIDs:%v", storeID, skuIDs)
|
||||
db := dao.GetDB()
|
||||
storeSkus, err := dao.GetStoreSkus(db, model.VendorIDJD, storeID, skuIDs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p.syncStoreSkus(ctx, parentTask, db, storeID, storeSkus, isAsync, isContinueWhenError)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) FullSyncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd FullSyncStoreSkus, storeID:%d", storeID)
|
||||
db := dao.GetDB()
|
||||
_, err = dao.SetStoreSkuSyncStatus(db, model.VendorIDJD, storeID, nil, model.SyncFlagModifiedMask|model.SyncFlagPriceMask|model.SyncFlagSaleMask)
|
||||
_, err = dao.SetStoreSkuSyncStatus(db, model.VendorIDJD, []int{storeID}, nil, model.SyncFlagStoreSkuOnlyMask)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
skus, err := dao.GetFullStoreSkus(db, model.VendorIDJD, storeID)
|
||||
storeSkus, err := dao.GetFullStoreSkus(db, model.VendorIDJD, storeID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p.syncStoreSkus(ctx, parentTask, db, storeID, skus, isAsync, isContinueWhenError)
|
||||
}
|
||||
|
||||
// todo 之后应该与SyncStoreSkus合并
|
||||
func (p *PurchaseHandler) syncStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, db *dao.DaoDB, storeID int, skus []*dao.StoreSkuSyncInfo, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd syncStoreSkus, storeID:%d, len(skus):%d", storeID, len(skus))
|
||||
if len(skus) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJD)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
stationNo := storeDetail.VendorStoreID
|
||||
task := tasksch.NewParallelTask("SyncStoresSkus京东", tasksch.NewParallelConfig().SetBatchSize(jdapi.MaxStoreSkuBatchSize).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (interface{}, error) {
|
||||
var skuPriceInfoList []*jdapi.SkuPriceInfo
|
||||
var skuVendibilityList []*jdapi.StockVendibility
|
||||
var skuStockList []*jdapi.SkuStock
|
||||
var batchSkuIDs []int
|
||||
for _, v := range batchItemList {
|
||||
storeSku := v.(*dao.StoreSkuSyncInfo)
|
||||
alreadyAddStock := false
|
||||
if storeSku.SkuSyncStatus&model.SyncFlagChangedMask != 0 || storeSku.BindID == 0 {
|
||||
if storeSku.BindID != 0 {
|
||||
batchSkuIDs = append(batchSkuIDs, storeSku.BindID)
|
||||
}
|
||||
if storeSku.SkuSyncStatus&(model.SyncFlagDeletedMask|model.SyncFlagNewMask) != 0 || storeSku.BindID == 0 { // 关注或取消关注
|
||||
stock := &jdapi.SkuStock{
|
||||
OutSkuId: utils.Int2Str(storeSku.ID),
|
||||
StockQty: model.MaxStoreSkuStockQty,
|
||||
}
|
||||
if storeSku.DeletedAt != utils.DefaultTimeValue || storeSku.BindID == 0 {
|
||||
stock.StockQty = 0
|
||||
} else {
|
||||
alreadyAddStock = true
|
||||
}
|
||||
if stock.StockQty != 0 || !storeskulock.IsJdStoreSkuLocked(stationNo, storeSku.JdID) {
|
||||
skuStockList = append(skuStockList, stock)
|
||||
}
|
||||
}
|
||||
if storeSku.SkuSyncStatus&(model.SyncFlagPriceMask|model.SyncFlagNewMask) != 0 {
|
||||
skuPriceInfoList = append(skuPriceInfoList, &jdapi.SkuPriceInfo{
|
||||
OutSkuId: utils.Int2Str(storeSku.ID),
|
||||
Price: constrainPrice(jxutils.CaculateSkuVendorPrice(int(storeSku.Price), int(storeDetail.PricePercentage))),
|
||||
})
|
||||
}
|
||||
if storeSku.SkuSyncStatus&(model.SyncFlagSaleMask|model.SyncFlagNewMask) != 0 {
|
||||
vendibility := &jdapi.StockVendibility{
|
||||
OutSkuId: utils.Int2Str(storeSku.ID),
|
||||
DoSale: true,
|
||||
}
|
||||
if storeSku.StoreSkuStatus != model.StoreSkuBindStatusNormal {
|
||||
vendibility.DoSale = false
|
||||
} else if !alreadyAddStock { // 如果是设置可售则自动将库存加满
|
||||
stock := &jdapi.SkuStock{
|
||||
OutSkuId: utils.Int2Str(storeSku.ID),
|
||||
StockQty: model.MaxStoreSkuStockQty,
|
||||
}
|
||||
skuStockList = append(skuStockList, stock)
|
||||
}
|
||||
if vendibility.DoSale || !storeskulock.IsJdStoreSkuLocked(stationNo, storeSku.JdID) {
|
||||
skuVendibilityList = append(skuVendibilityList, vendibility)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Debugf("jd syncStoreSkus sync detail, storeID:%d, skuVendibilityList:%s, skuPriceInfoList:%s, skuStockList:%s", storeID, utils.Format4Output(skuVendibilityList, true), utils.Format4Output(skuPriceInfoList, true), utils.Format4Output(skuStockList, true))
|
||||
if globals.EnableStoreWrite {
|
||||
// todo 以下可以优化为并行操作
|
||||
if len(skuVendibilityList) > 0 {
|
||||
_, err = api.JdAPI.BatchUpdateVendibility("", stationNo, skuVendibilityList, ctx.GetUserName())
|
||||
}
|
||||
if err == nil && len(skuStockList) > 0 {
|
||||
_, err = api.JdAPI.BatchUpdateCurrentQtys("", stationNo, skuStockList, ctx.GetUserName())
|
||||
}
|
||||
if err == nil && len(skuPriceInfoList) > 0 {
|
||||
_, err = api.JdAPI.UpdateVendorStationPrice("", stationNo, skuPriceInfoList)
|
||||
}
|
||||
}
|
||||
if err == nil && len(batchSkuIDs) > 0 {
|
||||
db := dao.GetDB() // 多线程问题
|
||||
sql := `
|
||||
UPDATE store_sku_bind t1
|
||||
SET t1.jd_sync_status = 0
|
||||
WHERE t1.id IN (` + dao.GenQuestionMarks(len(batchSkuIDs)) + ")"
|
||||
_, err = dao.ExecuteSQL(db, sql, batchSkuIDs)
|
||||
}
|
||||
return nil, err
|
||||
}, skus)
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
return task.ID, err
|
||||
return p.syncStoreSkus(ctx, parentTask, db, storeID, storeSkus, isAsync, isContinueWhenError)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteRemoteStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
@@ -278,3 +200,117 @@ func constrainPrice(price int) int {
|
||||
}
|
||||
return price
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoresSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeIDs []int) (storeSkuList []*model.StoreSkuBind, err error) {
|
||||
db := dao.GetDB()
|
||||
skuList, err := dao.GetSkus(db, nil, nil, []int{model.SkuStatusNormal}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var skuInfoList []*jdapi.BaseStockCenterRequest
|
||||
skuMap := make(map[int64]int)
|
||||
for _, sku := range skuList {
|
||||
if !jxutils.IsEmptyID(sku.JdID) {
|
||||
skuInfoList = append(skuInfoList, &jdapi.BaseStockCenterRequest{
|
||||
SkuId: sku.JdID,
|
||||
})
|
||||
skuMap[sku.JdID] = sku.ID
|
||||
}
|
||||
}
|
||||
for _, storeID := range storeIDs {
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJD)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, sku := range skuInfoList {
|
||||
sku.StationNo = storeDetail.VendorStoreID
|
||||
}
|
||||
task := tasksch.NewParallelTask("jd 获取京东门店商品信息", tasksch.NewParallelConfig().SetBatchSize(jdapi.MaxStoreSkuBatchSize), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
batchSkuInfoList := make([]*jdapi.BaseStockCenterRequest, len(batchItemList))
|
||||
batchSkuList := make([]int64, len(batchItemList))
|
||||
for k, v := range batchItemList {
|
||||
batchSkuInfoList[k] = v.(*jdapi.BaseStockCenterRequest)
|
||||
batchSkuList[k] = batchSkuInfoList[k].SkuId
|
||||
}
|
||||
stockInfo, err := api.JdAPI.QueryOpenUseable(batchSkuInfoList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
priceInfo, err := api.JdAPI.GetStationInfoList(storeDetail.VendorStoreID, batchSkuList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var batchStoreSkuList []*model.StoreSkuBind
|
||||
batchStoreSkuMap := make(map[int64]*model.StoreSkuBind)
|
||||
for _, v := range stockInfo {
|
||||
if v.UsableQty > 0 {
|
||||
batchSku := &model.StoreSkuBind{
|
||||
StoreID: storeID,
|
||||
SkuID: skuMap[v.SkuID],
|
||||
}
|
||||
if v.Vendibility == 0 {
|
||||
batchSku.Status = model.SkuStatusNormal
|
||||
} else {
|
||||
batchSku.Status = model.SkuStatusDontSale
|
||||
}
|
||||
batchStoreSkuMap[v.SkuID] = batchSku
|
||||
batchStoreSkuList = append(batchStoreSkuList, batchSku)
|
||||
}
|
||||
}
|
||||
for _, v := range priceInfo {
|
||||
if storeSku := batchStoreSkuMap[v.SkuID]; storeSku != nil {
|
||||
storeSku.Price = int(v.Price)
|
||||
}
|
||||
}
|
||||
return batchStoreSkuList, err
|
||||
}, skuInfoList)
|
||||
tasksch.AddChild(parentTask, task).Run()
|
||||
result, err := task.GetResult(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range result {
|
||||
storeSkuList = append(storeSkuList, v.(*model.StoreSkuBind))
|
||||
}
|
||||
}
|
||||
return storeSkuList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) SyncStoreProducts(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd SyncStoreProducts, storeID:%d", storeID)
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJD)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
storeSkuList, err := dao.GetStoreSkus2(db, model.VendorIDJD, storeID, skuIDs, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
task := tasksch.NewParallelTask("SyncStoreProducts京东", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeSku := batchItemList[0].(*dao.StoreSkuSyncInfo)
|
||||
if storeSku.VendorSkuID != "" && storeSku.StoreSkuStatus == model.SkuStatusNormal {
|
||||
if globals.EnableJdStoreWrite {
|
||||
synchronized, err2 := api.JdAPI.SyncProduct(storeDetail.VendorStoreID, storeSku.VendorSkuID)
|
||||
if err = err2; err == nil && synchronized {
|
||||
retVal = []int{1}
|
||||
}
|
||||
} else {
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, storeSkuList)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
result, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(result))
|
||||
}
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
66
business/partner/purchase/jd/store_sku2.go
Normal file
66
business/partner/purchase/jd/store_sku2.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.BareStoreSkuInfo) (outStoreSkuList []*partner.BareStoreSkuInfo, err error) {
|
||||
var batchSkuInfoList []*jdapi.BaseStockCenterRequest
|
||||
batchSkuList := partner.BareStoreSkuInfoList(inStoreSkuList).GetVendorSkuIDIntList()
|
||||
for _, v := range inStoreSkuList {
|
||||
if !dao.IsVendorThingIDEmpty(v.VendorSkuID) {
|
||||
batchSkuInfoList = append(batchSkuInfoList, &jdapi.BaseStockCenterRequest{
|
||||
StationNo: vendorStoreID,
|
||||
SkuId: utils.Str2Int64(v.VendorSkuID),
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(batchSkuInfoList) > 0 {
|
||||
var stockInfo []*jdapi.QueryStockResponse
|
||||
var priceInfo []*jdapi.StorePriceInfo
|
||||
task := tasksch.NewParallelTask("获取京东到家平台门店商品信息", tasksch.NewParallelConfig().SetParallelCount(2), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
subTaskID := batchItemList[0].(int)
|
||||
if subTaskID == 0 {
|
||||
stockInfo, err = api.JdAPI.QueryOpenUseable(batchSkuInfoList)
|
||||
} else {
|
||||
priceInfo, err = api.JdAPI.GetStationInfoList(vendorStoreID, batchSkuList)
|
||||
globals.SugarLogger.Debug(utils.Format4Output(priceInfo, false))
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
_, err = task.GetResult(0)
|
||||
if err == nil {
|
||||
storeSkuMap := make(map[int64]*partner.BareStoreSkuInfo)
|
||||
for _, v := range inStoreSkuList {
|
||||
storeSkuMap[utils.Str2Int64(v.VendorSkuID)] = v
|
||||
}
|
||||
for _, v := range stockInfo {
|
||||
outStoreSkuList = append(outStoreSkuList, storeSkuMap[v.SkuID])
|
||||
storeSkuMap[v.SkuID].Status = jdStoreSkuStatus2Jx(v.Vendibility)
|
||||
}
|
||||
for _, v := range priceInfo {
|
||||
storeSkuMap[v.SkuID].Price = v.Price
|
||||
}
|
||||
}
|
||||
}
|
||||
return outStoreSkuList, err
|
||||
}
|
||||
|
||||
func jdStoreSkuStatus2Jx(jdStoreSkuStatus int) (jxSkuStatus int) {
|
||||
if jdStoreSkuStatus == 0 {
|
||||
jxSkuStatus = model.SkuStatusNormal
|
||||
} else {
|
||||
jxSkuStatus = model.SkuStatusDontSale
|
||||
}
|
||||
return jxSkuStatus
|
||||
}
|
||||
169
business/partner/purchase/mtwm/act.go
Normal file
169
business/partner/purchase/mtwm/act.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package mtwm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||||
"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/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func actOrderRules2Mtwm(actOrderRules []*model.ActOrderRule) (actDetails []*mtwmapi.FullDiscountActDetail) {
|
||||
for _, v := range actOrderRules {
|
||||
actDetails = append(actDetails, &mtwmapi.FullDiscountActDetail{
|
||||
OriginalPrice: jxutils.IntPrice2Standard(v.SalePrice),
|
||||
ActPrice: jxutils.IntPrice2Standard(v.DeductPrice),
|
||||
})
|
||||
}
|
||||
return actDetails
|
||||
}
|
||||
|
||||
func storeSku2ActData(act *model.Act2, actStoreSku []*model.ActStoreSku2, handler func(int) bool) (actData []*mtwmapi.RetailDiscountActData) {
|
||||
for _, v := range actStoreSku {
|
||||
if handler == nil || handler(v.SyncStatus) {
|
||||
actData = append(actData, &mtwmapi.RetailDiscountActData{
|
||||
AppFoodCode: utils.Int2Str(v.SkuID),
|
||||
// UserType: 0,
|
||||
StartTime: act.BeginAt.Unix(),
|
||||
EndTime: act.EndAt.Unix(),
|
||||
OrderLimit: act.LimitCount,
|
||||
DayLimit: act.LimitDaily,
|
||||
// Period: "",
|
||||
// WeeksTime: "",
|
||||
SettingType: mtwmapi.SettingTypeAsPrice,
|
||||
ActPrice: jxutils.IntPrice2Standard(v.ActPrice),
|
||||
// DiscountCoefficient: 0,
|
||||
Sequence: int(v.ActPrice),
|
||||
ItemID: utils.Str2Int64WithDefault(v.VendorActID, 0),
|
||||
})
|
||||
}
|
||||
}
|
||||
return actData
|
||||
}
|
||||
|
||||
func storeSku2ActData4Delete(actStoreSku []*model.ActStoreSku2, handler func(int) bool) (actIDList []string) {
|
||||
for _, v := range actStoreSku {
|
||||
if handler == nil || handler(v.SyncStatus) {
|
||||
if v.VendorActID != "" {
|
||||
actIDList = append(actIDList, v.VendorActID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return actIDList
|
||||
}
|
||||
|
||||
func isCreateOrUpdate(syncStatus int) bool {
|
||||
return model.IsSyncStatusNeedCreate(syncStatus) || model.IsSyncStatusNeedUpdate(syncStatus)
|
||||
}
|
||||
|
||||
func createOneShopAct(act *model.Act2, storeMap *model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
actData := storeSku2ActData(act, actStoreSku, isCreateOrUpdate)
|
||||
if len(actData) > 0 {
|
||||
if globals.EnableMtwmStoreWrite {
|
||||
actResult, err2 := api.MtwmAPI.RetailDiscountBatchSave(storeMap.VendorStoreID, actData)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
actResultMap := make(map[string]*mtwmapi.RetailDiscountActResult)
|
||||
for _, v := range actResult {
|
||||
actResultMap[v.AppFoodCode] = v
|
||||
}
|
||||
for _, v := range actStoreSku {
|
||||
if result := actResultMap[utils.Int2Str(v.SkuID)]; result != nil {
|
||||
v.VendorActID = utils.Int64ToStr(result.ActID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, v := range actStoreSku {
|
||||
v.VendorActID = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CreateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
globals.SugarLogger.Debugf("mtwm CreateAct actID:%d", act.ID)
|
||||
if act.Type < model.ActOrderBegin {
|
||||
actStoreSkuMap := partner.ActStoreSku2Map(actStoreSku)
|
||||
task := tasksch.NewParallelTask("mtwm CreateAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
store := batchItemList[0].(*model.ActStore2)
|
||||
err = createOneShopAct(act, store, actStoreSkuMap[store.StoreID])
|
||||
return nil, err
|
||||
}, actStoreMap)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreMap2Remove, actStoreMap2Add, actStoreMap2Update []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
if act.Type < model.ActOrderBegin {
|
||||
actStoreSkuMap := partner.ActStoreSku2Map(actStoreSku)
|
||||
if len(actStoreMap2Remove) > 0 {
|
||||
if err = c.CancelAct(ctx, parentTask, act, actStoreMap2Remove, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range actStoreMap2Remove {
|
||||
delete(actStoreSkuMap, v.StoreID)
|
||||
}
|
||||
}
|
||||
if len(actStoreMap2Add) > 0 {
|
||||
if err = c.CreateAct(ctx, parentTask, act, actOrderRules, actStoreMap2Add, actStoreSku); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range actStoreMap2Add {
|
||||
delete(actStoreSkuMap, v.StoreID)
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("mtwm UpdateAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
v := batchItemList[0].(*model.ActStore2)
|
||||
if storeSkus := actStoreSkuMap[v.StoreID]; storeSkus != nil {
|
||||
if list := storeSku2ActData4Delete(storeSkus, model.IsSyncStatusNeedDelete); len(list) > 0 {
|
||||
if err = api.MtwmAPI.RetailDiscountDelete(v.VendorStoreID, list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = createOneShopAct(act, v, actStoreSkuMap[v.StoreID]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, actStoreMap2Update)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreMap []*model.ActStore2, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
if act.Type < model.ActOrderBegin {
|
||||
actStoreSkuMap := partner.ActStoreSku2Map(actStoreSku)
|
||||
task := tasksch.NewParallelTask("mtwm DeleteAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
v := batchItemList[0].(*model.ActStore2)
|
||||
actIDList := storeSku2ActData4Delete(actStoreSkuMap[v.StoreID], nil)
|
||||
if len(actIDList) > 0 {
|
||||
if globals.EnableMtwmStoreWrite {
|
||||
err = api.MtwmAPI.RetailDiscountDelete(v.VendorStoreID, actIDList)
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}, actStoreMap)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package mtwm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
@@ -19,11 +18,11 @@ func OnOrderCallbackMsg(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackRes
|
||||
}
|
||||
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDMTWM))
|
||||
}
|
||||
if msg.Cmd == mtwmapi.MsgTypeOrderRefund || msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund {
|
||||
/*if msg.Cmd == mtwmapi.MsgTypeOrderRefund || msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund {
|
||||
utils.CallFuncAsync(func() {
|
||||
OnFinancialMsg(msg)
|
||||
})
|
||||
} else if msg.Cmd == mtwmapi.MsgTypeStoreStatusChanged {
|
||||
} else */if msg.Cmd == mtwmapi.MsgTypeStoreStatusChanged {
|
||||
response = curPurchaseHandler.onStoreStatusChanged(msg)
|
||||
}
|
||||
}
|
||||
@@ -31,5 +30,5 @@ func OnOrderCallbackMsg(msg *mtwmapi.CallbackMsg) (response *mtwmapi.CallbackRes
|
||||
}
|
||||
|
||||
func GetOrderIDFromMsg(msg *mtwmapi.CallbackMsg) string {
|
||||
return msg.Data.Get(mtwmapi.KeyOrderID)
|
||||
return msg.FormData.Get(mtwmapi.KeyOrderID)
|
||||
}
|
||||
|
||||
@@ -18,13 +18,13 @@ const (
|
||||
// 存储美团退款订单结账信息
|
||||
func OnFinancialMsg(msg *mtwmapi.CallbackMsg) (err error) {
|
||||
if msg.Cmd == mtwmapi.MsgTypeOrderPartialRefund { // 部分退款处理
|
||||
orderData := msg.Data
|
||||
orderData := msg.FormData
|
||||
if orderData.Get("notify_type") == mtwmapi.NotifyTypeSuccess {
|
||||
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(curPurchaseHandler.AfsOrderDetail2Financial(orderData))
|
||||
}
|
||||
}
|
||||
if msg.Cmd == mtwmapi.MsgTypeOrderRefund { // todo 全额退款处理
|
||||
orderData := msg.Data
|
||||
orderData := msg.FormData
|
||||
if orderData.Get("notify_type") == mtwmapi.NotifyTypeSuccess {
|
||||
globals.SugarLogger.Debug(orderData.Get("order_id")) // 获得退款订单ID,去本地数据库拿?饿百消息推送只给了订单号,也没有通过订单号查询退款信息的接口
|
||||
afsOrderID := orderData.Get("order_id")
|
||||
@@ -45,7 +45,7 @@ func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.Orde
|
||||
VendorID: model.VendorIDMTWM,
|
||||
AfsOrderID: orderData.Get("order_id"),
|
||||
VendorOrderID: orderData.Get("order_id"),
|
||||
AfsCreateAt: utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp"))),
|
||||
AfsCreatedAt: utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp"))),
|
||||
// BoxMoney: orderFinancial.BoxMoney,
|
||||
// SkuBoxMoney: orderFinancial.SkuBoxMoney, // 美团的餐盒费已经拆到单条SKU里面去了,退款时直接计算用户支付sku金额就好了
|
||||
FreightUserMoney: orderFinancial.FreightMoney,
|
||||
@@ -64,9 +64,8 @@ func (p *PurchaseHandler) OrderFinancialDetail2Refund(orderFinancial *model.Orde
|
||||
}
|
||||
for _, sku := range orderFinancial.Skus {
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
VendorOrderID2: sku.VendorOrderID2,
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
// OrderFinancialID: sku.VendorOrderID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
@@ -93,7 +92,7 @@ func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData url.Values) (afsOrd
|
||||
VendorID: model.VendorIDMTWM,
|
||||
AfsOrderID: orderData.Get("order_id"),
|
||||
VendorOrderID: orderData.Get("order_id"),
|
||||
AfsCreateAt: utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp"))),
|
||||
AfsCreatedAt: utils.Timestamp2Time(utils.Str2Int64(orderData.Get("timestamp"))),
|
||||
RefundMoney: jxutils.StandardPrice2Int(utils.Str2Float64(orderData.Get("money"))),
|
||||
}
|
||||
// if orderData.Get("timestamp") != "" {
|
||||
|
||||
@@ -13,13 +13,13 @@ import (
|
||||
|
||||
func TestOnFinancialMsg(t *testing.T) {
|
||||
msg := &mtwmapi.CallbackMsg{
|
||||
Cmd: "orderRefund",
|
||||
Data: url.Values{},
|
||||
Cmd: "orderRefund",
|
||||
FormData: url.Values{},
|
||||
}
|
||||
msg.Data.Set("timestamp", utils.Int64ToStr(time.Now().Unix()))
|
||||
msg.Data.Set("order_id", "33762863167364867")
|
||||
msg.Data.Set("notify_type", "agree")
|
||||
msg.Data.Set("money", "23.56")
|
||||
msg.FormData.Set("timestamp", utils.Int64ToStr(time.Now().Unix()))
|
||||
msg.FormData.Set("order_id", "33762863167364867")
|
||||
msg.FormData.Set("notify_type", "agree")
|
||||
msg.FormData.Set("money", "23.56")
|
||||
food := []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"app_food_code": "123",
|
||||
@@ -40,8 +40,8 @@ func TestOnFinancialMsg(t *testing.T) {
|
||||
"box_price": 1,
|
||||
},
|
||||
}
|
||||
msg.Data.Set("food", string(utils.MustMarshal(food)))
|
||||
res := OnFinancialMsg(msg)
|
||||
msg.FormData.Set("food", string(utils.MustMarshal(food)))
|
||||
res := curPurchaseHandler.onAfsOrderMsg(msg)
|
||||
fmt.Println(res)
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ func bizStatusMtwm2JX(openLevel, online int) int {
|
||||
return model.StoreStatusDisabled
|
||||
} else {
|
||||
if openLevel == mtwmapi.PoiOpenLevelHaveRest {
|
||||
return model.StoreStatusClosed
|
||||
return model.StoreStatusHaveRest
|
||||
}
|
||||
}
|
||||
return model.StoreStatusOpened
|
||||
@@ -138,7 +138,7 @@ func bizStatusMtwm2JX(openLevel, online int) int {
|
||||
func bizStatusJX2Mtwm(status int) (openLevel, online int) {
|
||||
if status == model.StoreStatusDisabled {
|
||||
return mtwmapi.PoiOpenLevelHaveRest, mtwmapi.PoiStatusOffline
|
||||
} else if status == model.StoreStatusClosed {
|
||||
} else if status == model.StoreStatusHaveRest || status == model.StoreStatusClosed {
|
||||
return mtwmapi.PoiOpenLevelHaveRest, mtwmapi.PoiStatusOnline
|
||||
}
|
||||
return mtwmapi.PoiOpenLevelNormal, mtwmapi.PoiStatusOnline
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user