shan
This commit is contained in:
@@ -1,399 +0,0 @@
|
||||
package dada
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/delivery"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
const (
|
||||
maxOrderPrice = 6399 // 单位为分,达达最大价格,超过这个价格配送费会增加
|
||||
maxOrderWeight = 5000 // 5公斤
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindDadaCityCode = errors.New("不能找到美团配送站点配置")
|
||||
ErrExceedMaxDiffFee2Mtps = errors.New("与美团配送超价太多")
|
||||
)
|
||||
|
||||
var (
|
||||
CurDeliveryHandler *DeliveryHandler
|
||||
|
||||
dadaDistrictMap = map[string]string{
|
||||
"苏州工业园区": "工业园区",
|
||||
"郫都区": "郫县",
|
||||
"管城回族区": "管城区",
|
||||
"昆山市": "1",
|
||||
"常熟市": "1",
|
||||
"太仓市": "1",
|
||||
"虞山街道": "虞山镇",
|
||||
"常福街道": "虞山镇",
|
||||
}
|
||||
)
|
||||
|
||||
type DeliveryHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
CurDeliveryHandler = new(DeliveryHandler)
|
||||
partner.RegisterDeliveryPlatform(CurDeliveryHandler, true)
|
||||
}
|
||||
|
||||
func OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
|
||||
return CurDeliveryHandler.OnWaybillMsg(msg)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetVendorID() int {
|
||||
return model.VendorIDDada
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDDada))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
switch msg.OrderStatus {
|
||||
case dadaapi.OrderStatusWaitingForAccept:
|
||||
if dadaOrder, err := api.DadaAPI.QueryOrderInfo(msg.OrderID); err == nil {
|
||||
order.ActualFee = jxutils.StandardPrice2Int(dadaOrder.ActualFee)
|
||||
order.DesiredFee = jxutils.StandardPrice2Int(dadaOrder.DeliveryFee)
|
||||
}
|
||||
order.Status = model.WaybillStatusNew
|
||||
case dadaapi.OrderStatusAccepted:
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
case dadaapi.OrderStatusDelivering:
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
case dadaapi.OrderStatusFinished:
|
||||
order.Status = model.WaybillStatusDelivered
|
||||
case dadaapi.OrderStatusCanceled, dadaapi.OrderStatusExpired:
|
||||
order.Status = model.WaybillStatusCanceled
|
||||
case dadaapi.OrderStatusAddOrderFailed:
|
||||
order.Status = model.WaybillStatusFailed
|
||||
default:
|
||||
order.Status = model.WaybillStatusUnknown
|
||||
}
|
||||
return dadaapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), utils.Int2Str(order.Status))
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) callbackMsg2Waybill(msg *dadaapi.CallbackMsg) (retVal *model.Waybill) {
|
||||
retVal = &model.Waybill{
|
||||
VendorWaybillID: msg.ClientID,
|
||||
WaybillVendorID: model.VendorIDDada,
|
||||
CourierName: msg.DmName,
|
||||
CourierMobile: msg.DmMobile,
|
||||
VendorStatus: utils.Int2Str(msg.OrderStatus),
|
||||
Remark: msg.CancelReason,
|
||||
// StatusTime: utils.Timestamp2Time(int64(msg.UpdateTime)),
|
||||
}
|
||||
// dada太扯了,不同消息过来的时间格式不一样
|
||||
updateTime := int64(msg.UpdateTime)
|
||||
if updateTime > 2511789475 {
|
||||
updateTime = updateTime / 1000
|
||||
}
|
||||
retVal.StatusTime = utils.Timestamp2Time(updateTime)
|
||||
retVal.VendorOrderID, retVal.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
|
||||
return retVal
|
||||
}
|
||||
|
||||
func StoreDetail2ShopInfo(storeDetail *dao.StoreDetail2) (shopInfo *dadaapi.ShopInfo) {
|
||||
lng := jxutils.IntCoordinate2Standard(storeDetail.Lng)
|
||||
lat := jxutils.IntCoordinate2Standard(storeDetail.Lat)
|
||||
cityName := storeDetail.CityName
|
||||
districtName := storeDetail.DistrictName
|
||||
if dadaDistrictMap[districtName] != "" {
|
||||
if dadaDistrictMap[districtName] == "1" { // 区镇信息
|
||||
cityName = districtName
|
||||
districtName, _ = api.AutonaviAPI.GetCoordinateTownInfo(lng, lat)
|
||||
}
|
||||
if dadaDistrictMap[districtName] != "" {
|
||||
districtName = dadaDistrictMap[storeDetail.DistrictName]
|
||||
}
|
||||
}
|
||||
shopInfo = &dadaapi.ShopInfo{
|
||||
OriginShopID: storeDetail.VendorStoreID,
|
||||
StationName: globals.StoreName + "-" + storeDetail.Name,
|
||||
Business: dadaapi.BusinessTypeConvStore, // 故意设置成这个的
|
||||
CityName: cityName,
|
||||
AreaName: districtName,
|
||||
StationAddress: storeDetail.Address,
|
||||
Lng: lng,
|
||||
Lat: lat,
|
||||
ContactName: storeDetail.PayeeName,
|
||||
Phone: storeDetail.Tel1,
|
||||
}
|
||||
if storeDetail.CourierStatus >= model.StoreStatusClosed {
|
||||
shopInfo.Status = dadaapi.ShopStatusOnline
|
||||
} else {
|
||||
shopInfo.Status = dadaapi.ShopStatusOffline
|
||||
}
|
||||
return shopInfo
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) CreateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (vendorStoreID string, status int, err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
vendorStoreID, err = api.DadaAPI.ShopAdd(StoreDetail2ShopInfo(storeDetail))
|
||||
if err == nil {
|
||||
status = model.StoreAuditStatusOnline
|
||||
}
|
||||
} else {
|
||||
vendorStoreID = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
status = model.StoreAuditStatusOnline
|
||||
}
|
||||
return vendorStoreID, status, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) UpdateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.DadaAPI.ShopUpdate(StoreDetail2ShopInfo(storeDetail))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func dadaStatus2Jx(dadaStatus int) int {
|
||||
if dadaStatus == dadaapi.ShopStatusOnline {
|
||||
return model.StoreStatusOpened
|
||||
}
|
||||
return model.StoreStatusDisabled
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetStore(ctx *jxcontext.Context, storeID int, vendorStoreID string) (storeDetail *dao.StoreDetail2, err error) {
|
||||
shopInfo, err := api.DadaAPI.ShopDetail(vendorStoreID)
|
||||
if err == nil {
|
||||
storeDetail = &dao.StoreDetail2{
|
||||
Store: model.Store{
|
||||
Name: shopInfo.StationName,
|
||||
Address: shopInfo.StationAddress,
|
||||
Lng: jxutils.StandardCoordinate2Int(shopInfo.Lng),
|
||||
Lat: jxutils.StandardCoordinate2Int(shopInfo.Lat),
|
||||
PayeeName: shopInfo.ContactName,
|
||||
Tel1: shopInfo.Phone,
|
||||
},
|
||||
VendorID: model.VendorIDDada,
|
||||
VendorStoreID: shopInfo.OriginShopID,
|
||||
CourierStatus: dadaStatus2Jx(shopInfo.Status),
|
||||
AuditStatus: model.StoreAuditStatusOnline,
|
||||
CityName: shopInfo.CityName,
|
||||
DistrictName: shopInfo.AreaName,
|
||||
}
|
||||
}
|
||||
return storeDetail, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) IsErrStoreNotExist(err error) bool {
|
||||
return dadaapi.IsErrShopNotExist(err)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) IsErrStoreExist(err error) bool {
|
||||
return dadaapi.IsErrShopExist(err)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
|
||||
db := dao.GetDB()
|
||||
deliveryFeeInfo = &partner.WaybillFeeInfo{}
|
||||
billParams, err := c.getBillParams(db, order)
|
||||
if err == nil {
|
||||
var result *dadaapi.CreateOrderResponse
|
||||
if result, err = api.DadaAPI.QueryDeliverFee(billParams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deliveryFeeInfo.DeliveryFee = jxutils.StandardPrice2Int(result.Fee)
|
||||
deliveryFeeInfo.RefDeliveryFee = deliveryFeeInfo.DeliveryFee
|
||||
}
|
||||
return deliveryFeeInfo, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) getBillParams(db *dao.DaoDB, order *model.GoodsOrder) (billParams *dadaapi.OperateOrderParams, err error) {
|
||||
billParams = &dadaapi.OperateOrderParams{
|
||||
OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID),
|
||||
CargoPrice: jxutils.IntPrice2Standard(limitOrderPrice(order.ActualPayPrice)),
|
||||
IsPrepay: 0,
|
||||
ReceiverName: utils.FilterMb4(order.ConsigneeName),
|
||||
ReceiverAddress: utils.FilterMb4(order.ConsigneeAddress),
|
||||
ReceiverPhone: order.ConsigneeMobile,
|
||||
}
|
||||
if billParams.ShopNo, err = c.getDadaShopID(order, db); err == nil {
|
||||
if billParams.CityCode, err = c.getDataCityCodeFromOrder(order, db); err == nil {
|
||||
// storeTel := ""
|
||||
// storeID := jxutils.GetSaleStoreIDFromOrder(order)
|
||||
// storeDeatail, _ := dao.GetStoreDetail(db, storeID, order.VendorID)
|
||||
// if storeDeatail.Tel2 != "" {
|
||||
// storeTel = ",门店电话:" + storeDeatail.Tel2
|
||||
// }
|
||||
billParams.ReceiverLng, billParams.ReceiverLat, _ = jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType)
|
||||
billParams.Info = fmt.Sprintf("%s第%d号订单, %s", model.VendorChineseNames[order.VendorID], order.OrderSeq, utils.FilterMb4("客户电话:"+order.ConsigneeMobile+","+order.BuyerComment+"取货失败或配送遇到问题请联系18048531223,禁止未配送直接完成定单!"))
|
||||
billParams.CargoType = dadaapi.CargoTypeFresh
|
||||
billParams.CargoWeight = float64(jxutils.IntWeight2Float(limitOrderWeight(order.Weight)))
|
||||
billParams.CargoNum = order.GoodsCount
|
||||
}
|
||||
}
|
||||
return billParams, err
|
||||
}
|
||||
|
||||
// IDeliveryPlatformHandler
|
||||
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
|
||||
db := dao.GetDB()
|
||||
billParams, 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)
|
||||
AND vendor_order_id = ?
|
||||
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))
|
||||
if err = delivery.CallCreateWaybillPolicy(waybillList[0].ActualFee, maxDeliveryFee, order, model.VendorIDDada); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// result, err = api.DadaAPI.ReaddOrder(billParams, addParams)
|
||||
result, err = api.DadaAPI.ReaddOrder(billParams)
|
||||
} else {
|
||||
// 第一次创建
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
if false {
|
||||
result, err = api.DadaAPI.AddOrder(billParams)
|
||||
} else {
|
||||
if result, err = api.DadaAPI.QueryDeliverFee(billParams); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = delivery.CallCreateWaybillPolicy(jxutils.StandardPrice2Int(result.Fee), maxDeliveryFee, 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: jxutils.StandardPrice2Int(result.Fee),
|
||||
ActualFee: jxutils.StandardPrice2Int(result.Fee),
|
||||
}
|
||||
delivery.OnWaybillCreated(bill)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("测试环境不能真正创建运单")
|
||||
}
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
switch cancelReasonID {
|
||||
case partner.CancelWaybillReasonNotAcceptIntime:
|
||||
cancelReasonID = dadaapi.ReasonIDNobodyAccept
|
||||
case partner.CancelWaybillReasonSwitch2SelfFailed:
|
||||
cancelReasonID = dadaapi.ReasonIDClientDontWantItAnymore
|
||||
default:
|
||||
cancelReasonID = dadaapi.ReasonIDOther
|
||||
}
|
||||
_, err = api.DadaAPI.CancelOrder(bill.VendorOrderID, cancelReasonID, cancelReason)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) getDataCityCodeFromOrder(order *model.GoodsOrder, db *dao.DaoDB) (retVal string, err error) {
|
||||
jxStoreID := jxutils.GetSaleStoreIDFromOrder(order)
|
||||
sql := `
|
||||
SELECT t2.tel_code
|
||||
FROM store t1
|
||||
JOIN place t2 on t1.city_code = t2.code
|
||||
WHERE t1.id = ?
|
||||
`
|
||||
codeInfo := &struct {
|
||||
TelCode string
|
||||
}{}
|
||||
if err = dao.GetRow(db, codeInfo, sql, jxStoreID); err != nil {
|
||||
globals.SugarLogger.Errorf("GetDataCityCodeFromOrder can not find store info for vendorID:%d, store:%s, error:%v", order.VendorID, order.VendorStoreID, err)
|
||||
if err == nil {
|
||||
err = ErrCanNotFindDadaCityCode
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return codeInfo.TelCode, nil
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) getDadaShopID(order *model.GoodsOrder, db *dao.DaoDB) (retVal string, err error) {
|
||||
saleStoreID := jxutils.GetSaleStoreIDFromOrder(order)
|
||||
storeCourierList, err2 := dao.GetOpenedStoreCouriersByStoreID(db, saleStoreID, model.VendorIDDada)
|
||||
if err = err2; err != nil && !dao.IsNoRowsError(err) {
|
||||
return "", err
|
||||
}
|
||||
if len(storeCourierList) == 0 {
|
||||
return "", partner.ErrStoreHaveNoCourier
|
||||
}
|
||||
retVal = storeCourierList[0].VendorStoreID
|
||||
if beego.BConfig.RunMode == "dev" {
|
||||
retVal = "test_0001"
|
||||
}
|
||||
return retVal, nil
|
||||
}
|
||||
|
||||
func limitOrderPrice(price int64) int64 {
|
||||
if price > maxOrderPrice {
|
||||
return maxOrderPrice
|
||||
}
|
||||
return price
|
||||
}
|
||||
|
||||
func limitOrderWeight(weight int) int {
|
||||
if weight > maxOrderWeight {
|
||||
return maxOrderWeight
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.DadaAPI.ComplaintRider(bill.VendorOrderID, resonID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
|
||||
order, err := api.DadaAPI.QueryOrderInfo(vendorOrderID)
|
||||
if err == nil {
|
||||
tipFee = jxutils.StandardPrice2Int(order.Tips)
|
||||
}
|
||||
return tipFee, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.DadaAPI.AddTip(vendorOrderID, jxutils.IntPrice2Standard(tipFee), cityCode, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) {
|
||||
order, err := api.DadaAPI.QueryOrderInfo(vendorOrderID)
|
||||
if err == nil {
|
||||
lng = utils.Str2Float64WithDefault(order.TransporterLng, 0)
|
||||
lat = utils.Str2Float64WithDefault(order.TransporterLat, 0)
|
||||
}
|
||||
return lng, lat, err
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package dada
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"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/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestCreateWaybill(t *testing.T) {
|
||||
orderID := "817540316000041"
|
||||
if order, err := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil {
|
||||
// globals.SugarLogger.Debug(order)
|
||||
_, err = CurDeliveryHandler.CreateWaybill(order, 0)
|
||||
if err == nil {
|
||||
time.Sleep(1 * time.Second)
|
||||
bill := &model.Waybill{
|
||||
VendorOrderID: orderID,
|
||||
WaybillVendorID: model.VendorIDDada,
|
||||
}
|
||||
err = CurDeliveryHandler.CancelWaybill(bill, partner.CancelWaybillReasonOther, "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRidderPosition(t *testing.T) {
|
||||
lng, lat, err := CurDeliveryHandler.GetRidderPosition(jxcontext.AdminCtx, "", "80704840263399812", "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("lng:%f, lat:%f", lng, lat)
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package delivery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
warningDistance = 10 // 公里
|
||||
warningWeight = 50 * 1000 // 克
|
||||
// maxDiffFee2Mtps = 200 // 与美团配送最多差价
|
||||
// maxAddFee = 200 // 最大增加费用,单位为分,超过不发三方配送了
|
||||
defMaxDeliveryFee = 10000 // 创建运单最高价
|
||||
alarmFee = 1500 // 配送费报警阈值
|
||||
)
|
||||
|
||||
func CallCreateWaybillPolicy(deliveryFee, maxDeliveryFee int64, order *model.GoodsOrder, waybillVendorID int) (err error) {
|
||||
if maxDeliveryFee <= 0 || maxDeliveryFee > defMaxDeliveryFee {
|
||||
maxDeliveryFee = defMaxDeliveryFee
|
||||
}
|
||||
if deliveryFee > maxDeliveryFee {
|
||||
errStr := fmt.Sprintf("超最高限价, 所需运费:%s, 最高限价:%s", jxutils.IntPrice2StandardCurrencyString(deliveryFee), jxutils.IntPrice2StandardCurrencyString(maxDeliveryFee))
|
||||
err = fmt.Errorf(errStr)
|
||||
globals.SugarLogger.Debugf("CallCreateWaybillPolicy orderID:%s, 平台:%s运单,创建出错:%s", order.VendorOrderID, model.VendorChineseNames[waybillVendorID], errStr)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CalculateDeliveryFee(db *dao.DaoDB, jxStoreID int, hint string, consigneeLng, consigneeLat, coordinateType, weight int, billTime time.Time) (deliveryFee, addFee int64, err error) {
|
||||
globals.SugarLogger.Debugf("CalculateOrderDeliveryFee orderID:%s", hint)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
var lng, lat float64
|
||||
priceInfo := &struct {
|
||||
CityPrice int64
|
||||
DistrictPrice int64
|
||||
Lng int
|
||||
Lat int
|
||||
}{}
|
||||
if err = dao.GetRow(db, priceInfo, `
|
||||
SELECT
|
||||
t2.mtps_price city_price, t2.mtps_price district_price, t1.lng, t1.lat
|
||||
FROM store t1
|
||||
LEFT JOIN place t2 ON t2.level = 2 AND t2.code = t1.city_code
|
||||
LEFT JOIN place t3 ON t3.level = 3 AND t2.code = t1.district_code
|
||||
WHERE t1.id = ? AND t1.deleted_at = ?
|
||||
`, jxStoreID, utils.DefaultTimeValue); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
lng = jxutils.IntCoordinate2Standard(priceInfo.Lng)
|
||||
lat = jxutils.IntCoordinate2Standard(priceInfo.Lat)
|
||||
if deliveryFee = priceInfo.DistrictPrice; deliveryFee == 0 {
|
||||
deliveryFee = priceInfo.CityPrice
|
||||
}
|
||||
if deliveryFee == 0 {
|
||||
// globals.SugarLogger.Warnf("CalculateOrderDeliveryFee 查不到美团配送价格 orderID:%s", hint)
|
||||
deliveryFee = 650
|
||||
}
|
||||
if lng == 0 || lat == 0 {
|
||||
globals.SugarLogger.Infof("[运营]计算订单配送费orderID:%s,门店:%d没有坐标信息", hint, jxStoreID)
|
||||
return 0, 0, fmt.Errorf("找不到门店:%d的坐标", jxStoreID)
|
||||
}
|
||||
lng2, lat2, _ := jxutils.IntCoordinate2MarsStandard(consigneeLng, consigneeLat, coordinateType)
|
||||
|
||||
var distanceAddFee, weightAddFee, timeAddFee int64
|
||||
|
||||
// 距离加价
|
||||
distance := jxutils.WalkingDistance(lng, lat, lng2, lat2)
|
||||
if distance > warningDistance {
|
||||
globals.SugarLogger.Infof("[运营]计算订单配送费orderID:%s,距离%.3fkm太远,请检查门店坐标信息", hint, distance)
|
||||
}
|
||||
distanceAddFee = int64(jxutils.CalcStageValue([][]float64{
|
||||
[]float64{
|
||||
7,
|
||||
300,
|
||||
},
|
||||
[]float64{
|
||||
5,
|
||||
200,
|
||||
},
|
||||
[]float64{
|
||||
3,
|
||||
100,
|
||||
},
|
||||
}, distance))
|
||||
|
||||
// 重量加价
|
||||
if weight > warningWeight {
|
||||
globals.SugarLogger.Infof("[运营]计算订单配送费orderID:%s,重量:%dg太重,请检查商品属性", hint, weight)
|
||||
}
|
||||
weightAddFee = int64(jxutils.CalcStageValue([][]float64{
|
||||
[]float64{
|
||||
20,
|
||||
200,
|
||||
},
|
||||
[]float64{
|
||||
10,
|
||||
100,
|
||||
},
|
||||
[]float64{
|
||||
5,
|
||||
50,
|
||||
},
|
||||
}, float64(weight)/1000))
|
||||
|
||||
// 其它加价
|
||||
hour, min, sec := billTime.Clock()
|
||||
totalSeconds := hour*3600 + min*60 + sec
|
||||
// 午高峰加价
|
||||
if totalSeconds >= 11*3600 && totalSeconds <= 14*3600 { // 11:00 -- 14:00
|
||||
timeAddFee = jxutils.StandardPrice2Int(2)
|
||||
} else if totalSeconds >= 21*3600 || totalSeconds <= 6*3600 { // 21:00 -- 06:00 夜间加价
|
||||
timeAddFee = jxutils.StandardPrice2Int(3)
|
||||
}
|
||||
addFee = distanceAddFee + weightAddFee + timeAddFee
|
||||
globals.SugarLogger.Debugf("CalculateOrderDeliveryFee orderID:%s, deliveryFee:%d addFee:%d, distance:%.3fkm distanceAddFee:%d, weight:%dg weightAddFee:%d, time:%s timeAddFee:%d",
|
||||
hint, deliveryFee, addFee, distance, distanceAddFee, weight, weightAddFee, utils.Time2TimeStr(billTime), timeAddFee)
|
||||
return deliveryFee + addFee, addFee, nil
|
||||
}
|
||||
|
||||
func CalculateOrderDeliveryFee(order *model.GoodsOrder, billTime time.Time, db *dao.DaoDB) (deliveryFee, addFee int64, err error) {
|
||||
return CalculateDeliveryFee(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorOrderID, order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType, order.Weight, billTime)
|
||||
}
|
||||
|
||||
func CalculateBillDeliveryFee(bill *model.Waybill) (deliveryFee, addFee int64) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID)
|
||||
if err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
deliveryFee, addFee, _ = CalculateOrderDeliveryFee(order, bill.StatusTime, nil)
|
||||
return deliveryFee, addFee
|
||||
}
|
||||
|
||||
func OnWaybillCreated(waybill *model.Waybill) {
|
||||
deliveryFee := int64(math.Max(float64(waybill.DesiredFee), float64(waybill.ActualFee)))
|
||||
if deliveryFee > alarmFee {
|
||||
globals.SugarLogger.Infof("[运营]%s订单, orderID:%s, 成功创建%s运单:%s, 配送费:%s太高(大于%s),请知悉!", model.VendorChineseNames[waybill.OrderVendorID], waybill.VendorOrderID,
|
||||
model.VendorChineseNames[waybill.WaybillVendorID], waybill.VendorWaybillID, jxutils.IntPrice2StandardCurrencyString(deliveryFee), jxutils.IntPrice2StandardCurrencyString(alarmFee))
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package jdeclp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdeclpapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
CurDeliveryHandler *DeliveryHandler
|
||||
)
|
||||
|
||||
type DeliveryHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
CurDeliveryHandler = new(DeliveryHandler)
|
||||
partner.RegisterDeliveryPlatform(CurDeliveryHandler, true)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetVendorID() int {
|
||||
return model.VendorIDJDWL
|
||||
}
|
||||
|
||||
func OnWaybillMsg() {
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) OnWaybillMsg() {
|
||||
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) CreateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (vendorStoreID string, status int, err error) {
|
||||
return vendorStoreID, status, err
|
||||
}
|
||||
func (c *DeliveryHandler) GetStore(ctx *jxcontext.Context, storeID int, vendorStoreID string) (storeDetail *dao.StoreDetail2, err error) {
|
||||
return storeDetail, err
|
||||
}
|
||||
func (c *DeliveryHandler) IsErrStoreNotExist(err error) bool {
|
||||
return false
|
||||
}
|
||||
func (c *DeliveryHandler) IsErrStoreExist(err error) bool {
|
||||
return false
|
||||
}
|
||||
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
|
||||
storeID := jxutils.GetShowStoreIDFromOrder(order)
|
||||
stores, err := dao.GetStoreList(dao.GetDB(), []int{storeID}, nil, nil, nil, "")
|
||||
if len(stores) == 0 || err != nil {
|
||||
return bill, fmt.Errorf("未查询到该门店! 门店id :[%v]", storeID)
|
||||
}
|
||||
vendorWaybillID, err := api.JdEclpAPI.WaybillReceive(&jdeclpapi.WaybillReceiveParam{
|
||||
SalePlat: jdeclpapi.SalePlatSourceDelivery,
|
||||
CustomerCode: jdeclpapi.CustomerCode,
|
||||
OrderID: order.VendorOrderID,
|
||||
SenderName: order.StoreName,
|
||||
SenderAddress: stores[0].Address,
|
||||
SenderTel: stores[0].Tel1,
|
||||
ReceiveName: order.ConsigneeName,
|
||||
ReceiveAddress: order.ConsigneeAddress,
|
||||
ReceiveTel: order.ConsigneeMobile,
|
||||
Weight: order.Weight,
|
||||
Vloumn: order.Weight,
|
||||
PackageCount: 1,
|
||||
Description: "生鲜",
|
||||
Aging: 5,
|
||||
PromiseTimeType: 1, //特惠送
|
||||
})
|
||||
waybill := &model.Waybill{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
OrderVendorID: model.VendorIDJDShop,
|
||||
VendorWaybillID: vendorWaybillID,
|
||||
WaybillVendorID: model.VendorIDJDWL,
|
||||
Status: model.WaybillStatusDelivering,
|
||||
WaybillCreatedAt: time.Now(),
|
||||
StatusTime: time.Now(),
|
||||
WaybillFinishedAt: utils.DefaultTimeValue,
|
||||
DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled,
|
||||
}
|
||||
dao.CreateEntity(dao.GetDB(), waybill)
|
||||
return waybill, err
|
||||
}
|
||||
func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
err = api.JdEclpAPI.CancelWayBill(&jdeclpapi.CancelWayBillParam{
|
||||
WaybillCode: bill.VendorWaybillID,
|
||||
CustomerCode: jdeclpapi.CustomerCode,
|
||||
Source: "JOS",
|
||||
CancelReason: cancelReason,
|
||||
OperatorName: "jxadmin",
|
||||
})
|
||||
return err
|
||||
}
|
||||
func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
|
||||
return deliveryFeeInfo, err
|
||||
}
|
||||
func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package jdeclp
|
||||
|
||||
import "git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package mtps
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtpsapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
fakeContactEmail = "fakeemail@163.com"
|
||||
)
|
||||
|
||||
var (
|
||||
auditStatusMap = map[int]int{
|
||||
mtpsapi.ShopStatusAuditCreated: model.StoreAuditStatusCreated,
|
||||
mtpsapi.ShopStatusAuditRejected: model.StoreAuditStatusRejected,
|
||||
mtpsapi.ShopStatusAuditPassed: model.StoreAuditStatusCreated,
|
||||
mtpsapi.ShopStatusAuditOnline: model.StoreAuditStatusOnline,
|
||||
}
|
||||
)
|
||||
|
||||
func getAuditStatus(vendorAuditStatus int) int {
|
||||
if auditStatus, ok := auditStatusMap[vendorAuditStatus]; ok {
|
||||
return auditStatus
|
||||
}
|
||||
return model.StoreAuditStatusCreated
|
||||
}
|
||||
|
||||
func OnStoreStatus(msg *mtpsapi.CallbackShopStatusMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
return curDeliveryHandler.OnStoreStatus(msg)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) OnStoreStatus(msg *mtpsapi.CallbackShopStatusMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
globals.SugarLogger.Debugf("mtps OnStoreStatus, msg:%s", utils.Format4Output(msg, true))
|
||||
err := partner.CurStoreManager.OnCourierStoreStatusChanged(jxcontext.AdminCtx, msg.ShopID, model.VendorIDMTPS, getAuditStatus(msg.Status))
|
||||
retVal = mtpsapi.Err2CallbackResponse(err, "mtps OnStoreStatus")
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) CreateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (vendorStoreID string, status int, err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
businessHours := []*mtpsapi.BusinessHour{
|
||||
&mtpsapi.BusinessHour{
|
||||
BeginTime: "06:00",
|
||||
EndTime: "22:00",
|
||||
},
|
||||
}
|
||||
shopInfo := &mtpsapi.ShopInfo{
|
||||
ShopID: storeDetail.VendorStoreID,
|
||||
ShopName: storeDetail.Name,
|
||||
Category: mtpsapi.ShopCategoryFruit,
|
||||
SecondCategory: mtpsapi.ShopCategoryFruitFruit,
|
||||
ContactName: storeDetail.PayeeName,
|
||||
ContactPhone: storeDetail.Tel1,
|
||||
ContactEmail: fakeContactEmail,
|
||||
ShopAddress: storeDetail.Address,
|
||||
ShopLng: storeDetail.Lng,
|
||||
ShopLat: storeDetail.Lat,
|
||||
CoordinateType: mtpsapi.CoordinateTypeMars,
|
||||
BusinessHours: string(utils.MustMarshal(businessHours)),
|
||||
}
|
||||
shopStatus := mtpsapi.ShopStatusAuditCreated
|
||||
if globals.EnableStoreWrite {
|
||||
shopStatus, err = api.MtpsAPI.ShopCreate(shopInfo)
|
||||
if err == nil {
|
||||
vendorStoreID = shopInfo.ShopID
|
||||
status = getAuditStatus(shopStatus)
|
||||
}
|
||||
} else {
|
||||
vendorStoreID = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
status = model.StoreAuditStatusOnline
|
||||
}
|
||||
}
|
||||
return vendorStoreID, status, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetStore(ctx *jxcontext.Context, storeID int, vendorStoreID string) (storeDetail *dao.StoreDetail2, err error) {
|
||||
shopInfo, err := api.MtpsAPI.ShopQuery(vendorStoreID)
|
||||
if err == nil {
|
||||
storeDetail = &dao.StoreDetail2{
|
||||
Store: model.Store{
|
||||
Name: shopInfo.ShopName,
|
||||
CityCode: shopInfo.City,
|
||||
PayeeName: shopInfo.ContactName,
|
||||
Tel1: shopInfo.ContactPhone,
|
||||
Address: shopInfo.ShopAddress,
|
||||
Lng: shopInfo.ShopLng,
|
||||
Lat: shopInfo.ShopLat,
|
||||
},
|
||||
VendorID: model.VendorIDMTPS,
|
||||
VendorStoreID: shopInfo.ShopID,
|
||||
// CourierStatus: model.StoreStatusOpened,
|
||||
// AuditStatus: model.StoreAuditStatusOnline,
|
||||
}
|
||||
result, err := api.MtpsAPI.GetStoreStatus(shopInfo.ShopName)
|
||||
if err == nil {
|
||||
storeDetail.AuditStatus = mtpsOpenTypeToJx(result.DataList[0].OpenType)
|
||||
storeDetail.CourierStatus = mtpsOpenTypeToJx2(result.DataList[0].OpenType)
|
||||
}
|
||||
}
|
||||
return storeDetail, err
|
||||
}
|
||||
|
||||
func mtpsOpenTypeToJx(openType int) (status int) {
|
||||
if openType == 0 {
|
||||
status = model.StoreAuditStatusRejected
|
||||
} else {
|
||||
status = model.StoreAuditStatusOnline
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func mtpsOpenTypeToJx2(openType int) (status int) {
|
||||
if openType == 0 {
|
||||
status = model.StoreStatusClosed
|
||||
} else {
|
||||
status = model.StoreStatusOpened
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) IsErrStoreNotExist(err error) bool {
|
||||
return mtpsapi.IsErrShopNotExist(err)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) IsErrStoreExist(err error) bool {
|
||||
return mtpsapi.IsErrShopExist(err)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) UpdateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (err error) {
|
||||
// if globals.EnableStoreWrite {
|
||||
// err = api.MtpsAPI.PagePoiUpdate(storeDetail.VendorStoreID, storeDetail.PayeeName, storeDetail.Tel1, fakeContactEmail)
|
||||
// }
|
||||
return err
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
package mtps
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtpsapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/delivery"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
const (
|
||||
// maxOrderPrice = 6399 // 单位为分,达达最大价格,超过这个价格配送费会增加
|
||||
maxOrderWeight = 5000 // 5公斤
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindMTPSStore = errors.New("不能找到美团配送站点配置")
|
||||
ErrStoreNoPriceInfo = errors.New("找不到门店的美团配送价格信息")
|
||||
)
|
||||
|
||||
var (
|
||||
curDeliveryHandler *DeliveryHandler
|
||||
)
|
||||
|
||||
type DeliveryHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
if api.MtpsAPI != nil {
|
||||
curDeliveryHandler = new(DeliveryHandler)
|
||||
partner.RegisterDeliveryPlatform(curDeliveryHandler, true)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetVendorID() int {
|
||||
return model.VendorIDMTPS
|
||||
}
|
||||
|
||||
func OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
return curDeliveryHandler.OnWaybillMsg(msg)
|
||||
}
|
||||
|
||||
func OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
return curDeliveryHandler.OnWaybillExcept(msg)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDMTPS))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
order := &model.Waybill{
|
||||
VendorWaybillID: msg.MtPeisongID,
|
||||
VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID),
|
||||
WaybillVendorID: model.VendorIDMTPS,
|
||||
CourierName: msg.CourierName,
|
||||
CourierMobile: msg.CourierPhone,
|
||||
Status: model.WaybillStatusUnknown, // todo 这里要再确定一下是否只要收到订单异常消息就只简单当成一个消息
|
||||
VendorStatus: utils.Int2Str(msg.ExceptionCode),
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
}
|
||||
order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
|
||||
retVal = mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept")
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDDada))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
|
||||
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.Status = model.WaybillStatusAccepted
|
||||
case mtpsapi.OrderStatusPickedUp:
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
case mtpsapi.OrderStatusDeliverred:
|
||||
order.Status = model.WaybillStatusDelivered
|
||||
case mtpsapi.OrderStatusCanceled:
|
||||
order.Status = model.WaybillStatusCanceled
|
||||
default:
|
||||
globals.SugarLogger.Warnf("onWaybillMsg unknown msg:%v", msg)
|
||||
return mtpsapi.SuccessResponse
|
||||
}
|
||||
order2, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.OrderVendorID)
|
||||
// order2, _ := dao.GetSimpleOrder(dao.GetDB(), order.VendorOrderID)
|
||||
//查不到订单可能就是果园的订单
|
||||
if order2 == nil {
|
||||
c.pushToGy(msg)
|
||||
return mtpsapi.SuccessResponse
|
||||
}
|
||||
return mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) pushToGy(msg *mtpsapi.CallbackOrderMsg) {
|
||||
cl := http.Client{}
|
||||
params := make(map[string]interface{})
|
||||
params["mt_peisong_id"] = msg.MtPeisongID
|
||||
params["courier_name"] = msg.CourierName
|
||||
params["delivery_id"] = msg.DeliveryID
|
||||
params["appkey"] = msg.AppKey
|
||||
params["order_id"] = msg.OrderID
|
||||
params["courier_phone"] = msg.CourierPhone
|
||||
params["status"] = msg.Status
|
||||
params["timestamp"] = msg.Timestamp
|
||||
params["cancel_reason_id"] = msg.CancelReasonId
|
||||
params["cancel_reason"] = msg.CancelReason
|
||||
urls := utils.Map2URLValues(params)
|
||||
sign := signParams(urls)
|
||||
params["sign"] = sign
|
||||
globals.SugarLogger.Debugf("pushToGy", utils.Format4Output(msg, false))
|
||||
request, err := http.NewRequest(http.MethodPost, "http://callback-jxgy.jxc4.com/mtps/status", strings.NewReader(utils.Map2URLValues(params).Encode()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
cl.Do(request)
|
||||
}
|
||||
|
||||
func signParams(params url.Values) string {
|
||||
keys := make([]string, 0)
|
||||
for k := range params {
|
||||
if k != "sign" {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
finalStr := "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE"
|
||||
for _, key := range keys {
|
||||
valStr := strings.Join(params[key], "")
|
||||
if valStr != "" {
|
||||
finalStr += key + valStr
|
||||
}
|
||||
}
|
||||
|
||||
// baseapi.SugarLogger.Debug(finalStr)
|
||||
return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr)))
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) (retVal *model.Waybill) {
|
||||
retVal = &model.Waybill{
|
||||
VendorWaybillID: msg.MtPeisongID,
|
||||
VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID),
|
||||
WaybillVendorID: model.VendorIDMTPS,
|
||||
CourierName: msg.CourierName,
|
||||
CourierMobile: msg.CourierPhone,
|
||||
VendorStatus: utils.Int2Str(msg.Status),
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
Remark: msg.CancelReason,
|
||||
}
|
||||
retVal.VendorOrderID, retVal.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
|
||||
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, maxDeliveryFee int64) (bill *model.Waybill, err error) {
|
||||
db := dao.GetDB()
|
||||
deliveryFee, _, err := delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
|
||||
if err == nil {
|
||||
if err = delivery.CallCreateWaybillPolicy(deliveryFee, maxDeliveryFee, order, model.VendorIDMTPS); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 忽略坐标转换错误,即使是转换出错,也只能当成转换成功来处理,底层会有错误日志输出
|
||||
lngFloat, latFloat, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType)
|
||||
billParams := &mtpsapi.CreateOrderByShopParam{
|
||||
OrderID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID),
|
||||
DeliveryServiceCode: mtpsapi.DeliveryServiceCodeRapid,
|
||||
ReceiverName: utils.FilterMb4(order.ConsigneeName),
|
||||
ReceiverAddress: utils.FilterMb4(order.ConsigneeAddress),
|
||||
ReceiverPhone: order.ConsigneeMobile,
|
||||
CoordinateType: model.CoordinateTypeMars,
|
||||
ReceiverLng: jxutils.StandardCoordinate2Int(lngFloat),
|
||||
ReceiverLat: jxutils.StandardCoordinate2Int(latFloat),
|
||||
GoodsValue: jxutils.IntPrice2Standard(order.ActualPayPrice), // todo 超价处理
|
||||
GoodsWeight: float64(jxutils.IntWeight2Float(limitOrderWeight(order.Weight))),
|
||||
// ExpectedDeliveryTime: order.ExpectedDeliveredTime.Unix(),
|
||||
OrderType: mtpsapi.OrderTypeASAP,
|
||||
}
|
||||
if billParams.DeliveryID, err = c.getDeliveryID(order, db); err == nil {
|
||||
if billParams.ShopID, err = c.getMTPSShopID(order, db); err == nil {
|
||||
globals.SugarLogger.Debug(billParams.ShopID)
|
||||
goods := &mtpsapi.GoodsDetail{
|
||||
Goods: []*mtpsapi.GoodsItem{},
|
||||
}
|
||||
goodItemMap := map[string]*mtpsapi.GoodsItem{}
|
||||
for _, sku := range order.Skus {
|
||||
goodItem := &mtpsapi.GoodsItem{
|
||||
GoodCount: sku.Count,
|
||||
GoodPrice: jxutils.IntPrice2Standard(sku.SalePrice),
|
||||
}
|
||||
goodItem.GoodName, goodItem.GoodUnit = jxutils.GetNameAndUnitFromSkuName(sku.SkuName)
|
||||
// 好像SKU名不能重复,否则会报错,尝试处理一下
|
||||
if item, ok := goodItemMap[goodItem.GoodName]; !ok {
|
||||
goods.Goods = append(goods.Goods, goodItem)
|
||||
goodItemMap[goodItem.GoodName] = goodItem
|
||||
} else {
|
||||
item.GoodCount += goodItem.GoodCount
|
||||
}
|
||||
}
|
||||
// addParams := map[string]interface{}{
|
||||
// "note": utils.FilterMb4(order.BuyerComment),
|
||||
// "goods_detail": string(utils.MustMarshal(goods)),
|
||||
// "goods_pickup_info": fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq),
|
||||
// "poi_seq": fmt.Sprintf("#%d", order.OrderSeq),
|
||||
// }
|
||||
// storeTel := ""
|
||||
// storeID := jxutils.GetSaleStoreIDFromOrder(order)
|
||||
// storeDeatail, _ := dao.GetStoreDetail(db, storeID, order.VendorID)
|
||||
// if storeDeatail.Tel2 != "" {
|
||||
// storeTel = ",门店电话:" + storeDeatail.Tel2
|
||||
// }
|
||||
billParams.Note = utils.FilterMb4("客户电话:" + order.ConsigneeMobile + "," + order.BuyerComment + ",取货失败或配送遇到问题请联系18048531223,禁止未配送直接完成定单!")
|
||||
billParams.GoodsDetail = string(utils.MustMarshal(goods))
|
||||
billParams.GoodsPickupInfo = fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq)
|
||||
billParams.PoiSeq = fmt.Sprintf("#%d", order.OrderSeq)
|
||||
if globals.EnableStoreWrite {
|
||||
result, err2 := api.MtpsAPI.CreateOrderByShop2(billParams)
|
||||
if err = err2; err == nil {
|
||||
bill = &model.Waybill{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
OrderVendorID: order.VendorID,
|
||||
VendorWaybillID: result.MtPeisongID,
|
||||
VendorWaybillID2: utils.Int64ToStr(result.DeliveryID),
|
||||
WaybillVendorID: model.VendorIDMTPS,
|
||||
DesiredFee: deliveryFee,
|
||||
}
|
||||
delivery.OnWaybillCreated(bill)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, error:%v", order.VendorOrderID, billParams, err)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("测试环境不能真正创建运单")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
// switch cancelReasonID {
|
||||
// case partner.CancelWaybillReasonNotAcceptIntime:
|
||||
// cancelReasonID = mtpsapi.CancelReasonRideerMtpsOther
|
||||
// case partner.CancelWaybillReasonSwitch2SelfFailed:
|
||||
// cancelReasonID = mtpsapi.CancelReasonMerchantOther
|
||||
// default:
|
||||
// cancelReasonID = mtpsapi.CancelReasonRideerOther
|
||||
// }
|
||||
cancelReasonID = mtpsapi.CancelReasonMerchantOther
|
||||
cancelReason = ""
|
||||
_, err = api.MtpsAPI.CancelOrder(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, cancelReasonID, cancelReason)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) getDeliveryID(order *model.GoodsOrder, db *dao.DaoDB) (retVal int64, err error) {
|
||||
// jxorder表当前已经有50多万条记录了,加100万避免冲突
|
||||
// 508505
|
||||
return order.ID + 1000000, nil
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) getMTPSShopID(order *model.GoodsOrder, db *dao.DaoDB) (retVal string, err error) {
|
||||
saleStoreID := jxutils.GetSaleStoreIDFromOrder(order)
|
||||
storeCourierList, err2 := dao.GetOpenedStoreCouriersByStoreID(db, saleStoreID, model.VendorIDMTPS)
|
||||
if err = err2; err != nil && err != orm.ErrNoRows {
|
||||
return "", err
|
||||
}
|
||||
if len(storeCourierList) == 0 {
|
||||
return "", partner.ErrStoreHaveNoCourier
|
||||
}
|
||||
retVal = storeCourierList[0].VendorStoreID
|
||||
if beego.BConfig.RunMode == "dev" {
|
||||
retVal = "test_0001"
|
||||
}
|
||||
return retVal, nil
|
||||
}
|
||||
|
||||
func limitOrderWeight(weight int) int {
|
||||
if weight > maxOrderWeight {
|
||||
return maxOrderWeight
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.MtpsAPI.EvaluateRider(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, 1, resonContent)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *DeliveryHandler) GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) {
|
||||
intLng, intLat, err := api.MtpsAPI.RiderLocation(utils.Str2Int64(vendorWaybillID2), vendorWaybillID)
|
||||
if err == nil {
|
||||
lng = jxutils.IntCoordinate2Standard(intLng)
|
||||
lat = jxutils.IntCoordinate2Standard(intLat)
|
||||
}
|
||||
return lng, lat, err
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package mtps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestCreateWaybill(t *testing.T) {
|
||||
orerID := "817109342000022"
|
||||
order, _ := partner.CurOrderManager.LoadOrder(orerID, model.VendorIDJD)
|
||||
// globals.SugarLogger.Debug(order)
|
||||
c := new(DeliveryHandler)
|
||||
_, err := c.CreateWaybill(order, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelWaybill(t *testing.T) {
|
||||
bill := &model.Waybill{
|
||||
VendorWaybillID: "1532332342088966",
|
||||
VendorWaybillID2: "55",
|
||||
}
|
||||
c := new(DeliveryHandler)
|
||||
if err := c.CancelWaybill(bill, partner.CancelWaybillReasonOther, ""); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"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 (
|
||||
StoreNameSeparator = "-"
|
||||
)
|
||||
|
||||
const (
|
||||
CreatedPeration = "create"
|
||||
UpdatedPeration = "update"
|
||||
)
|
||||
|
||||
const (
|
||||
CancelWaybillReasonNotAcceptIntime = 1
|
||||
CancelWaybillReasonSwitch2SelfFailed = 2
|
||||
CancelWaybillReasonOther = 10
|
||||
)
|
||||
|
||||
const (
|
||||
AfsApproveTypeRefund = 1 // 退款
|
||||
AfsApproveTypeReturnGoods = 2 // 退货
|
||||
AfsApproveTypeRefused = 3 // 驳回
|
||||
)
|
||||
|
||||
const (
|
||||
TimerTypeNoOverride = 0 // GetStatusActionConfig 返回表示不修改缺省配置
|
||||
TimerTypeByPass = 1
|
||||
TimerTypeBaseNow = 2
|
||||
TimerTypeBaseStatusTime = 3
|
||||
TimerTypeBaseOrderCreatedAt = 4
|
||||
)
|
||||
|
||||
type StatusActionParams struct {
|
||||
TimerType int // 参见上面的相关常量定义
|
||||
Timeout time.Duration // 超时时间,0在GetStatusActionConfig返回时表示不修改缺省
|
||||
TimeoutGap int // 以秒为单位的随机时间,0在GetStatusActionConfig返回时表示不修改缺省
|
||||
}
|
||||
|
||||
type OrderInFoChange struct {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
var (
|
||||
CancelWaybillReasonStrNotAcceptIntime = "没有及时抢单"
|
||||
CancelWaybillReasonStrSwitch2SelfFailed = "转自送失败"
|
||||
CancelWaybillReasonStrOrderAlreadyFinished = "订单已经结束"
|
||||
CancelWaybillReasonStrActive = "操作由人员主动发起"
|
||||
CancelWaybillReasonNotInStoreOpenTime = "不在门店的营业时间范围内"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindItem = errors.New("没有找到指定的东西")
|
||||
ErrStoreHaveNoCourier = errors.New("门店没有绑定相应的配送信息")
|
||||
)
|
||||
|
||||
var (
|
||||
CurOrderManager IOrderManager
|
||||
CurStoreManager IStoreManager
|
||||
|
||||
PurchasePlatformHandlers map[int]IPurchasePlatformHandler
|
||||
PurchaseOrderHandlers map[int]IPurchasePlatformOrderHandler
|
||||
)
|
||||
|
||||
type IOrderManager interface {
|
||||
SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error)
|
||||
|
||||
OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error)
|
||||
OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error)
|
||||
OnOrderStatusChanged(vendorOrgCode string, orderStatus *model.OrderStatus) (err error)
|
||||
OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark string) (err error)
|
||||
|
||||
OnWaybillStatusChanged(bill *model.Waybill) (err error)
|
||||
|
||||
CreateAfsOrderFromOrder(vendorOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error)
|
||||
LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error)
|
||||
LoadOrder2(vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error)
|
||||
|
||||
LoadOrderFinancial(vendorOrderID string, vendorID int) (order *model.OrderFinancial, err error)
|
||||
LoadOrderFinancial2(vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error)
|
||||
|
||||
UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error)
|
||||
UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error)
|
||||
LoadStoreDetail(storeID, vendorID int) (storeDetail *dao.StoreDetail, 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, isGetPos bool) (bills []*model.WaybillExt, err error)
|
||||
|
||||
ChangeOrderInfo(order *model.GoodsOrder) (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 {
|
||||
OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error)
|
||||
OnCourierStoreStatusChanged(ctx *jxcontext.Context, vendorStoreID string, vendorID int, auditStatus int) (err error)
|
||||
}
|
||||
|
||||
// purchase handler中
|
||||
// 所有Sync,Refresh开头的函数都必须自己清理sync_status标记
|
||||
// 所有非以Sync,Refresh开头的函数不用自己清理sync_status标记(VendorSync统一处理)
|
||||
|
||||
type IPurchasePlatformHandler interface {
|
||||
IPurchasePlatformActHandler
|
||||
IPurchasePlatformOrderHandler
|
||||
|
||||
GetVendorID() int
|
||||
|
||||
// 只与平台相关
|
||||
GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error)
|
||||
|
||||
////////
|
||||
// Store
|
||||
ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (store *dao.StoreDetail, err error)
|
||||
UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error)
|
||||
CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error)
|
||||
DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error)
|
||||
GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error)
|
||||
UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error)
|
||||
|
||||
RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error)
|
||||
|
||||
UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error)
|
||||
}
|
||||
|
||||
// db *dao.DaoDB,
|
||||
type IMultipleStoresHandler interface {
|
||||
IPurchasePlatformHandler
|
||||
GetAllCategories(ctx *jxcontext.Context, vendorOrgCode string) (cats []*BareCategoryInfo, err error)
|
||||
|
||||
// CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error)
|
||||
// UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error
|
||||
// DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error
|
||||
// ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error)
|
||||
|
||||
CreateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error)
|
||||
UpdateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error)
|
||||
DeleteCategory2(ctx *jxcontext.Context, vendorOrgCode, vendorCatID string) (err error)
|
||||
ReorderCategories2(ctx *jxcontext.Context, vendorOrgCode, vendorParentCatID string, vendorCatIDList []string) (err error)
|
||||
|
||||
// sku
|
||||
// CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error)
|
||||
// UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error)
|
||||
// DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error)
|
||||
|
||||
// ReadSku(ctx *jxcontext.Context, vendorOrgCode, vendorSkuID string) (skuNameExt *model.SkuNameExt, err error)
|
||||
CreateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error)
|
||||
UpdateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error)
|
||||
DeleteSku2(ctx *jxcontext.Context, vendorOrgCode string, sku *StoreSkuInfo) (err error)
|
||||
|
||||
// RefreshAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error)
|
||||
|
||||
GetSkus(ctx *jxcontext.Context, vendorOrgCode string, skuID int, vendorSkuID string) (skuNameList []*SkuNameInfo, err error)
|
||||
}
|
||||
|
||||
type ISingleStoreHandler interface {
|
||||
IPurchasePlatformHandler
|
||||
ISingleStoreStoreSkuHandler
|
||||
// SyncStoreCategory(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, isAsync bool) (hint string, err error)
|
||||
|
||||
// RefreshStoresAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool, storeIDs []int) (hint string, err error)
|
||||
}
|
||||
|
||||
type BasePurchasePlatform struct {
|
||||
}
|
||||
|
||||
func (p *BasePurchasePlatform) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *StatusActionParams) {
|
||||
return params
|
||||
}
|
||||
|
||||
func (c *BasePurchasePlatform) CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
PurchasePlatformHandlers = make(map[int]IPurchasePlatformHandler)
|
||||
PurchaseOrderHandlers = make(map[int]IPurchasePlatformOrderHandler)
|
||||
DeliveryPlatformHandlers = make(map[int]*DeliveryPlatformHandlerInfo)
|
||||
}
|
||||
|
||||
func InitOrderManager(curOrderManager IOrderManager) {
|
||||
CurOrderManager = curOrderManager
|
||||
}
|
||||
|
||||
func InitStoreManager(curStoreManager IStoreManager) {
|
||||
CurStoreManager = curStoreManager
|
||||
}
|
||||
|
||||
func RegisterPurchasePlatform(handler IPurchasePlatformHandler) {
|
||||
vendorID := handler.GetVendorID()
|
||||
if !(model.IsPurchaseVendorExist(vendorID)) {
|
||||
panic(fmt.Sprintf("purchase vendor:%d is illegal", vendorID))
|
||||
}
|
||||
if _, ok := PurchasePlatformHandlers[vendorID]; ok {
|
||||
panic(fmt.Sprintf("purchase vendor:%d, already exists", vendorID))
|
||||
}
|
||||
_, isSingleStore := handler.(ISingleStoreHandler)
|
||||
_, isMultiStore := handler.(IMultipleStoresHandler)
|
||||
if !isSingleStore && !isMultiStore {
|
||||
panic(fmt.Sprintf("platform:%d type is wrong!", vendorID))
|
||||
}
|
||||
PurchasePlatformHandlers[vendorID] = handler
|
||||
}
|
||||
|
||||
func RegisterPurchaseOrderHandler(vendorID int, handler IPurchasePlatformOrderHandler) {
|
||||
PurchaseOrderHandlers[vendorID] = handler
|
||||
}
|
||||
|
||||
func GetPurchasePlatformFromVendorID(vendorID int) IPurchasePlatformHandler {
|
||||
return PurchasePlatformHandlers[vendorID]
|
||||
}
|
||||
|
||||
func GetPurchaseOrderHandlerFromVendorID(vendorID int) (handler IPurchasePlatformOrderHandler) {
|
||||
handler = PurchasePlatformHandlers[vendorID]
|
||||
if handler == nil {
|
||||
handler = PurchaseOrderHandlers[vendorID]
|
||||
}
|
||||
return handler
|
||||
}
|
||||
|
||||
func GetPurchasePlatformVendorIDs() (vendorIDs []int) {
|
||||
for k := range PurchasePlatformHandlers {
|
||||
vendorIDs = append(vendorIDs, k)
|
||||
}
|
||||
return vendorIDs
|
||||
}
|
||||
|
||||
func GetMultiStoreVendorIDs() (vendorIDs []int) {
|
||||
for k, v := range PurchasePlatformHandlers {
|
||||
if _, ok := v.(IMultipleStoresHandler); ok {
|
||||
vendorIDs = append(vendorIDs, k)
|
||||
}
|
||||
}
|
||||
return vendorIDs
|
||||
}
|
||||
|
||||
func GetSingleStoreVendorIDs() (vendorIDs []int) {
|
||||
for k, v := range PurchasePlatformHandlers {
|
||||
if _, ok := v.(ISingleStoreHandler); ok {
|
||||
vendorIDs = append(vendorIDs, k)
|
||||
}
|
||||
}
|
||||
return vendorIDs
|
||||
}
|
||||
|
||||
func IsMultiStore(vendorID int) bool {
|
||||
if _, ok := GetPurchasePlatformFromVendorID(vendorID).(IMultipleStoresHandler); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GetRidderPositionGetter(vendorID int) (handler IRidderPositionGetter) {
|
||||
if handlerInfo := GetDeliveryPlatformFromVendorID(vendorID); handlerInfo != nil {
|
||||
if handler, _ = handlerInfo.Handler.(IRidderPositionGetter); handler != nil {
|
||||
return handler
|
||||
}
|
||||
}
|
||||
handler, _ = GetPurchasePlatformFromVendorID(vendorID).(IRidderPositionGetter)
|
||||
return handler
|
||||
}
|
||||
|
||||
func GetWaybillTipUpdater(vendorID int) (handler IAddWaybillTip) {
|
||||
if handlerInfo := GetDeliveryPlatformFromVendorID(vendorID); handlerInfo != nil {
|
||||
if handler, _ = handlerInfo.Handler.(IAddWaybillTip); handler != nil {
|
||||
return handler
|
||||
}
|
||||
}
|
||||
handler, _ = GetPurchasePlatformFromVendorID(vendorID).(IAddWaybillTip)
|
||||
return handler
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type IActManager interface {
|
||||
IsVendorActExist(ctx *jxcontext.Context, vendorActID string, vendorID int) (isExist bool)
|
||||
CreateActFromVendor(ctx *jxcontext.Context, act2 *model.Act2, actStoreSku []*model.ActStoreSku2) (actID int, err error)
|
||||
}
|
||||
|
||||
type IPurchasePlatformActHandler interface {
|
||||
// // 如果是单品级活动,actOrderRules为空
|
||||
// // 如果是订单级活动,actStoreSku可以为空(表示不限制SKU)
|
||||
// CreateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSku []*model.ActStoreSku2) (err error)
|
||||
// UpdateAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSku []*model.ActStoreSku2) (err error)
|
||||
// // 取消整个京西活动
|
||||
// CancelAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (err error)
|
||||
|
||||
SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error)
|
||||
}
|
||||
|
||||
type IPurchasePlatformPageActHandler interface {
|
||||
GetPageActList(ctx *jxcontext.Context, createdFrom time.Time) (actList []*model.Act2, err error)
|
||||
GetPageActSkuList(ctx *jxcontext.Context, vendorPageActID string) (actStoreSkuList []*model.ActStoreSku2, err error)
|
||||
}
|
||||
|
||||
var (
|
||||
CurActManager IActManager
|
||||
)
|
||||
|
||||
func InitActManager(p IActManager) {
|
||||
CurActManager = p
|
||||
}
|
||||
|
||||
func SplitActStoreSku(actStoreSkuList []*model.ActStoreSku2) (actStoreSkuMap map[int][]*model.ActStoreSku2) {
|
||||
actStoreSkuMap = make(map[int][]*model.ActStoreSku2)
|
||||
for _, v := range actStoreSkuList {
|
||||
actStoreSkuMap[v.StoreID] = append(actStoreSkuMap[v.StoreID], v)
|
||||
}
|
||||
return actStoreSkuMap
|
||||
}
|
||||
|
||||
func SplitActStoreSku2List(actStoreSkuList []*model.ActStoreSku2) (actStoreSkuListList [][]*model.ActStoreSku2) {
|
||||
actStoreSkuMap := SplitActStoreSku(actStoreSkuList)
|
||||
for _, v := range actStoreSkuMap {
|
||||
actStoreSkuListList = append(actStoreSkuListList, v)
|
||||
}
|
||||
return actStoreSkuListList
|
||||
}
|
||||
|
||||
func Act2ActMap(act *model.Act2) (actMap *model.ActMap) {
|
||||
actMap = &model.ActMap{}
|
||||
actMap.ID = act.MapID
|
||||
return actMap
|
||||
}
|
||||
|
||||
func ActStoreSku2ActStoreSkuMap(actStoreSku *model.ActStoreSku2) (actStoreSkuMap *model.ActStoreSkuMap) {
|
||||
actStoreSkuMap = &model.ActStoreSkuMap{
|
||||
ModelIDCULD: actStoreSku.ModelIDCULD,
|
||||
BindID: actStoreSku.MapID,
|
||||
|
||||
ActID: actStoreSku.ActID,
|
||||
StoreID: actStoreSku.StoreID,
|
||||
SkuID: actStoreSku.SkuID,
|
||||
VendorID: actStoreSku.VendorID,
|
||||
VendorActID: actStoreSku.VendorActID,
|
||||
SyncStatus: actStoreSku.SyncStatus,
|
||||
VendorPrice: actStoreSku.VendorPrice,
|
||||
ActualActPrice: actStoreSku.ActualActPrice,
|
||||
|
||||
EarningPrice: actStoreSku.EarningPrice,
|
||||
}
|
||||
actStoreSkuMap.ID = actStoreSku.MapID
|
||||
return actStoreSkuMap
|
||||
}
|
||||
|
||||
func Act2Update(ctx *jxcontext.Context, act *model.Act2, syncStatus int) (item *dao.KVUpdateItem) {
|
||||
kvs := map[string]interface{}{
|
||||
model.FieldSyncStatus: 0,
|
||||
model.FieldUpdatedAt: time.Now(),
|
||||
model.FieldLastOperator: ctx.GetUserName(),
|
||||
}
|
||||
if syncStatus == model.SyncFlagDeletedMask {
|
||||
kvs[model.FieldDeletedAt] = time.Now()
|
||||
} else if syncStatus == model.SyncFlagNewMask {
|
||||
kvs[model.FieldVendorActID] = act.VendorActID
|
||||
}
|
||||
item = &dao.KVUpdateItem{
|
||||
Item: Act2ActMap(act),
|
||||
KVs: kvs,
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func ActStoreSku2Update(ctx *jxcontext.Context, actStoreSkuList []*model.ActStoreSku2, syncStatus int) (items []*dao.KVUpdateItem) {
|
||||
for _, v := range actStoreSkuList {
|
||||
v.SyncStatus = 0
|
||||
v.UpdatedAt = time.Now()
|
||||
v.LastOperator = ctx.GetUserName()
|
||||
kvs := map[string]interface{}{
|
||||
model.FieldSyncStatus: v.SyncStatus,
|
||||
model.FieldUpdatedAt: v.UpdatedAt,
|
||||
model.FieldLastOperator: v.LastOperator,
|
||||
}
|
||||
if syncStatus == model.SyncFlagDeletedMask {
|
||||
v.DeletedAt = time.Now()
|
||||
kvs[model.FieldDeletedAt] = v.DeletedAt
|
||||
} else if syncStatus == model.SyncFlagNewMask {
|
||||
kvs[model.FieldVendorActID] = v.VendorActID
|
||||
}
|
||||
items = append(items, &dao.KVUpdateItem{
|
||||
Item: ActStoreSku2ActStoreSkuMap(v),
|
||||
KVs: kvs,
|
||||
})
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
func GetVendorIDsFromActMap(actMap map[int]*model.Act2) (vendorIDs []int) {
|
||||
for vendorID := range actMap {
|
||||
vendorIDs = append(vendorIDs, vendorID)
|
||||
}
|
||||
return vendorIDs
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package partner
|
||||
|
||||
type IAPIManager interface {
|
||||
GetAPI(vendorID int, appOrgCode string) interface{}
|
||||
GetAppOrgCodeList(vendorID int) (appOrgCodeList []string)
|
||||
}
|
||||
|
||||
var (
|
||||
CurAPIManager IAPIManager
|
||||
)
|
||||
|
||||
func InitAPIManager(curAPIManager IAPIManager) {
|
||||
CurAPIManager = curAPIManager
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
type CreateWaybillPolicyFunc func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string)
|
||||
|
||||
type IDeliveryPlatformHandler interface {
|
||||
GetVendorID() int
|
||||
|
||||
CreateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (vendorStoreID string, status int, err error)
|
||||
GetStore(ctx *jxcontext.Context, storeID int, vendorStoreID string) (storeDetail *dao.StoreDetail2, err error)
|
||||
IsErrStoreNotExist(err error) bool
|
||||
IsErrStoreExist(err error) bool
|
||||
|
||||
CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error)
|
||||
CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error)
|
||||
GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *WaybillFeeInfo, err error)
|
||||
//投诉骑手
|
||||
ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error)
|
||||
}
|
||||
|
||||
type IDeliveryUpdateStoreHandler interface {
|
||||
UpdateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (err error)
|
||||
}
|
||||
|
||||
type DeliveryPlatformHandlerInfo struct {
|
||||
Handler IDeliveryPlatformHandler
|
||||
Use4CreateWaybill bool
|
||||
}
|
||||
|
||||
var (
|
||||
DeliveryPlatformHandlers map[int]*DeliveryPlatformHandlerInfo
|
||||
UseableDeliveryVendorIDs []int
|
||||
)
|
||||
|
||||
func init() {
|
||||
DeliveryPlatformHandlers = make(map[int]*DeliveryPlatformHandlerInfo)
|
||||
}
|
||||
|
||||
func RegisterDeliveryPlatform(handler IDeliveryPlatformHandler, isUse4CreateWaybill bool) {
|
||||
vendorID := handler.GetVendorID()
|
||||
if !(model.IsDeliveryVendorExist(vendorID)) {
|
||||
panic(fmt.Sprintf("delivery vendor:%d is illegal", vendorID))
|
||||
}
|
||||
if _, ok := DeliveryPlatformHandlers[vendorID]; ok {
|
||||
panic(fmt.Sprintf("delivery vendor:%d, already exists", vendorID))
|
||||
}
|
||||
DeliveryPlatformHandlers[vendorID] = &DeliveryPlatformHandlerInfo{
|
||||
Handler: handler,
|
||||
Use4CreateWaybill: isUse4CreateWaybill,
|
||||
}
|
||||
UseableDeliveryVendorIDs = append(UseableDeliveryVendorIDs, vendorID)
|
||||
}
|
||||
|
||||
func GetDeliveryPlatformFromVendorID(vendorID int) *DeliveryPlatformHandlerInfo {
|
||||
return DeliveryPlatformHandlers[vendorID]
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
type OrderPhoneNumberInfo struct {
|
||||
VendorOrderID string
|
||||
PhoneNumber string
|
||||
}
|
||||
|
||||
type IPurchasePlatformOrderHandler interface {
|
||||
Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder)
|
||||
GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error)
|
||||
GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error)
|
||||
GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *StatusActionParams)
|
||||
|
||||
AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error)
|
||||
PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error)
|
||||
|
||||
AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error)
|
||||
CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) // 取货失败后再次招唤平台配送
|
||||
ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) // 投递失败后确认收到退货
|
||||
|
||||
// 是否可能转商家自送
|
||||
CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error)
|
||||
// 将订单从购物平台配送转为自送
|
||||
Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error)
|
||||
|
||||
// 将订单从购物平台配送转为自送后又送达
|
||||
Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error)
|
||||
|
||||
// 完全自送的门店表示开始配送
|
||||
SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error)
|
||||
|
||||
// 完全自送的门店表示配送完成
|
||||
SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error)
|
||||
|
||||
GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error)
|
||||
|
||||
ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error)
|
||||
|
||||
AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error)
|
||||
CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error)
|
||||
// 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)
|
||||
}
|
||||
|
||||
type IAddWaybillTip interface {
|
||||
GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error)
|
||||
UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error)
|
||||
}
|
||||
|
||||
type IRidderPositionGetter interface {
|
||||
GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error)
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
PrinterStatusUnknown = 0
|
||||
PrinterStatusOffline = 1
|
||||
PrinterStatusOnlineOK = 2
|
||||
PrinterStatusOnlineAbnormal = 3
|
||||
)
|
||||
|
||||
const (
|
||||
PrintResultSuccess = 0 // 成功
|
||||
PrintResultNoPrinter = 1 // 没有配置网络打印机
|
||||
)
|
||||
|
||||
const (
|
||||
PrinterFontSizeNormal = int8(0) //正常大小
|
||||
PrinterFontSizeBig = int8(1) //两倍大小
|
||||
)
|
||||
|
||||
var (
|
||||
PrinterStatusName = map[int]string{
|
||||
PrinterStatusUnknown: "未知",
|
||||
PrinterStatusOffline: "离线",
|
||||
PrinterStatusOnlineOK: "正常",
|
||||
PrinterStatusOnlineAbnormal: "异常",
|
||||
}
|
||||
)
|
||||
|
||||
type PrinterStatus struct {
|
||||
PrintResult int `json:"printResult"`
|
||||
PrinterStatus int `json:"printerStatus"`
|
||||
Printed int `json:"printed"` // 已经打印的单数
|
||||
Waiting int `json:"waiting"` // 等待打印的单数,超过1一般不太正常
|
||||
}
|
||||
|
||||
type BindPrinterResult struct {
|
||||
PrinterSN string `json:"printerSN"`
|
||||
PrinterKey string `json:"printerKey"`
|
||||
PrinterKey2 string `json:"printerKey2"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
}
|
||||
|
||||
type IPrinterHandler interface {
|
||||
GetVendorID() int
|
||||
PrintMsg(ctx *jxcontext.Context, id1, id2, msgTitle, msgContent string) (printerStatus *PrinterStatus, err error)
|
||||
GetPrinterStatus(ctx *jxcontext.Context, id1, id2 string) (printerStatus *PrinterStatus, err error)
|
||||
|
||||
RegisterPrinter(ctx *jxcontext.Context, id1, id2, printerName string) (newID1, newID2 string, err error)
|
||||
UnregisterPrinter(ctx *jxcontext.Context, id1, id2 string) (err error)
|
||||
|
||||
BindPrinter(ctx *jxcontext.Context, mapData map[string]interface{}) (bindResult *BindPrinterResult, err error)
|
||||
RebindPrinter(ctx *jxcontext.Context, lastBindResult *BindPrinterResult) (bindResult *BindPrinterResult, err error)
|
||||
|
||||
PrintOrder(ctx *jxcontext.Context, store *model.Store, order *model.GoodsOrder) (printerStatus *PrinterStatus, err error)
|
||||
|
||||
EmptyPrintList(ctx *jxcontext.Context, id1, id2 string) (err error)
|
||||
PlayText(ctx *jxcontext.Context, id1, id2, orderID, text string) (printerStatus *PrinterStatus, err error)
|
||||
SetSound(ctx *jxcontext.Context, id1, id2, sound string) (err error)
|
||||
}
|
||||
|
||||
var (
|
||||
PrinterPlatformHandlers map[int]IPrinterHandler
|
||||
)
|
||||
|
||||
func init() {
|
||||
PrinterPlatformHandlers = make(map[int]IPrinterHandler)
|
||||
}
|
||||
|
||||
func RegisterPrinterPlatform(handler IPrinterHandler) {
|
||||
vendorID := handler.GetVendorID()
|
||||
if !(model.IsPrinterVendorExist(vendorID)) {
|
||||
panic(fmt.Sprintf("printer vendor:%d is illegal", vendorID))
|
||||
}
|
||||
if _, ok := PrinterPlatformHandlers[vendorID]; ok {
|
||||
panic(fmt.Sprintf("printer vendor:%d, already exists", vendorID))
|
||||
}
|
||||
PrinterPlatformHandlers[vendorID] = handler
|
||||
}
|
||||
|
||||
func GetPrinterPlatformFromVendorID(vendorID int) IPrinterHandler {
|
||||
return PrinterPlatformHandlers[vendorID]
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
type IStoreHandler interface {
|
||||
GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error)
|
||||
|
||||
EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error)
|
||||
UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error)
|
||||
// opTime格式为整数1130代表11:30
|
||||
UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error)
|
||||
}
|
||||
|
||||
// 同步资质信息至平台
|
||||
type IStoreSyncQualifyHandler interface {
|
||||
SyncQualify(ctx *jxcontext.Context, storeDetail *dao.StoreDetail) (err error)
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
const (
|
||||
// FuncGetStoreSkusBareInfo = 1 // 此接口要求实现为不限制批处理大小的
|
||||
FuncUpdateStoreSkusStock = 2
|
||||
FuncUpdateStoreSkusStatus = 3
|
||||
FuncUpdateStoreSkusPrice = 4
|
||||
|
||||
FuncGetStoreSkusFullInfo = 6
|
||||
FuncCreateStoreSkus = 7
|
||||
FuncUpdateStoreSkus = 8
|
||||
FuncDeleteStoreSkus = 9
|
||||
|
||||
FuncCreateActs = 10
|
||||
FuncCancelActs = 11
|
||||
)
|
||||
|
||||
const (
|
||||
UnlimitedBatchSize = math.MaxInt32
|
||||
|
||||
MaxStoreSkuStock = model.MaxStoreSkuStockQty
|
||||
UnlimitedStoreSkuStock = -1
|
||||
)
|
||||
|
||||
type StoreSkuInfo struct {
|
||||
SkuID int `json:"skuID,omitempty"`
|
||||
VendorSkuID string `json:"vendorSkuID,omitempty"`
|
||||
NameID int `json:"nameID,omitempty"`
|
||||
VendorNameID string `json:"vendorNameID,omitempty"`
|
||||
|
||||
Stock int `json:"stock,omitempty"`
|
||||
VendorPrice int64 `json:"price,omitempty"`
|
||||
Status int `json:"status,omitempty"`
|
||||
|
||||
Seq int `json:"seq,omitempty"`
|
||||
|
||||
ActPrice int64 `json:"actPrice,omitempty"`
|
||||
VendorActID string `json:"vendorActID,omitempty"`
|
||||
IsSpecialty int `json:"isSpecialty,omitempty"`
|
||||
JxPrice int64 `json:"jxPrice,omitempty"`
|
||||
JxUnitPrice int64 `json:"jxUnitPrice,omitempty"`
|
||||
VendorSkuID2 string `json:"vendorSkuID2,omitempty"`
|
||||
JdsStockSwitch int `json:"jdsStockSwitch"`
|
||||
IsDeletedBySku bool `json:"isDeletedBySku"`
|
||||
}
|
||||
|
||||
type StoreSkuInfoWithErr struct {
|
||||
StoreSkuInfo *StoreSkuInfo
|
||||
CategoryName string
|
||||
VendoreID int
|
||||
VendoreName string
|
||||
StoreID int
|
||||
SyncType string
|
||||
ErrMsg string
|
||||
}
|
||||
|
||||
type SkuInfo struct {
|
||||
StoreSkuInfo
|
||||
SkuName string
|
||||
Comment string
|
||||
SpecQuality float64
|
||||
SpecUnit string
|
||||
Weight int
|
||||
ActPrice int64
|
||||
}
|
||||
|
||||
type SkuNameInfo struct {
|
||||
NameID int `json:"nameID,omitempty"`
|
||||
VendorNameID string `json:"vendorNameID,omitempty"`
|
||||
|
||||
Prefix string
|
||||
Name string
|
||||
Description string
|
||||
Unit string
|
||||
VendorCatIDList []string
|
||||
PictureList []string
|
||||
Status int `json:"status,omitempty"`
|
||||
YbBarCode string
|
||||
SkuList []*SkuInfo
|
||||
}
|
||||
|
||||
type BareStoreSkuInfoList []*StoreSkuInfo
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (l BareStoreSkuInfoList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l BareStoreSkuInfoList) Less(i, j int) bool {
|
||||
if l[i].Seq != l[j].Seq {
|
||||
return l[i].Seq < l[j].Seq
|
||||
}
|
||||
return l[i].VendorPrice < l[j].VendorPrice
|
||||
}
|
||||
|
||||
func (l BareStoreSkuInfoList) Swap(i, j int) {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
// 批处理函数,如果是部分失败的情况会返回失败,successedList中会返回成功的列表
|
||||
|
||||
type IPurchasePlatformStoreSkuHandler interface {
|
||||
GetStoreSkusBatchSize(funcID int) int
|
||||
|
||||
ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error)
|
||||
|
||||
// 此接口要求实现为不限制批处理大小的
|
||||
GetStoreSkusBareInfo(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*StoreSkuInfo) (outStoreSkuList []*StoreSkuInfo, err error)
|
||||
UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo, status int) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
|
||||
CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (err error)
|
||||
}
|
||||
|
||||
type ISingleStoreStoreSkuHandler interface {
|
||||
IPurchasePlatformStoreSkuHandler
|
||||
|
||||
GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (outSkuNameList []*SkuNameInfo, err error)
|
||||
CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*StoreSkuInfo) (failedList []*StoreSkuInfoWithErr, err error)
|
||||
DeleteStoreAllSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, isContinueWhenError bool) (err error)
|
||||
IsErrSkuExist(err error) (isExist bool)
|
||||
IsErrSkuNotExist(err error) (isNotExist bool)
|
||||
|
||||
GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*BareCategoryInfo, err error)
|
||||
GetStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, catName string) (cat *BareCategoryInfo, err error)
|
||||
CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error)
|
||||
UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error)
|
||||
DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error)
|
||||
DeleteStoreAllCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, isContinueWhenError bool) (err error)
|
||||
|
||||
IsErrCategoryExist(err error) (isExist bool)
|
||||
IsErrCategoryNotExist(err error) (isNotExist bool)
|
||||
|
||||
GetSensitiveWordRegexp() *regexp.Regexp
|
||||
}
|
||||
|
||||
type IStoreSkuSorter interface {
|
||||
ReorderStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, vendorCatID string, storeSkuList []*StoreSkuInfo) (err error)
|
||||
}
|
||||
|
||||
func BuildSkuName(skuID int, vendorSkuID string) (skuName *SkuNameInfo) {
|
||||
return &SkuNameInfo{
|
||||
SkuList: []*SkuInfo{
|
||||
&SkuInfo{
|
||||
StoreSkuInfo: StoreSkuInfo{
|
||||
SkuID: skuID,
|
||||
VendorSkuID: vendorSkuID,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package pay
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
type PayOpStatus int
|
||||
|
||||
const (
|
||||
OpStatusFailed PayOpStatus = 0
|
||||
OpStatusSuccessed PayOpStatus = 1
|
||||
)
|
||||
|
||||
type CreatePayParam struct {
|
||||
PayOrderID string
|
||||
VendorPayType string
|
||||
|
||||
VendorOrderID string
|
||||
ProductDesc string
|
||||
ProductDetail string
|
||||
FeeType string
|
||||
TotalFee int
|
||||
TimeStart time.Time
|
||||
TimeExpire time.Time
|
||||
|
||||
UserData string
|
||||
}
|
||||
|
||||
type PayOpResult struct {
|
||||
Status PayOpStatus
|
||||
VendorStatus string
|
||||
ErrMsg string
|
||||
|
||||
ID string
|
||||
VendorID string
|
||||
|
||||
OriginalData string
|
||||
}
|
||||
|
||||
type ResponseHandler interface {
|
||||
OnCreatePay(vendorID int, result *PayOpResult) (err error)
|
||||
OnRefundPay(vendorID int, result *PayOpResult) (err error)
|
||||
}
|
||||
|
||||
type IPayPlatformHandler interface {
|
||||
CreatePay(ctx *jxcontext.Context, param *CreatePayParam, isOffline bool) (prepayID, qrCodeURL string, err error)
|
||||
ClosePay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID string) (err error)
|
||||
RefundPay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID, refundID, reason string, totalFee, refundFee int) (vendorRefundID string, err error)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package wxpay
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/pay"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func OnCallback(msg *wxpayapi.CallbackMsg) (err error) {
|
||||
globals.SugarLogger.Debugf("wxpay OnCallback msg:%s", utils.Format4Output(msg, true))
|
||||
switch msg.MsgType {
|
||||
case wxpayapi.MsgTypePay:
|
||||
err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg))
|
||||
case wxpayapi.MsgTypeRefund:
|
||||
err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) {
|
||||
opResult := &pay.PayOpResult{
|
||||
OriginalData: string(utils.MustMarshal(msg)),
|
||||
}
|
||||
if msg.ReturnCode == wxpayapi.ResponseCodeSuccess {
|
||||
opResult.Status = pay.OpStatusSuccessed
|
||||
opResult.ID = msg.OutTradeNo
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
opResult.VendorID = msg.TransactionID
|
||||
} else {
|
||||
opResult.VendorStatus = msg.ErrCode
|
||||
opResult.ErrMsg = msg.ErrCodeDes
|
||||
}
|
||||
} else {
|
||||
opResult.Status = pay.OpStatusFailed
|
||||
}
|
||||
err = payHandler.responseHandler.OnCreatePay(model.VendorIDWXPay, opResult)
|
||||
return err
|
||||
}
|
||||
|
||||
func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) {
|
||||
opResult := &pay.PayOpResult{
|
||||
OriginalData: string(utils.MustMarshal(msg)),
|
||||
}
|
||||
if msg.ReturnCode == wxpayapi.ResponseCodeSuccess {
|
||||
opResult.Status = pay.OpStatusSuccessed
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
opResult.ID = msg.ReqInfoObj.OutRefundNo
|
||||
opResult.VendorID = msg.ReqInfoObj.RefundID
|
||||
} else {
|
||||
opResult.VendorStatus = msg.ErrCode
|
||||
opResult.ErrMsg = msg.ErrCodeDes
|
||||
}
|
||||
} else {
|
||||
opResult.Status = pay.OpStatusFailed
|
||||
}
|
||||
err = payHandler.responseHandler.OnRefundPay(model.VendorIDWXPay, opResult)
|
||||
return err
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package wxpay
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/pay"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type PayHandler struct {
|
||||
responseHandler pay.ResponseHandler
|
||||
}
|
||||
|
||||
var (
|
||||
payHandler *PayHandler
|
||||
)
|
||||
|
||||
func New(responseHandler pay.ResponseHandler) (handler *PayHandler) {
|
||||
return &PayHandler{
|
||||
responseHandler: responseHandler,
|
||||
}
|
||||
}
|
||||
|
||||
func vendorPayType2WxpayType(vendorPayType string) string {
|
||||
return vendorPayType
|
||||
}
|
||||
|
||||
func (p *PayHandler) CreatePay(ctx *jxcontext.Context, createParam *pay.CreatePayParam, isOffline bool) (prepayID, qrCodeURL string, err error) {
|
||||
param := &wxpayapi.CreateOrderParam{
|
||||
OutTradeNo: createParam.PayOrderID,
|
||||
Body: createParam.ProductDesc,
|
||||
NotifyURL: globals.WxpayNotifyURL,
|
||||
SpbillCreateIP: ctx.GetRealRemoteIP(),
|
||||
TradeType: vendorPayType2WxpayType(createParam.VendorPayType),
|
||||
TotalFee: createParam.TotalFee,
|
||||
|
||||
TimeStart: wxpayapi.Time2PayTime(createParam.TimeStart),
|
||||
TimeExpire: wxpayapi.Time2PayTime(createParam.TimeExpire),
|
||||
ProfitSharing: wxpayapi.OptYes,
|
||||
}
|
||||
if isOffline {
|
||||
param.TradeType = wxpayapi.TradeTypeNative
|
||||
}
|
||||
if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini {
|
||||
param.OpenID = authInfo.GetAuthID()
|
||||
}
|
||||
if result, err := api.WxpayAPI.CreateUnifiedOrder(param); err == nil {
|
||||
prepayID = result.PrepayID
|
||||
qrCodeURL = result.CodeURL
|
||||
}
|
||||
return prepayID, qrCodeURL, err
|
||||
}
|
||||
|
||||
func (p *PayHandler) ClosePay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID string) (err error) {
|
||||
return api.WxpayAPI.CloseOrder(payOrderID)
|
||||
}
|
||||
|
||||
func (p *PayHandler) RefundPay(ctx *jxcontext.Context, payOrderID, vendorPayOrderID, refundID, reason string, totalFee, refundFee int) (vendorRefundID string, err error) {
|
||||
param := &wxpayapi.PayRefundParam{
|
||||
OutTradeNo: payOrderID,
|
||||
NotifyURL: globals.WxpayNotifyURL,
|
||||
OutRefundNo: refundID,
|
||||
TotalFee: totalFee,
|
||||
RefundFee: refundFee,
|
||||
RefundDesc: wxpayapi.CData(reason),
|
||||
}
|
||||
retVal, err := api.WxpayAPI.PayRefund(param)
|
||||
if err == nil {
|
||||
vendorRefundID = retVal.RefundID
|
||||
}
|
||||
return vendorRefundID, err
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
package feie
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/feieapi"
|
||||
"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 (
|
||||
CurPrinterHandler *PrinterHandler
|
||||
)
|
||||
|
||||
type PrinterHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
CurPrinterHandler = new(PrinterHandler)
|
||||
partner.RegisterPrinterPlatform(CurPrinterHandler)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<B>饿百取货码:%s</B><BR><BR>\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
orderFmt := `
|
||||
<CB>%s</CB><BR><BR>
|
||||
<C>手机买菜上京西</C><BR>
|
||||
<C>极速到家送惊喜</C><BR>
|
||||
--------------------------------<BR>
|
||||
下单时间: %s<BR>
|
||||
预计送达: %s<BR>
|
||||
订单编号: %s<BR>
|
||||
<BR>
|
||||
|
||||
<B>%s#%d</B><BR><BR>
|
||||
<QR>%s</QR><BR>
|
||||
` + getCode +
|
||||
`客户: %s<BR>
|
||||
电话: %s<BR>
|
||||
地址: %s<BR>
|
||||
<BR>
|
||||
客户备注: <BR>
|
||||
<B>%s</B><BR>
|
||||
<BR>
|
||||
|
||||
<BR>
|
||||
商品明细: <BR>
|
||||
品名 数量 单价 小计<BR>
|
||||
--------------------------------<BR>`
|
||||
// <BOLD>实际支付:</BOLD>%s<BR>
|
||||
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 += `%s<BR>`
|
||||
orderFmt += `%8s%10s%10s<BR>`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count)))
|
||||
}
|
||||
orderFmt += `<BR>
|
||||
<BOLD>共%d种%d件商品</BOLD>
|
||||
<BR>
|
||||
--------------------------------<BR>
|
||||
<C><L><BOLD>商品质量问题请联系:</BOLD></L><BR></C>
|
||||
<C><L><BOLD>%s:%s</BOLD></L><BR></C><BR>
|
||||
<BR>
|
||||
更多信息请关注官方微信: %s<BR>
|
||||
<BR>
|
||||
<BR><BR>
|
||||
--------------------------------<BR>
|
||||
--------------------------------<BR>
|
||||
<BR><BR>
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<B>饿百取货码:%s</B><BR><BR>\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
orderFmt := `
|
||||
<CB>%s</CB><BR><BR>
|
||||
<C>手机买菜上京西</C><BR>
|
||||
<C>极速到家送惊喜</C><BR>
|
||||
--------------------------------<BR>
|
||||
<B>下单时间: %s<BR><BR><BR></B>
|
||||
<B>预计送达: %s<BR><BR><BR></B>
|
||||
<B>订单编号: %s<BR></B>
|
||||
<BR>
|
||||
|
||||
<B>%s#%d</B><BR><BR>
|
||||
<QR>%s</QR><BR>
|
||||
` + getCode +
|
||||
`<B>客户: %s<BR></B>
|
||||
<B>电话: %s<BR></B>
|
||||
<B>地址: %s<BR></B>
|
||||
<BR>
|
||||
<B>客户备注: <BR></B>
|
||||
<B>%s</B><BR>
|
||||
<BR>
|
||||
|
||||
<BR>
|
||||
<B>商品明细: <BR></B>
|
||||
<B>品名数量单价小计<BR></B>
|
||||
--------------------------------<BR>`
|
||||
// <B><BOLD>实际支付:</BOLD></B><B>%s<BR></B>
|
||||
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 += `<B>%s<BR></B>`
|
||||
orderFmt += `<B>%s %s %s<BR><BR></B>`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count)))
|
||||
}
|
||||
orderFmt += `<BR>
|
||||
<B><BOLD>共%d种%d件商品</BOLD></B>
|
||||
<BR>
|
||||
--------------------------------<BR>
|
||||
<C><L><BOLD>商品质量问题请联系:</BOLD></L><BR></C>
|
||||
<C><L><BOLD>%s:%s</BOLD></L><BR></C><BR>
|
||||
<BR>
|
||||
<B>更多信息请关注官方微信: %s<BR></B>
|
||||
<BR>
|
||||
<BR><BR>
|
||||
--------------------------------<BR>
|
||||
--------------------------------<BR>
|
||||
<BR><BR>
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetVendorID() int {
|
||||
return model.VendorIDFeiE
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintMsg(ctx *jxcontext.Context, id1, id2, msgTitle, msgContent string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("PrintMsg id1:%s", id1)
|
||||
if id1 != "" {
|
||||
if globals.EnableStoreWrite {
|
||||
_, err = api.FeieAPI.PrintMsg(id1, msgContent, 1)
|
||||
}
|
||||
if err == nil {
|
||||
printerStatus, err = c.GetPrinterStatus(ctx, id1, id2)
|
||||
}
|
||||
} else {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultNoPrinter,
|
||||
}
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetPrinterStatus(ctx *jxcontext.Context, printerSN, printerKey string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
tmpStatus, err := api.FeieAPI.QueryPrinterStatus(printerSN)
|
||||
if err == nil {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrinterStatus: tmpStatus,
|
||||
PrintResult: partner.PrintResultSuccess,
|
||||
}
|
||||
printerStatus.Printed, printerStatus.Waiting, err = api.FeieAPI.QueryOrderInfoByDate(printerSN, time.Now())
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintOrder(ctx *jxcontext.Context, store *model.Store, order *model.GoodsOrder) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("feie PrintOrderByOrder orderID:%s, storeID:%d", order.VendorOrderID, store.ID)
|
||||
content := ""
|
||||
if store.PrinterFontSize == partner.PrinterFontSizeBig {
|
||||
content = c.getOrderContentBig(order, store.Tel1)
|
||||
} else {
|
||||
content = c.getOrderContent(order, store.Tel1)
|
||||
}
|
||||
return c.PrintMsg(ctx, store.PrinterSN, store.PrinterKey, order.VendorOrderID, content)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RegisterPrinter(ctx *jxcontext.Context, printerSN, printerKey, printerName string) (notUsed1, notUsed2 string, err error) {
|
||||
var no map[string]string
|
||||
if globals.EnableStoreWrite {
|
||||
_, no, err = api.FeieAPI.PrinterAddList([]*feieapi.PrinterInfo{
|
||||
&feieapi.PrinterInfo{
|
||||
SN: printerSN,
|
||||
Key: printerKey,
|
||||
Name: printerName,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
no = make(map[string]string)
|
||||
}
|
||||
if err == nil {
|
||||
if no[printerSN] != "" {
|
||||
if no[printerSN] == feieapi.ErrMsgAlredyAdded {
|
||||
api.FeieAPI.PrinterEdit(printerSN, printerName, "")
|
||||
} else {
|
||||
err = fmt.Errorf("添加打印机出错:%s", no[printerSN])
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) UnregisterPrinter(ctx *jxcontext.Context, printerSN, notUsed string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
_, _, err = api.FeieAPI.PrinterDelList([]string{printerSN})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) BindPrinter(ctx *jxcontext.Context, mapData map[string]interface{}) (bindResult *partner.BindPrinterResult, err error) {
|
||||
return nil, fmt.Errorf("%s打印机当前不支持扫码绑定", model.VendorChineseNames[model.VendorIDFeiE])
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RebindPrinter(ctx *jxcontext.Context, lastBindResult *partner.BindPrinterResult) (bindResult *partner.BindPrinterResult, err error) {
|
||||
return nil, fmt.Errorf("%s打印机当前不支持扫码绑定", model.VendorChineseNames[model.VendorIDFeiE])
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) EmptyPrintList(ctx *jxcontext.Context, id1, id2 string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.FeieAPI.DelPrinterSqs(id1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PlayText(ctx *jxcontext.Context, id1, id2, orderID, text string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
return c.GetPrinterStatus(ctx, id1, id2)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) SetSound(ctx *jxcontext.Context, id1, id2, sound string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.FeieAPI.SetSound(id1, sound)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package feie
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestPrintMsg(t *testing.T) {
|
||||
orderID := "910838879000442"
|
||||
vendorID := 0
|
||||
order, err := partner.CurOrderManager.LoadOrder(orderID, vendorID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
context := CurPrinterHandler.getOrderContent(order, "13412345678")
|
||||
//context := CurPrinterHandler.getOrderContentBig(order, "13412345678")
|
||||
status, err := CurPrinterHandler.PrintMsg(jxcontext.AdminCtx, "218510310", "ztdpveyg", "test", context)
|
||||
t.Log(utils.Format4Output(status, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterPrinter(t *testing.T) {
|
||||
newID1, newID2, err := CurPrinterHandler.RegisterPrinter(jxcontext.AdminCtx, "218510310", "ztdpveyg", "title")
|
||||
t.Log(newID1 + "," + newID2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
package xiaowm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/xiaowmapi"
|
||||
|
||||
"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 (
|
||||
CurPrinterHandler *PrinterHandler
|
||||
)
|
||||
|
||||
type PrinterHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
CurPrinterHandler = new(PrinterHandler)
|
||||
partner.RegisterPrinterPlatform(CurPrinterHandler)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<big>饿百取货码:%s**\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
buyerComment := order.BuyerComment
|
||||
if buyerComment == "" {
|
||||
buyerComment = " "
|
||||
}
|
||||
orderFmt := `
|
||||
<big> %s**
|
||||
手机买菜上京西*
|
||||
极速到家送惊喜*
|
||||
------------------------------*
|
||||
下单时间: %s*
|
||||
预计送达: %s*
|
||||
订单编号: %s*
|
||||
*
|
||||
<big>%s\#%d**
|
||||
<qrcA4>%s*
|
||||
` + getCode +
|
||||
`客户: %s*
|
||||
电话: %s*
|
||||
地址: %s*
|
||||
*
|
||||
客户备注: *
|
||||
<big>%s*
|
||||
商品明细: *
|
||||
品名 数量 单价 小计
|
||||
--------------------------------*
|
||||
`
|
||||
// <S011>实际支付: %s*
|
||||
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,
|
||||
buyerComment,
|
||||
// jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice),
|
||||
}
|
||||
for _, sku := range order.Skus {
|
||||
orderFmt += `%s*`
|
||||
orderFmt += `%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 += `
|
||||
*
|
||||
<S011>共%d种%d件商品*
|
||||
--------------------------------*
|
||||
<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, globals.StoreName)
|
||||
content = fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), escapeString4Printer(orderParams)...)
|
||||
// globals.SugarLogger.Debugf("xiaowm orderParams:%s\n", utils.Format4Output(orderParams, false))
|
||||
// globals.SugarLogger.Debugf("xiaowm getOrderContent:%s\n", content)
|
||||
return content
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<big>饿百取货码:%s**\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
buyerComment := order.BuyerComment
|
||||
if buyerComment == "" {
|
||||
buyerComment = " "
|
||||
}
|
||||
orderFmt := `
|
||||
<big> %s**
|
||||
手机买菜上京西*
|
||||
极速到家送惊喜*
|
||||
------------------------------*
|
||||
<big>下单时间: %s**
|
||||
<big>预计送达: %s**
|
||||
<big>订单编号: %s*
|
||||
*
|
||||
<big>%s\#%d*
|
||||
<qrcA4>%s*
|
||||
` + getCode +
|
||||
`<big>客户: %s*
|
||||
<big>电话: %s*
|
||||
<big>地址: %s*
|
||||
*
|
||||
<big>客户备注: *
|
||||
<big>%s*
|
||||
<big>商品明细: *
|
||||
<big>品名数量单价小计*
|
||||
--------------------------------*
|
||||
`
|
||||
// <big>实际支付: %s*
|
||||
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,
|
||||
buyerComment,
|
||||
// jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice),
|
||||
}
|
||||
for _, sku := range order.Skus {
|
||||
orderFmt += `<big>%s*`
|
||||
orderFmt += `<big>%s %s %s*`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count)))
|
||||
}
|
||||
orderFmt += `
|
||||
<big>共%d种%d件商品*
|
||||
--------------------------------*
|
||||
<S020>商品质量问题请联系:*
|
||||
<S020>%s:%s*
|
||||
*
|
||||
<big>更多信息请关注官方微信: %s*
|
||||
--------------------------------
|
||||
--------------------------------
|
||||
*<BEEP13500,3,2,1>*
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
content = fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), escapeString4Printer(orderParams)...)
|
||||
// globals.SugarLogger.Debugf("xiaowm orderParams:%s\n", utils.Format4Output(orderParams, false))
|
||||
// globals.SugarLogger.Debugf("xiaowm getOrderContent:%s\n", content)
|
||||
return content
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("|7饿百取货码:%s\n\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
buyerComment := order.BuyerComment
|
||||
if buyerComment == "" {
|
||||
buyerComment = " "
|
||||
}
|
||||
orderFmt := `
|
||||
|7 %s
|
||||
|5 手机买菜上京西
|
||||
|5 极速到家送惊喜
|
||||
|5--------------------------------
|
||||
|5下单时间: %s
|
||||
|5预计送达: %s
|
||||
|5订单编号: %s
|
||||
|5
|
||||
|7%s\#%d
|
||||
` + getCode + `|5
|
||||
|2%s
|
||||
|5客户: %s
|
||||
|5电话: %s
|
||||
|5地址: %s
|
||||
|5
|
||||
|5客户备注:
|
||||
|7%s
|
||||
|5
|
||||
|5
|
||||
|5商品明细:
|
||||
|5品名 数量
|
||||
|5--------------------------------
|
||||
`
|
||||
// |6实际支付: %s
|
||||
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,
|
||||
buyerComment,
|
||||
// jxutils.IntPrice2StandardCurrencyString(order.ActualPayPrice),
|
||||
}
|
||||
for _, sku := range order.Skus {
|
||||
orderFmt += `|5%s`
|
||||
orderFmt += `|5%8s`
|
||||
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
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintMsg(ctx *jxcontext.Context, printerNumber, printerToken, msgTitle, msgContent string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("PrintMsg printerNumber:%s", printerNumber)
|
||||
if printerNumber != "" {
|
||||
if globals.EnableStoreWrite {
|
||||
_, err = api.XiaoWMAPI.SendMsg(printerNumber, printerToken, msgContent)
|
||||
}
|
||||
if err == nil {
|
||||
printerStatus, err = c.GetPrinterStatus(ctx, printerNumber, printerToken)
|
||||
}
|
||||
} else {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultNoPrinter,
|
||||
}
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetPrinterStatus(ctx *jxcontext.Context, printerNumber, printerToken string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
runningState, paperState, err := api.XiaoWMAPI.GetPrinterStatus(printerNumber, printerToken)
|
||||
if err == nil {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultSuccess,
|
||||
}
|
||||
if runningState == xiaowmapi.RunningStateOffline {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOffline
|
||||
} else {
|
||||
if paperState == xiaowmapi.PaperStateLackPaper {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOnlineAbnormal
|
||||
} else {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOnlineOK
|
||||
}
|
||||
}
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
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, storeID:%d", order.VendorOrderID, store.ID)
|
||||
var content string
|
||||
if isV500(store.PrinterSN) {
|
||||
content = c.getOrderContent2(order, store.Tel1)
|
||||
} else {
|
||||
if store.PrinterFontSize == partner.PrinterFontSizeBig {
|
||||
content = c.getOrderContentBig(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") {
|
||||
err = fmt.Errorf("外卖管家打印机设备编号:%s长度不合法", printerNumber)
|
||||
} else {
|
||||
if globals.EnableStoreWrite {
|
||||
printerToken, err = api.XiaoWMAPI.AuthPrinter(printerNumber, "", "")
|
||||
}
|
||||
if err == nil {
|
||||
if _, err = c.GetPrinterStatus(ctx, printerNumber, printerToken); err != nil {
|
||||
if globals.EnableStoreWrite {
|
||||
c.UnregisterPrinter(ctx, printerNumber, printerToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Debugf("xiaowm RegisterPrinter printerNumber:%s, error:%v", printerNumber, err)
|
||||
return "", printerToken, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) UnregisterPrinter(ctx *jxcontext.Context, printerNumber, printerToken string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.XiaoWMAPI.DelPrinter(printerNumber, printerToken)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func escapeString4Printer(params []interface{}) []interface{} {
|
||||
for k, v := range params {
|
||||
if vStr, ok := v.(string); ok {
|
||||
vStr = strings.Replace(vStr, "*", "\\*", -1)
|
||||
params[k] = strings.Replace(vStr, "#", "\\#", -1)
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) BindPrinter(ctx *jxcontext.Context, mapData map[string]interface{}) (bindResult *partner.BindPrinterResult, err error) {
|
||||
return nil, fmt.Errorf("%s打印机当前不支持扫码绑定", model.VendorChineseNames[model.VendorIDXiaoWM])
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RebindPrinter(ctx *jxcontext.Context, lastBindResult *partner.BindPrinterResult) (bindResult *partner.BindPrinterResult, err error) {
|
||||
return nil, fmt.Errorf("%s打印机当前不支持扫码绑定", model.VendorChineseNames[model.VendorIDXiaoWM])
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) EmptyPrintList(ctx *jxcontext.Context, id1, id2 string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PlayText(ctx *jxcontext.Context, id1, id2, orderID, text string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
return c.GetPrinterStatus(ctx, id1, id2)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) SetSound(ctx *jxcontext.Context, id1, id2, sound string) (err error) {
|
||||
return fmt.Errorf("%s打印机当前不支持设置声音", model.VendorChineseNames[model.VendorIDXiaoWM])
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package xiaowm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestPrintMsg(t *testing.T) {
|
||||
orderID := "910838879000442"
|
||||
vendorID := 0
|
||||
order, err := partner.CurOrderManager.LoadOrder(orderID, vendorID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// context := CurPrinterHandler.getOrderContent(order, "13412345678")
|
||||
context := CurPrinterHandler.getOrderContentBig(order, "13412345678")
|
||||
status, err := CurPrinterHandler.PrintMsg(jxcontext.AdminCtx, "7JizmSyiXNzkggaqU", "177f213277dd842ba2b53f6c926a48ea", "test", context)
|
||||
t.Log(utils.Format4Output(status, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterPrinter(t *testing.T) {
|
||||
newID1, newID2, err := CurPrinterHandler.RegisterPrinter(jxcontext.AdminCtx, "7JizmSyiXNzkggaqU", "", "title")
|
||||
t.Log(newID1 + "," + newID2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
package yilianyun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/yilianyunapi"
|
||||
"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 (
|
||||
CurPrinterHandler *PrinterHandler
|
||||
)
|
||||
|
||||
type PrinterHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
CurPrinterHandler = new(PrinterHandler)
|
||||
partner.RegisterPrinterPlatform(CurPrinterHandler)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<FS2>饿百取货码:%s</FS2>\\n\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
//TODO 去掉单价和小计,2020-06-18
|
||||
orderFmt := `
|
||||
<FS2><center>%s</center></FS2>\n\n
|
||||
<center>手机买菜上京西</center>
|
||||
<center>极速到家送惊喜</center>\n
|
||||
--------------------------------
|
||||
下单时间: %s\n
|
||||
预计送达: %s\n
|
||||
订单编号: %s\n
|
||||
\n
|
||||
<FS2>%s#%d</FS2>\n\n
|
||||
<QR>%s</QR>
|
||||
` + getCode + `\n
|
||||
客户: %s\n
|
||||
电话: %s\n
|
||||
地址: %s\n
|
||||
\n
|
||||
客户备注: \n
|
||||
<FS2>%s</FS2>\n
|
||||
\n
|
||||
\n
|
||||
商品明细: \n
|
||||
品名 数量 单价 小计\n
|
||||
--------------------------------\n`
|
||||
// <FB>实际支付:</FB>%s\n
|
||||
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 += `%s\n`
|
||||
orderFmt += `%8s%10s%10s\n`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count)))
|
||||
}
|
||||
orderFmt += `\n
|
||||
<FB>共%d种%d件商品</FB>
|
||||
\n
|
||||
--------------------------------\n
|
||||
<center><FH2>商品质量问题请联系:</FH2></center>
|
||||
<center><FH2>%s:%s</FH2></center>\n
|
||||
更多信息请关注官方微信: %s\n
|
||||
--------------------------------\n
|
||||
--------------------------------\n
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
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)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<FS2>饿百取货码:%s</FS2>\\n\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
orderFmt := `
|
||||
<FS2><center>%s</center></FS2>\n\n
|
||||
<center>手机买菜上京西</center>
|
||||
<center>极速到家送惊喜</center>\n
|
||||
--------------------------------
|
||||
<FS2>下单时间: %s\n\n</FS2>
|
||||
<FS2>预计送达: %s\n\n</FS2>
|
||||
<FS2>订单编号: %s\n</FS2>
|
||||
\n
|
||||
<FS2>%s#%d</FS2>\n\n
|
||||
<QR>%s</QR>
|
||||
` + getCode + `\n
|
||||
<FS2>客户: %s\n</FS2>
|
||||
<FS2>电话: %s\n</FS2>
|
||||
<FS2>地址: %s\n</FS2>
|
||||
\n
|
||||
<FS2>客户备注: \n</FS2>
|
||||
<FS2>%s</FS2>\n
|
||||
\n
|
||||
\n
|
||||
<FS2>商品明细: \n</FS2>
|
||||
<FS2>品名数量单价小计\n</FS2>
|
||||
--------------------------------\n`
|
||||
// <FS2><FB>实际支付:</FB>%s\n</FS2>
|
||||
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 += `<FS2>%s\n</FS2>`
|
||||
orderFmt += `<FS2>%s %s %s\n\n</FS2>`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count)))
|
||||
}
|
||||
orderFmt += `\n
|
||||
<FS2><FB>共%d种%d件商品</FB></FS2>
|
||||
\n
|
||||
--------------------------------\n
|
||||
<center><FH2>商品质量问题请联系:</FH2></center>
|
||||
<center><FH2>%s:%s</FH2></center>\n
|
||||
<FS2>更多信息请关注官方微信: %s\n</FS2>
|
||||
--------------------------------\n
|
||||
--------------------------------\n
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
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)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetVendorID() int {
|
||||
return model.VendorIDYiLianYun
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintMsg(ctx *jxcontext.Context, machineCode, possibleToken, msgTitle, msgContent string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("PrintMsg machineCode:%s", machineCode)
|
||||
if machineCode != "" {
|
||||
if globals.EnableStoreWrite {
|
||||
err = getApiByToken(possibleToken).PrintMsgWithToken(machineCode, msgTitle, msgContent, possibleToken)
|
||||
}
|
||||
if err == nil {
|
||||
printerStatus, err = c.GetPrinterStatus(ctx, machineCode, possibleToken)
|
||||
}
|
||||
} else {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultNoPrinter,
|
||||
}
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetPrinterStatus(ctx *jxcontext.Context, machineCode, possibleToken string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
status, err := getApiByToken(possibleToken).GetPrintStatusWithToken(machineCode, possibleToken)
|
||||
if err == nil {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultSuccess,
|
||||
}
|
||||
if status == yilianyunapi.PrintStatusOffline {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOffline
|
||||
} else if status == yilianyunapi.PrintStatusOnline {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOnlineOK
|
||||
} else {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOnlineAbnormal
|
||||
}
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintOrder(ctx *jxcontext.Context, store *model.Store, order *model.GoodsOrder) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("yilianyun PrintOrderByOrder orderID:%s, storeID:%d", order.VendorOrderID, store.ID)
|
||||
content := ""
|
||||
if store.PrinterFontSize == partner.PrinterFontSizeBig {
|
||||
content = c.getOrderContentBig(order, store.Tel1)
|
||||
} else {
|
||||
content = c.getOrderContent(order, store.Tel1)
|
||||
}
|
||||
return c.PrintMsg(ctx, store.PrinterSN, store.PrinterKey, order.VendorOrderID, content)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RegisterPrinter(ctx *jxcontext.Context, machineCode, secret, printerName string) (notUsed1, notUsed2 string, err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.YilianyunAPI.AddPrinter(machineCode, secret, printerName)
|
||||
}
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) UnregisterPrinter(ctx *jxcontext.Context, machineCode, notUsed string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.YilianyunAPI.DeletePrinter(machineCode)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) BindPrinter(ctx *jxcontext.Context, mapData map[string]interface{}) (bindResult *partner.BindPrinterResult, err error) {
|
||||
machineCode := utils.Interface2String(mapData["machineCode"])
|
||||
qrKey := utils.Interface2String(mapData["qrKey"])
|
||||
if machineCode == "" || qrKey == "" {
|
||||
return nil, fmt.Errorf("易联云扫描数据格式不正确")
|
||||
}
|
||||
tokenInfo, err := api.YilianyunAPI2.GetPrinterToken(machineCode, qrKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return yilianyunToken2BindResult(tokenInfo), nil
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RebindPrinter(ctx *jxcontext.Context, lastBindResult *partner.BindPrinterResult) (bindResult *partner.BindPrinterResult, err error) {
|
||||
var tokenInfo *yilianyunapi.TokenInfo
|
||||
if globals.EnableStoreWrite {
|
||||
tokenInfo, err = api.YilianyunAPI2.RefreshToken(lastBindResult.PrinterKey2)
|
||||
} else {
|
||||
tokenInfo = &yilianyunapi.TokenInfo{}
|
||||
}
|
||||
if err == nil {
|
||||
bindResult = yilianyunToken2BindResult(tokenInfo)
|
||||
}
|
||||
return bindResult, err
|
||||
}
|
||||
|
||||
func yilianyunToken2BindResult(tokenInfo *yilianyunapi.TokenInfo) (bindResult *partner.BindPrinterResult) {
|
||||
return &partner.BindPrinterResult{
|
||||
PrinterSN: tokenInfo.MachineCode,
|
||||
PrinterKey: tokenInfo.AccessToken,
|
||||
PrinterKey2: tokenInfo.RefreshToken,
|
||||
ExpiresAt: time.Now().Add(time.Duration(tokenInfo.ExpiresIn) * time.Second).Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func getApiByToken(possibleToken string) *yilianyunapi.API {
|
||||
if yilianyunapi.IsStrToken(possibleToken) {
|
||||
return api.YilianyunAPI2
|
||||
}
|
||||
return api.YilianyunAPI
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) EmptyPrintList(ctx *jxcontext.Context, id1, id2 string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.YilianyunAPI.CancelAll(id1, id2)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PlayText(ctx *jxcontext.Context, id1, id2, orderID, text string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.YilianyunAPI.PlayText(id1, orderID, text, id2)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) SetSound(ctx *jxcontext.Context, id1, id2, sound string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
err = api.YilianyunAPI.SetSound(id1, sound)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package yilianyun
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api.YilianyunAPI.SetToken("8d54951744984b7a8908251c3063b445")
|
||||
}
|
||||
|
||||
func TestPrintMsg(t *testing.T) {
|
||||
orderID := "910838879000442"
|
||||
vendorID := 0
|
||||
order, err := partner.CurOrderManager.LoadOrder(orderID, vendorID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// context := CurPrinterHandler.getOrderContent(order, "13412345678")
|
||||
context := CurPrinterHandler.getOrderContentBig(order, "13412345678")
|
||||
status, err := CurPrinterHandler.PrintMsg(jxcontext.AdminCtx, "4004600675", "fem2ukwvduik", "test", context)
|
||||
t.Log(utils.Format4Output(status, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterPrinter(t *testing.T) {
|
||||
newID1, newID2, err := CurPrinterHandler.RegisterPrinter(jxcontext.AdminCtx, "4004600675", "fem2ukwvduik", "title")
|
||||
t.Log(newID1 + "," + newID2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
package zhongwu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/zhongwuapi"
|
||||
|
||||
"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 (
|
||||
CurPrinterHandler *PrinterHandler
|
||||
)
|
||||
|
||||
type PrinterHandler struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
CurPrinterHandler = new(PrinterHandler)
|
||||
partner.RegisterPrinterPlatform(CurPrinterHandler)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContent(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<S2>饿百取货码:%s</S2><RN>\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
orderFmt := `
|
||||
<S2><C>%s</C></S2><RN><RN>
|
||||
<C>手机买菜上京西</C>
|
||||
<C>极速到家送惊喜</C><RN>
|
||||
********************************
|
||||
下单时间: %s<RN>
|
||||
预计送达: %s<RN>
|
||||
订单编号: %s<RN>
|
||||
<RN>
|
||||
<S2>%s#%d</S2><RN><RN>
|
||||
<QR>%s</QR>
|
||||
` + getCode + `<RN>
|
||||
客户: %s<RN>
|
||||
电话: %s<RN>
|
||||
地址: %s<RN>
|
||||
<RN>
|
||||
客户备注: <RN>
|
||||
<S2>%s</S2><RN>
|
||||
<RN>
|
||||
<RN>
|
||||
商品明细: <RN>
|
||||
品名 数量 <RN>
|
||||
********************************<RN>`
|
||||
// <B1>实际支付:</B1>%s<RN>
|
||||
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 += `%s<RN>`
|
||||
orderFmt += `%8s<RN>`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count))
|
||||
//jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count))
|
||||
}
|
||||
orderFmt += `<RN>
|
||||
<B1>共%d种%d件商品</B1>
|
||||
<RN>
|
||||
********************************<RN>
|
||||
<C><H2>商品质量问题请联系:</H2></C>
|
||||
<C><H2>%s:%s</H2></C><RN>
|
||||
更多信息请关注官方微信: %s<RN>
|
||||
********************************<RN>
|
||||
********************************<RN>
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) getOrderContentBig(order *model.GoodsOrder, storeTel string) (content string) {
|
||||
expectedDeliveryTime := order.ExpectedDeliveredTime
|
||||
if utils.IsTimeZero(expectedDeliveryTime) {
|
||||
expectedDeliveryTime = order.OrderCreatedAt.Add(1 * time.Hour)
|
||||
}
|
||||
getCode := ""
|
||||
if order.VendorID == model.VendorIDEBAI {
|
||||
getCode = fmt.Sprintf("<S2>饿百取货码:%s</S2><RN>\n", jxutils.GetEbaiOrderGetCode(order))
|
||||
}
|
||||
orderFmt := `
|
||||
<S2><C>%s</C></S2><RN><RN>
|
||||
<C>手机买菜上京西</C>
|
||||
<C>极速到家送惊喜</C><RN>
|
||||
********************************
|
||||
<S2>下单时间: %s<RN><RN></S2>
|
||||
<S2>预计送达: %s<RN><RN></S2>
|
||||
<S2>订单编号: %s<RN></S2>
|
||||
<RN>
|
||||
<S2>%s#%d</S2><RN><RN>
|
||||
<QR>%s</QR>
|
||||
` + getCode + `<RN>
|
||||
<S2>客户: %s<RN></S2>
|
||||
<S2>电话: %s<RN></S2>
|
||||
<S2>地址: %s<RN></S2>
|
||||
<RN>
|
||||
<S2>客户备注: <RN></S2>
|
||||
<S2>%s</S2><RN>
|
||||
<RN>
|
||||
<RN>
|
||||
<S2>商品明细: <RN></S2>
|
||||
<S2>品名 数量<RN></S2>
|
||||
********************************<RN>`
|
||||
// <S2><B1>实际支付:</B1>%s<RN></S2>
|
||||
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 += `<S2>%s<RN></S2>`
|
||||
orderFmt += `<S2>%s<RN><RN></S2>`
|
||||
orderParams = append(orderParams, sku.SkuName, "x"+utils.Int2Str(sku.Count))
|
||||
//jxutils.IntPrice2StandardCurrencyString(sku.SalePrice), jxutils.IntPrice2StandardCurrencyString(sku.SalePrice*int64(sku.Count))
|
||||
}
|
||||
orderFmt += `<RN>
|
||||
<S2><B1>共%d种%d件商品</B1></S2>
|
||||
<RN>
|
||||
********************************<RN>
|
||||
<C><H2>商品质量问题请联系:</H2></C>
|
||||
<C><H2>%s:%s</H2></C><RN>
|
||||
<S2>更多信息请关注官方微信: %s<RN></S2>
|
||||
********************************<RN>
|
||||
********************************<RN>
|
||||
`
|
||||
// <QR>http://weixin.qq.com/r/tkkDGzTERmk5rXB49xyk</QR>
|
||||
orderParams = append(orderParams, order.SkuCount, order.GoodsCount, order.StoreName, storeTel, globals.StoreName)
|
||||
return fmt.Sprintf(strings.Replace(orderFmt, "\n", "", -1), orderParams...)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetVendorID() int {
|
||||
return model.VendorIDZhongWu
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintMsg(ctx *jxcontext.Context, deviceID, deviceSecret, msgTitle, msgContent string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("PrintMsg deviceID:%s", deviceID)
|
||||
if deviceID != "" {
|
||||
var status int
|
||||
if globals.EnableStoreWrite {
|
||||
_, status, err = api.ZhongwuAPI.PrintMsg(deviceID, deviceSecret, msgContent)
|
||||
}
|
||||
if err == nil {
|
||||
printerStatus = c.translateStatus(status)
|
||||
}
|
||||
} else {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultNoPrinter,
|
||||
}
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) GetPrinterStatus(ctx *jxcontext.Context, deviceID, deviceSecret string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
status, err := api.ZhongwuAPI.GetPrinterStatus(deviceID, deviceSecret)
|
||||
if err == nil {
|
||||
printerStatus = c.translateStatus(status)
|
||||
}
|
||||
return printerStatus, err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PrintOrder(ctx *jxcontext.Context, store *model.Store, order *model.GoodsOrder) (printerStatus *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("zhongwu PrintOrderByOrder orderID:%s, storeID:%d", order.VendorOrderID, store.ID)
|
||||
content := ""
|
||||
if store.PrinterFontSize == partner.PrinterFontSizeBig {
|
||||
content = c.getOrderContentBig(order, store.Tel1)
|
||||
} else {
|
||||
content = c.getOrderContent(order, store.Tel1)
|
||||
}
|
||||
return c.PrintMsg(ctx, store.PrinterSN, store.PrinterKey, order.VendorOrderID, content)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RegisterPrinter(ctx *jxcontext.Context, deviceID, deviceSecret, printerName string) (notUsed1, notUsed2 string, err error) {
|
||||
if deviceID == "" || deviceSecret == "" {
|
||||
err = fmt.Errorf("打印机ID与打印机密钥都不能为空")
|
||||
}
|
||||
_, err = c.GetPrinterStatus(ctx, deviceID, deviceSecret)
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) UnregisterPrinter(ctx *jxcontext.Context, deviceID, deviceSecret string) (err error) {
|
||||
// 中午云不需要注册
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) translateStatus(status int) (printerStatus *partner.PrinterStatus) {
|
||||
printerStatus = &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultSuccess,
|
||||
}
|
||||
if status == zhongwuapi.PrinterStatusOnline {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOnlineOK
|
||||
} else if status == zhongwuapi.PrinterStatusLackPaper {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOnlineAbnormal
|
||||
} else {
|
||||
printerStatus.PrinterStatus = partner.PrinterStatusOffline
|
||||
}
|
||||
return printerStatus
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) BindPrinter(ctx *jxcontext.Context, mapData map[string]interface{}) (bindResult *partner.BindPrinterResult, err error) {
|
||||
return nil, fmt.Errorf("%s打印机当前不支持扫码绑定", model.VendorChineseNames[model.VendorIDZhongWu])
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) RebindPrinter(ctx *jxcontext.Context, lastBindResult *partner.BindPrinterResult) (bindResult *partner.BindPrinterResult, err error) {
|
||||
return nil, fmt.Errorf("%s打印机当前不支持扫码绑定", model.VendorChineseNames[model.VendorIDZhongWu])
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) EmptyPrintList(ctx *jxcontext.Context, id1, id2 string) (err error) {
|
||||
if globals.EnableStoreWrite {
|
||||
_, err = api.ZhongwuAPI.EmptyPrintQueue(id1, id2)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) PlayText(ctx *jxcontext.Context, id1, id2, orderID, text string) (printerStatus *partner.PrinterStatus, err error) {
|
||||
return c.GetPrinterStatus(ctx, id1, id2)
|
||||
}
|
||||
|
||||
func (c *PrinterHandler) SetSound(ctx *jxcontext.Context, id1, id2, sound string) (err error) {
|
||||
return fmt.Errorf("%s打印机当前不支持设置声音", model.VendorChineseNames[model.VendorIDZhongWu])
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package zhongwu
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestPrintMsg(t *testing.T) {
|
||||
orderID := "910838879000442"
|
||||
vendorID := 0
|
||||
order, err := partner.CurOrderManager.LoadOrder(orderID, vendorID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// context := CurPrinterHandler.getOrderContent(order, "13412345678")
|
||||
context := CurPrinterHandler.getOrderContentBig(order, "13412345678")
|
||||
status, err := CurPrinterHandler.PrintMsg(jxcontext.AdminCtx, "12364142", "v7rvjv9b", "test", context)
|
||||
t.Log(utils.Format4Output(status, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterPrinter(t *testing.T) {
|
||||
newID1, newID2, err := CurPrinterHandler.RegisterPrinter(jxcontext.AdminCtx, "12364142", "v7rvjv9b", "title")
|
||||
t.Log(newID1 + "," + newID2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
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/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 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 v.VendorSkuID != "" {
|
||||
if model.IsSyncStatusNeedCreate(v.SyncStatus) {
|
||||
skus = append(skus, &ebaiapi.ActivitySkuInfo4Add{
|
||||
SkuID: v.VendorSkuID,
|
||||
SpecialPrice: v.ActualActPrice,
|
||||
Stock: v.Stock,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return skus
|
||||
}
|
||||
|
||||
func actStoreSu2Ebai4Update(oneStoreActSku []*model.ActStoreSku2) (skus []*ebaiapi.ActivitySkuInfo4Update) {
|
||||
for _, v := range oneStoreActSku {
|
||||
if v.VendorSkuID != "" {
|
||||
if model.IsSyncStatusNeedUpdate(v.SyncStatus) {
|
||||
skus = append(skus, &ebaiapi.ActivitySkuInfo4Update{
|
||||
ShopID: utils.Int2Str(v.StoreID),
|
||||
SkuID: v.VendorSkuID,
|
||||
SpecialPrice: v.ActPrice,
|
||||
Stock: v.Stock,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return skus
|
||||
}
|
||||
|
||||
func actStoreSu2Ebai4Delete(oneStoreActSku []*model.ActStoreSku2) (skus []string) {
|
||||
for _, v := range oneStoreActSku {
|
||||
if v.VendorSkuID != "" {
|
||||
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: utils.LimitMixedStringLen(act.GetRealActName(), ebaiapi.MaxActivityNameLength),
|
||||
ActivityType: actType2Ebai(act.Type),
|
||||
StartTime: act.BeginAt.Unix(),
|
||||
EndTime: act.EndAt.Unix(),
|
||||
OpenTime: "00:00",
|
||||
CloseTime: "23:59",
|
||||
WeekDay: "0,1,2,3,4,5,6",
|
||||
ActivityDesc: act.Advertising,
|
||||
ShowCategory: model.ActTypeName[act.Type],
|
||||
PromotionSkuDesc: utils.LimitMixedStringLen(act.Advertising, ebaiapi.MaxActivityDescLength),
|
||||
DayLimit: act.LimitDaily,
|
||||
ActivityPlatform: ebaiapi.ActivityPFAll,
|
||||
}
|
||||
if act.LimitCount > 0 {
|
||||
activity.OrderLimit = act.LimitCount
|
||||
}
|
||||
if activity.DayLimit == 0 {
|
||||
activity.DayLimit = 999
|
||||
}
|
||||
if actOrderRules != nil {
|
||||
activity.Rule = actOrderRules2Ebai(actOrderRules)
|
||||
}
|
||||
return activity
|
||||
}
|
||||
|
||||
func createOneShopAct(act *model.Act2, shopID string, oneStoreActSku []*model.ActStoreSku2) (ebaiActIDStr string, err error) {
|
||||
globals.SugarLogger.Debugf("ebai createOneShopAct")
|
||||
activity := act2EbaiActivity(act, nil)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
ebaiActID, err2 := api.EbaiAPI.ActivityCreate(shopID, 0, 0, activity)
|
||||
if err = err2; err == nil {
|
||||
ebaiActIDStr = utils.Int64ToStr(ebaiActID)
|
||||
if _, err = ActivitySkuAddBatch(ebaiActID, shopID, 0, activity.ActivityType, actStoreSu2Ebai4Add(oneStoreActSku), false); err != nil {
|
||||
ActivityDisable(ebaiActID, shopID, 0, 0)
|
||||
}
|
||||
}
|
||||
} 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) {
|
||||
globals.SugarLogger.Debugf("ebai ActivitySkuAddBatch")
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
successIDs, err = api.EbaiAPI.ActivitySkuAddBatch(activityID, shopID, baiduShopID, activityType, skuList, isSkuIDCustom)
|
||||
} else {
|
||||
for _, v := range skuList {
|
||||
successIDs = append(successIDs, v.SkuID)
|
||||
}
|
||||
}
|
||||
return successIDs, err
|
||||
}
|
||||
|
||||
func ActivitySkuDeleteBatch(activityID int64, shopID string, baiduShopID int64, skuIDs []string, isSkuIDCustom bool) (successIDs []string, err error) {
|
||||
globals.SugarLogger.Debugf("ebai ActivitySkuDeleteBatch")
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
successIDs, err = api.EbaiAPI.ActivitySkuDeleteBatch(activityID, shopID, baiduShopID, skuIDs, isSkuIDCustom)
|
||||
} else {
|
||||
successIDs = append([]string{}, skuIDs...)
|
||||
}
|
||||
return successIDs, err
|
||||
}
|
||||
|
||||
func ActivitySkuUpdateBatch(activityID int64, actSkuInfoList []*ebaiapi.ActivitySkuInfo4Update) (faildInfoList []string, err error) {
|
||||
globals.SugarLogger.Debugf("ebai ActivitySkuUpdateBatch")
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
faildInfoList, err = api.EbaiAPI.ActivitySkuUpdateBatch(activityID, actSkuInfoList)
|
||||
}
|
||||
return faildInfoList, err
|
||||
}
|
||||
|
||||
func ActivityDisable(activityID int64, shopID string, baiduShopID, supplierID int64) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai ActivityDisable")
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ActivityDisable(activityID, shopID, baiduShopID, supplierID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getActStoreSkuFromTaskResult(taskReslt []interface{}) (list []*model.ActStoreSku2) {
|
||||
for _, v := range taskReslt {
|
||||
actStoreSkuList := v.([]*model.ActStoreSku2)
|
||||
list = append(list, actStoreSkuList...)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func createSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2) (createdList []*model.ActStoreSku2, err error) {
|
||||
globals.SugarLogger.Debugf("ebai createSkuAct")
|
||||
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
|
||||
task := tasksch.NewParallelTask("ebai createSkuAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
list := batchItemList[0].([]*model.ActStoreSku2)
|
||||
var vendorActID string
|
||||
if vendorActID, err = createOneShopAct(act, utils.Int2Str(list[0].StoreID), list); err == nil {
|
||||
for _, v := range list {
|
||||
v.VendorActID = vendorActID
|
||||
}
|
||||
retVal = []interface{}{list}
|
||||
}
|
||||
return retVal, err
|
||||
}, actStoreSkuListList)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
result, err := task.GetResult(0)
|
||||
return getActStoreSkuFromTaskResult(result), err
|
||||
}
|
||||
|
||||
func cancelSkuAct(ctx *jxcontext.Context, parentTask tasksch.ITask, actStoreSkuMap map[string][]*model.ActStoreSku2) (canceledList []*model.ActStoreSku2, err error) {
|
||||
globals.SugarLogger.Debugf("ebai cancelSkuAct")
|
||||
var vendorActIDs []string
|
||||
for k := range actStoreSkuMap {
|
||||
vendorActIDs = append(vendorActIDs, k)
|
||||
}
|
||||
task := tasksch.NewParallelTask("ebai cancelSkuAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorActID := batchItemList[0].(string)
|
||||
actStoreSkuList := actStoreSkuMap[vendorActID]
|
||||
if vendorActID != "" {
|
||||
err = ActivityDisable(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, 0)
|
||||
}
|
||||
if err == nil {
|
||||
retVal = []interface{}{actStoreSkuList}
|
||||
}
|
||||
return retVal, err
|
||||
}, vendorActIDs)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
result, err := task.GetResult(0)
|
||||
return getActStoreSkuFromTaskResult(result), err
|
||||
}
|
||||
|
||||
func deleteSkuActSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, actStoreSkuMap, vendorActInfoMap map[string][]*model.ActStoreSku2) (deletedList []*model.ActStoreSku2, err error) {
|
||||
globals.SugarLogger.Debugf("ebai deleteSkuActSkus")
|
||||
var vendorActIDs []string
|
||||
for k := range actStoreSkuMap {
|
||||
if k != "" {
|
||||
vendorActIDs = append(vendorActIDs, k)
|
||||
}
|
||||
}
|
||||
if len(vendorActIDs) > 0 {
|
||||
task := tasksch.NewParallelTask("ebai deleteSkuAct", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorActID := batchItemList[0].(string)
|
||||
actStoreSkuList := actStoreSkuMap[vendorActID]
|
||||
vendorActStoreSkuList := vendorActInfoMap[vendorActID]
|
||||
if len(actStoreSkuList) < len(vendorActStoreSkuList) {
|
||||
if list := actStoreSu2Ebai4Delete(actStoreSkuList); len(list) > 0 {
|
||||
_, err = ActivitySkuDeleteBatch(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, list, false)
|
||||
}
|
||||
} else {
|
||||
err = ActivityDisable(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, 0)
|
||||
}
|
||||
if err == nil {
|
||||
retVal = []interface{}{actStoreSkuList}
|
||||
}
|
||||
return retVal, err
|
||||
}, vendorActIDs)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
result, err2 := task.GetResult(0)
|
||||
err = err2
|
||||
deletedList = getActStoreSkuFromTaskResult(result)
|
||||
}
|
||||
return deletedList, err
|
||||
}
|
||||
|
||||
func addSkuActSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actStoreSku []*model.ActStoreSku2, vendorActIDMap map[int]string) (addedList []*model.ActStoreSku2, err error) {
|
||||
globals.SugarLogger.Debugf("ebai addSkuActSkus, actID:%d", act.ID)
|
||||
actStoreSkuListList := partner.SplitActStoreSku2List(actStoreSku)
|
||||
if len(actStoreSkuListList) > 0 {
|
||||
task := tasksch.NewParallelTask("ebai addSkuActSkus", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
actStoreSkuList := batchItemList[0].([]*model.ActStoreSku2)
|
||||
vendorActID := vendorActIDMap[actStoreSkuList[0].StoreID]
|
||||
if vendorActID != "" {
|
||||
if list := actStoreSu2Ebai4Add(actStoreSkuList); len(list) > 0 {
|
||||
_, err = ActivitySkuAddBatch(utils.Str2Int64(vendorActID), utils.Int2Str(actStoreSkuList[0].StoreID), 0, actType2Ebai(act.Type), list, false)
|
||||
}
|
||||
} else {
|
||||
vendorActID, err = createOneShopAct(act, utils.Int2Str(actStoreSkuList[0].StoreID), actStoreSkuList)
|
||||
}
|
||||
if err == nil {
|
||||
for _, v := range actStoreSkuList {
|
||||
v.VendorActID = vendorActID
|
||||
}
|
||||
retVal = []interface{}{actStoreSkuList}
|
||||
}
|
||||
return retVal, err
|
||||
}, actStoreSkuListList)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
result, err2 := task.GetResult(0)
|
||||
err = err2
|
||||
addedList = getActStoreSkuFromTaskResult(result)
|
||||
}
|
||||
return addedList, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai SyncAct, actID:%d", act.ID)
|
||||
vendorActInfoMap := make(map[string][]*model.ActStoreSku2)
|
||||
deleteActInfoMap := make(map[string][]*model.ActStoreSku2)
|
||||
vendorActIDMap := make(map[int]string)
|
||||
var actStoreSkuList4Create []*model.ActStoreSku2
|
||||
var updateItems []*dao.KVUpdateItem
|
||||
|
||||
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
|
||||
for storeID := range actStoreSkuMap {
|
||||
for _, actStoreSku := range actStoreSkuMap[storeID] {
|
||||
vendorActInfoMap[actStoreSku.VendorActID] = append(vendorActInfoMap[actStoreSku.VendorActID], actStoreSku)
|
||||
if vendorActIDMap[storeID] == "" && actStoreSku.VendorActID != "" {
|
||||
vendorActIDMap[storeID] = actStoreSku.VendorActID
|
||||
}
|
||||
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
|
||||
vendorActID := actStoreSku.VendorActID
|
||||
if vendorActID == "" {
|
||||
vendorActID = act.VendorActID
|
||||
}
|
||||
deleteActInfoMap[vendorActID] = append(deleteActInfoMap[vendorActID], actStoreSku)
|
||||
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
|
||||
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = func() (err error) {
|
||||
if model.IsSyncStatusDelete(act.SyncStatus) {
|
||||
canceledList, err2 := cancelSkuAct(ctx, nil, vendorActInfoMap)
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, canceledList, model.SyncFlagModifiedMask)...)
|
||||
if err = err2; err == nil {
|
||||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
|
||||
}
|
||||
} else if model.IsSyncStatusNew(act.SyncStatus) {
|
||||
createdList, err2 := createSkuAct(ctx, nil, act, actStoreSkuList4Create)
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, createdList, model.SyncFlagNewMask)...)
|
||||
if err = err2; err == nil {
|
||||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask))
|
||||
}
|
||||
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
|
||||
if len(actStoreSkuList4Create) > 0 {
|
||||
addedList, err2 := addSkuActSkus(ctx, nil, act, actStoreSkuList4Create, vendorActIDMap)
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, addedList, model.SyncFlagNewMask)...)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(deleteActInfoMap) > 0 {
|
||||
deletedList, err2 := deleteSkuActSkus(ctx, nil, deleteActInfoMap, vendorActInfoMap)
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deletedList, model.SyncFlagDeletedMask)...)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
db := dao.GetDB()
|
||||
_, err2 := dao.BatchUpdateActEntity(db, model.IsSyncStatusDelete(act.SyncStatus), updateItems)
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"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/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
type tShowStatusAndTypeInfo struct {
|
||||
ShowStatus int
|
||||
ActivityType int
|
||||
}
|
||||
|
||||
func ebaiPageActType2Jx(activityType int) int {
|
||||
if activityType == ebaiapi.PageActivityTypeSkuDiscount || activityType == ebaiapi.PageActivityTypeSkuDirectDown {
|
||||
return model.ActSkuDirectDown
|
||||
} else if activityType == ebaiapi.PageActivityTypeSkuSpecialPrice {
|
||||
return model.ActSkuSecKill
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func ebaiPageActStatus2Jx(status int) int {
|
||||
if status == ebaiapi.PageActivityStatusWaiting || status == ebaiapi.PageActivityStatusOnGoing {
|
||||
return model.ActStatusCreated
|
||||
} else if status == ebaiapi.PageActivityStatusEnded {
|
||||
return model.ActStatusEnded
|
||||
}
|
||||
return model.ActStatusNA
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetPageActList(ctx *jxcontext.Context, createdFrom time.Time) (actList []*model.Act2, err error) {
|
||||
var typeAndStatusList []*tShowStatusAndTypeInfo
|
||||
for _, showStatus := range []int{
|
||||
ebaiapi.PageActivityShowStatusWaiting,
|
||||
ebaiapi.PageActivityShowStatusOnGoing,
|
||||
// ebaiapi.PageActivityStatusEnded,
|
||||
} {
|
||||
for _, activityType := range []int{
|
||||
ebaiapi.PageActivityTypeSkuDiscount,
|
||||
ebaiapi.PageActivityTypeSkuSpecialPrice,
|
||||
ebaiapi.PageActivityTypeSkuDirectDown,
|
||||
} {
|
||||
typeAndStatusList = append(typeAndStatusList, &tShowStatusAndTypeInfo{
|
||||
ShowStatus: showStatus,
|
||||
ActivityType: activityType,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
task := tasksch.NewParallelTask("ebai GetPageActList", tasksch.NewParallelConfig().SetParallelCount(10), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
info := batchItemList[0].(*tShowStatusAndTypeInfo)
|
||||
list, err := api.EbaiAPI.BegetActivityList(info.ShowStatus, info.ActivityType, 0, api.EbaiAPI.GetSupplierID())
|
||||
if err == nil {
|
||||
retVal = list
|
||||
}
|
||||
return retVal, err
|
||||
}, typeAndStatusList)
|
||||
task.Run()
|
||||
list, err := task.GetResult(0)
|
||||
if len(list) > 0 {
|
||||
for _, v := range list {
|
||||
ebaiAct := v.(*ebaiapi.PageActItem)
|
||||
if utils.Timestamp2Time(ebaiAct.CreateTime).Sub(createdFrom) > 0 {
|
||||
act := &model.Act2{
|
||||
Act: model.Act{
|
||||
Name: fmt.Sprintf("%s-%s", ebaiAct.ActivityName, ebaiAct.ActivityID),
|
||||
Type: ebaiPageActType2Jx(ebaiAct.ActivityType),
|
||||
Status: ebaiPageActStatus2Jx(ebaiAct.Status),
|
||||
Source: ebaiAct.User,
|
||||
CreateType: model.ActCreateTypeSpider,
|
||||
BeginAt: utils.Timestamp2Time(ebaiAct.StartTime),
|
||||
EndAt: utils.Timestamp2Time(ebaiAct.EndTime),
|
||||
VendorMask: model.GetVendorMask(model.VendorIDEBAI),
|
||||
LimitCount: 1,
|
||||
},
|
||||
VendorID: model.VendorIDEBAI,
|
||||
VendorOrgCode: api.EbaiAPI.GetSource(),
|
||||
VendorActID: ebaiAct.ActivityID,
|
||||
}
|
||||
actList = append(actList, act)
|
||||
}
|
||||
}
|
||||
}
|
||||
return actList, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetPageActSkuList(ctx *jxcontext.Context, vendorPageActID string) (actStoreSkuList []*model.ActStoreSku2, err error) {
|
||||
skus, err := api.EbaiAPI.BegetActSkuList(utils.Str2Int64(vendorPageActID), 0, api.EbaiAPI.GetSupplierID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range skus {
|
||||
actStoreSku := &model.ActStoreSku2{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
Stock: v.Stock,
|
||||
OriginalPrice: jxutils.StandardPrice2Int(v.OriginalPrice),
|
||||
},
|
||||
VendorStoreID: utils.Int64ToStr(v.Wid),
|
||||
VendorSkuID: v.SkuID,
|
||||
VendorActID: v.ActivityID,
|
||||
ActualActPrice: jxutils.StandardPrice2Int(v.PromotionPrice),
|
||||
}
|
||||
actStoreSkuList = append(actStoreSkuList, actStoreSku)
|
||||
}
|
||||
return actStoreSkuList, nil
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
)
|
||||
|
||||
func TestGetPageActList(t *testing.T) {
|
||||
actList, err := new(PurchaseHandler).GetPageActList(jxcontext.AdminCtx, utils.DefaultTimeValue)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(actList, false))
|
||||
t.Log(len(actList))
|
||||
}
|
||||
|
||||
func TestGetPageActSkuList(t *testing.T) {
|
||||
actList, err := new(PurchaseHandler).GetPageActSkuList(jxcontext.AdminCtx, "3000000001477429")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(actList, false))
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
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/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func OnCallbackMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
globals.SugarLogger.Debugf("ebai OnCallbackMsg msg:%s", utils.Format4Output(msg, true))
|
||||
if CurPurchaseHandler != nil {
|
||||
if orderID := GetOrderIDFromMsg(msg); orderID != "" {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
switch msg.Cmd {
|
||||
case ebaiapi.CmdOrderCreate, ebaiapi.CmdOrderStatus, ebaiapi.CmdOrderUserCancel, ebaiapi.CmdOrderPartRefund:
|
||||
response = CurPurchaseHandler.onOrderMsg(msg)
|
||||
case ebaiapi.CmdOrderDeliveryStatus:
|
||||
response = CurPurchaseHandler.onWaybillMsg(msg)
|
||||
}
|
||||
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDEBAI))
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func GetOrderIDFromMsg(msg *ebaiapi.CallbackMsg) string {
|
||||
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
|
||||
}
|
||||
return utils.Int64ToStr(utils.MustInterface2Int64(orderID))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"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/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) UpdatePlaces() (err error) {
|
||||
provinces, err := api.EbaiAPI.CommonShopCities(0)
|
||||
if err == nil {
|
||||
task := tasksch.NewParallelTask("UpdatePlaces", nil, jxcontext.AdminCtx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
province := batchItemList[0].(*ebaiapi.CityInfo)
|
||||
retSlice := make([]*ebaiapi.CityInfo, 0)
|
||||
if province.IsOpen != 0 {
|
||||
retSlice = append(retSlice, province)
|
||||
cities, err := api.EbaiAPI.CommonShopCities(province.ID)
|
||||
for _, city := range cities {
|
||||
if city.IsOpen != 0 {
|
||||
retSlice = append(retSlice, city)
|
||||
districts, err2 := api.EbaiAPI.CommonShopCities(city.ID)
|
||||
if err = err2; err == nil {
|
||||
for _, district := range districts {
|
||||
if district.IsOpen != 0 {
|
||||
retSlice = append(retSlice, district)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retSlice, err
|
||||
}, provinces)
|
||||
task.Run()
|
||||
places, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
globals.SugarLogger.Debug(utils.Format4Output(places, false))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUpdatePlacese(t *testing.T) {
|
||||
err := new(PurchaseHandler).UpdatePlaces()
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"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/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
CurPurchaseHandler *PurchaseHandler
|
||||
)
|
||||
|
||||
type PurchaseHandler struct {
|
||||
partner.BasePurchasePlatform
|
||||
putils.DefSingleStorePlatform
|
||||
|
||||
shopList []*ebaiapi.ShopInfo
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
if api.EbaiAPI != nil {
|
||||
CurPurchaseHandler = New()
|
||||
partner.RegisterPurchasePlatform(CurPurchaseHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func New() (obj *PurchaseHandler) {
|
||||
obj = new(PurchaseHandler)
|
||||
obj.ISingleStoreStoreSkuHandler = obj
|
||||
return obj
|
||||
}
|
||||
|
||||
func EbaiBusStatus2JxStatus(ebaiStatus int) int {
|
||||
if ebaiStatus == ebaiapi.ShopBusStatusHaveRest {
|
||||
return model.StoreStatusClosed
|
||||
}
|
||||
if ebaiStatus == ebaiapi.ShopBusStatusSuspended {
|
||||
return model.StoreStatusDisabled
|
||||
}
|
||||
return model.StoreStatusOpened
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetVendorID() int {
|
||||
return model.VendorIDEBAI
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
|
||||
globals.SugarLogger.Debugf("ebai UploadImg imgURL:%s, imgName:%s, imgType:%d", imgURL, imgName, imgType)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if imgType == model.ImgTypeMain {
|
||||
imgHint, err = api.EbaiAPI.PictureUpload(imgURL, imgData)
|
||||
} else if imgType == model.ImgTypeDesc {
|
||||
imgHint, err = api.EbaiAPI.SkuUploadRTF(p.getShopID4UploadRTF(), ebaiapi.BuildRFTFromImgs(imgURL))
|
||||
}
|
||||
} else {
|
||||
imgHint = imgURL + ".ebai"
|
||||
}
|
||||
return imgHint, err
|
||||
}
|
||||
|
||||
func getShopIDFromList(shopList []*ebaiapi.ShopInfo) (shopID string) {
|
||||
if len(shopList) > 0 {
|
||||
shopID = shopList[0].ShopID
|
||||
}
|
||||
return shopID
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) getShopID4UploadRTF() (shopID string) {
|
||||
var shopList []*ebaiapi.ShopInfo
|
||||
p.locker.RLock()
|
||||
shopList = p.shopList
|
||||
p.locker.RUnlock()
|
||||
if len(shopList) > 0 {
|
||||
return getShopIDFromList(shopList)
|
||||
}
|
||||
|
||||
p.locker.Lock()
|
||||
shopList = p.shopList
|
||||
if len(shopList) > 0 {
|
||||
p.locker.Unlock()
|
||||
return getShopIDFromList(shopList)
|
||||
}
|
||||
|
||||
defer p.locker.Unlock()
|
||||
shopList, err := api.EbaiAPI.ShopList(ebaiapi.SysStatusAll)
|
||||
if err == nil {
|
||||
if len(shopList) > 0 {
|
||||
p.shopList = shopList
|
||||
shopID = getShopIDFromList(shopList)
|
||||
} else {
|
||||
// p.shopList = []*ebaiapi.ShopInfo{
|
||||
// &ebaiapi.ShopInfo{
|
||||
// ShopID: "",
|
||||
// },
|
||||
// }
|
||||
}
|
||||
}
|
||||
return shopID
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) getVendorCategories(level int, pid int64) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
cats, err := api.EbaiAPI.SkuCategoryList("", level, pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range cats {
|
||||
cat := &model.SkuVendorCategory{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
Name: v.CatName,
|
||||
Level: level,
|
||||
VendorCategoryID: v.CatID,
|
||||
}
|
||||
if level > 1 {
|
||||
cat.ParentID = v.ParentID
|
||||
if level == 3 {
|
||||
cat.IsLeaf = 1
|
||||
}
|
||||
}
|
||||
vendorCats = append(vendorCats, cat)
|
||||
if level < 3 {
|
||||
childVendorCats, err2 := p.getVendorCategories(level+1, utils.Str2Int64(v.CatID))
|
||||
if err2 == nil && len(childVendorCats) > 0 {
|
||||
vendorCats = append(vendorCats, childVendorCats...)
|
||||
} else {
|
||||
cat.IsLeaf = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return vendorCats, nil
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
vendorCats, err = p.getVendorCategories(1, 0)
|
||||
return vendorCats, err
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
const (
|
||||
// testShopBaiduID = "2233976901"
|
||||
// testShopID = 100077
|
||||
|
||||
testShopBaiduID = "2267254343"
|
||||
testShopID = 2
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestGetVendorCategories(t *testing.T) {
|
||||
catList, err := new(PurchaseHandler).GetVendorCategories(jxcontext.AdminCtx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(catList, false))
|
||||
}
|
||||
@@ -1,288 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"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 (p *PurchaseHandler) OnFinancialMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
utils.CallFuncAsync(func() {
|
||||
response = p.onFinancialMsg(msg)
|
||||
})
|
||||
return response
|
||||
}
|
||||
|
||||
// 存储饿百退款订单结账信息
|
||||
func (p *PurchaseHandler) onFinancialMsg(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
var err error
|
||||
if msg.Cmd == ebaiapi.CmdOrderPartRefund { // 部分退款处理
|
||||
if int(utils.MustInterface2Int64(msg.Body["status"])) == ebaiapi.OrderPartRefundSuccess {
|
||||
// 获取到部分退款订单id
|
||||
afsOrderID := GetOrderIDFromMsg(msg)
|
||||
// 处理部分退款信息
|
||||
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 := int(utils.MustInterface2Int64(msg.Body["type"]))
|
||||
if int(utils.MustInterface2Int64(msg.Body["cancel_type"])) == ebaiapi.OrderUserCancelTypeAfterSale &&
|
||||
(messageType == ebaiapi.OrderUserCancelCSAgreed || messageType == ebaiapi.OrderUserCancelMerchantAgreed) {
|
||||
afsOrderID := GetOrderIDFromMsg(msg)
|
||||
// 获得退款订单ID,去本地数据库拿?饿百消息推送只给了订单号,但是没有查询全额退款的接口,只有部分退款才可以查询
|
||||
orderFinancial, err := partner.CurOrderManager.LoadOrderFinancial(afsOrderID, model.VendorIDEBAI)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debug(utils.Format4Output(orderFinancial, false))
|
||||
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(CurPurchaseHandler.OrderFinancialDetail2Refund(orderFinancial, msg))
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai OnFinancialMsg, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrderFinancial", afsOrderID)
|
||||
}
|
||||
}
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderDeliveryStatus { // 转自送调整
|
||||
if utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["status"])) == ebaiapi.WaybillStatusSelfDelivery {
|
||||
vendorOrderID := GetOrderIDFromMsg(msg)
|
||||
orderMap, err := api.EbaiAPI.OrderGet(vendorOrderID)
|
||||
if err == nil {
|
||||
err = CurPurchaseHandler.OnOrderDetail(orderMap, partner.UpdatedPeration)
|
||||
}
|
||||
}
|
||||
}
|
||||
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: GetOrderIDFromMsg(msg),
|
||||
VendorOrderID: GetOrderIDFromMsg(msg),
|
||||
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
|
||||
// BoxMoney: orderFinancial.BoxMoney, // 饿百的餐盒费已经拆分到单条Sku里面,退款时直接计算用户支付sku金额就好了
|
||||
// SkuBoxMoney: orderFinancial.SkuBoxMoney,
|
||||
FreightUserMoney: orderFinancial.FreightMoney,
|
||||
SkuUserMoney: orderFinancial.ActualPayMoney - orderFinancial.FreightMoney,
|
||||
PmSubsidyMoney: orderFinancial.PmSubsidyMoney,
|
||||
}
|
||||
// if msg.Body["timestamp"] != nil {
|
||||
// afsOrder.AfsCreateAt = utils.Timestamp2Time(utils.Str2Int64(utils.Interface2String(msg.Body["timestamp"])))
|
||||
// } else {
|
||||
// globals.SugarLogger.Warnf("ebai OrderFinancialDetail2Refund timestamp is not found in afsOrder:%s", afsOrder.AfsOrderID)
|
||||
// afsOrder.AfsCreateAt = time.Now()
|
||||
// }
|
||||
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
|
||||
globals.SugarLogger.Debug(utils.Format4Output(order, false))
|
||||
if err == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
afsOrder.VendorStoreID = order.VendorStoreID
|
||||
afsOrder.StoreID = order.StoreID
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
|
||||
err = nil
|
||||
}
|
||||
for _, sku := range orderFinancial.Skus {
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
AfsOrderID: sku.VendorOrderID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
StoreID: afsOrder.StoreID,
|
||||
JxStoreID: afsOrder.JxStoreID,
|
||||
VendorSkuID: sku.VendorSkuID,
|
||||
SkuID: sku.SkuID,
|
||||
PromotionType: sku.PromotionType,
|
||||
Name: sku.Name,
|
||||
ShopPrice: sku.ShopPrice,
|
||||
SalePrice: sku.SalePrice,
|
||||
Count: sku.Count,
|
||||
SkuBoxMoney: sku.SkuBoxMoney,
|
||||
UserMoney: sku.UserMoney,
|
||||
PmSubsidyMoney: sku.PmSubsidyMoney,
|
||||
IsAfsOrder: 1,
|
||||
}
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interface{}) (afsOrder *model.AfsOrder) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
AfsOrderID: GetOrderIDFromMap(orderData),
|
||||
VendorOrderID: GetOrderIDFromMap(orderData),
|
||||
}
|
||||
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
|
||||
if err == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
|
||||
err = nil
|
||||
}
|
||||
// 部分退款订单,第三方平台佣金会变化,金额为 orderData["commission"],是否将该字段更新到正向订单结算表中
|
||||
// 不作更新的话,商户可以得到的钱会少几毛钱,最终京西受益
|
||||
// 如果要更新,总佣金,京西佣金是否都要更新,而其它一系列连锁反应,是否需要考虑更新
|
||||
// 或者换个思路,不考虑变更之前的正向订单,在佣金上入手,退款金额减去佣金减少的部分
|
||||
orderFinancial, err := partner.CurOrderManager.LoadOrderFinancial(afsOrder.VendorOrderID, model.VendorIDEBAI)
|
||||
if err == nil {
|
||||
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)
|
||||
err = nil
|
||||
}
|
||||
if orderData["refund_detail"] != nil {
|
||||
refundDetail := orderData["refund_detail"].([]interface{})
|
||||
for _, refundInfo := range refundDetail {
|
||||
xMap := refundInfo.(map[string]interface{})
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
AfsOrderID: afsOrder.AfsOrderID,
|
||||
VendorOrderID: afsOrder.VendorOrderID,
|
||||
// ConfirmTime: getTimeFromInterface(xMap["apply_time"]),
|
||||
VendorSkuID: utils.Interface2String(xMap["sku_id"]),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["custom_sku_id"]), 0)),
|
||||
Name: utils.Interface2String(xMap["name"]),
|
||||
UserMoney: utils.MustInterface2Int64(xMap["total_refund"]),
|
||||
PmSubsidyMoney: utils.MustInterface2Int64(xMap["shop_ele_refund"]),
|
||||
IsAfsOrder: 1,
|
||||
}
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
|
||||
afsOrder.SkuUserMoney += orderSkuFinancial.UserMoney
|
||||
afsOrder.PmSubsidyMoney += orderSkuFinancial.PmSubsidyMoney
|
||||
}
|
||||
if len(refundDetail) > 0 {
|
||||
afsOrder.AfsCreatedAt = getTimeFromInterface(refundDetail[0].(map[string]interface{})["apply_time"])
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, orderID:%s have no refund_detail", afsOrder.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai AfsOrderDetail2Financial, orderID:% refund_detail is nil", afsOrder.VendorOrderID)
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
// 存储饿百正向订单结账信息
|
||||
func (p *PurchaseHandler) OnOrderDetail(result map[string]interface{}, operation string) (err error) {
|
||||
err = partner.CurOrderManager.SaveOrderFinancialInfo(p.OrderDetail2Financial(result), operation)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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(GetOrderIDFromMap(order))
|
||||
// if err == nil {
|
||||
// return p.GetTrueEbaiOrder(result)
|
||||
// }
|
||||
// }
|
||||
// return result1
|
||||
// }
|
||||
|
||||
func (p *PurchaseHandler) OrderDetail2Financial(result map[string]interface{}) (orderFinancial *model.OrderFinancial) {
|
||||
orderFinancial = &model.OrderFinancial{
|
||||
VendorID: model.VendorIDEBAI,
|
||||
}
|
||||
order1 := result["order"].(map[string]interface{})
|
||||
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"])
|
||||
orderFinancial.ReceivableFreight = utils.MustInterface2Int64(order1["send_fee"])
|
||||
orderFinancial.DownFlag = int8(utils.MustInterface2Int64(order1["down_flag"]))
|
||||
|
||||
if int(getInt64FromInterface(order1["delivery_party"])) == ebaiapi.DeliveryPartyFengElmSelf {
|
||||
orderFinancial.SelfDeliveryDiscountMoney = orderFinancial.ReceivableFreight
|
||||
orderFinancial.DistanceFreightMoney = 0
|
||||
// 通过本地数据库去取是否转美团/达达,并计算运费
|
||||
// wayBill, err := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
|
||||
// if err == nil {
|
||||
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
// }
|
||||
}
|
||||
orderFinancial.BoxMoney = utils.ForceInterface2Int64(order1["package_fee"])
|
||||
orderFinancial.ActualPayMoney = utils.ForceInterface2Int64(order1["user_fee"])
|
||||
orderFinancial.PmMoney = utils.ForceInterface2Int64(order1["commission"])
|
||||
orderFinancial.ShopMoney = utils.ForceInterface2Int64(order1["shop_fee"])
|
||||
order, err := partner.CurOrderManager.LoadOrder(orderFinancial.VendorOrderID, orderFinancial.VendorID)
|
||||
storeID := 0
|
||||
jxStoreID := 0
|
||||
if err == nil {
|
||||
storeID = order.StoreID
|
||||
jxStoreID = order.JxStoreID
|
||||
skus := order.Skus
|
||||
if skus != nil {
|
||||
for _, x := range skus {
|
||||
orderFinancial.ShopPriceMoney += x.ShopPrice * int64(x.Count)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("ebai OrderDetail2Financial, orderID:%s is not found from partner.CurOrderManager.LoadOrder", orderFinancial.VendorOrderID)
|
||||
err = nil
|
||||
}
|
||||
shop := result["shop"].(map[string]interface{})
|
||||
if result["products"] != nil {
|
||||
products := result["products"].([]interface{})
|
||||
for _, x := range products {
|
||||
for _, y := range x.([]interface{}) {
|
||||
product := y.(map[string]interface{})
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
// OrderFinancialID: orderFinancial.VendorOrderID,
|
||||
// ConfirmTime: getTimeFromInterface(order1["create_time"]),
|
||||
VendorStoreID: utils.Interface2String(shop["baidu_shop_id"]),
|
||||
StoreID: storeID,
|
||||
JxStoreID: jxStoreID,
|
||||
VendorSkuID: utils.Interface2String(product["baidu_product_id"]),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["custom_sku_id"]), 0)),
|
||||
Name: utils.Interface2String(product["product_name"]),
|
||||
SalePrice: utils.MustInterface2Int64(product["product_price"]),
|
||||
Count: int(utils.MustInterface2Int64(product["product_amount"])),
|
||||
SkuBoxMoney: utils.MustInterface2Int64(product["package_fee"]),
|
||||
IsAfsOrder: 0,
|
||||
}
|
||||
orderFinancial.Skus = append(orderFinancial.Skus, orderSkuFinancial)
|
||||
orderFinancial.SalePriceMoney += orderSkuFinancial.SalePrice * int64(orderSkuFinancial.Count)
|
||||
orderFinancial.SkuBoxMoney += orderSkuFinancial.SkuBoxMoney
|
||||
orderFinancial.BoxMoney -= orderSkuFinancial.SkuBoxMoney
|
||||
}
|
||||
}
|
||||
}
|
||||
if result["discount"] != nil {
|
||||
discount := result["discount"].([]interface{})
|
||||
for _, x := range discount {
|
||||
xMap := x.(map[string]interface{})
|
||||
discountPrice := utils.MustInterface2Int64(xMap["fee"])
|
||||
orderFinancial.DiscountMoney += discountPrice
|
||||
orderFinancial.PmSubsidyMoney += utils.MustInterface2Int64(xMap["baidu_rate"]) // 平台承担补贴
|
||||
activity := &model.OrderDiscountFinancial{
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
// ActivityName: utils.Interface2String(xMap["desc"]),
|
||||
// ActivityMoney: discountPrice,
|
||||
VendorActivityID: utils.Interface2String(xMap["activity_id"]),
|
||||
Type: utils.Interface2String(xMap["type"]),
|
||||
}
|
||||
orderFinancial.Discounts = append(orderFinancial.Discounts, activity)
|
||||
// 通过活动Id去取,京西活动补贴
|
||||
// orderFinancial.JxSubsidyMoney +=
|
||||
}
|
||||
}
|
||||
orderFinancial.FreightDiscountMoney = orderFinancial.TotalDiscountMoney - orderFinancial.DiscountMoney
|
||||
return orderFinancial
|
||||
}
|
||||
|
||||
func getInt64FromInterface(strOrNum interface{}) int64 {
|
||||
var resultNum int64
|
||||
if resultStr, ok := strOrNum.(string); ok {
|
||||
resultNum = utils.Str2Int64WithDefault(resultStr, 0)
|
||||
} else {
|
||||
resultNum = utils.Interface2Int64WithDefault(strOrNum, 0)
|
||||
}
|
||||
return resultNum
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func TestOnFinancialMsg(t *testing.T) {
|
||||
msg := &ebaiapi.CallbackMsg{
|
||||
Timestamp: time.Now().Unix(),
|
||||
Body: make(map[string]interface{}),
|
||||
}
|
||||
msg.Body["order_id"] = "1554939646172038357"
|
||||
|
||||
// 部分退款
|
||||
msg.Cmd = "order.partrefund.push"
|
||||
msg.Body["status"] = json.Number("20")
|
||||
|
||||
// 全单退款
|
||||
// msg.Cmd = "order.user.cancel"
|
||||
// msg.Body["type"] = json.Number("40")
|
||||
// msg.Body["cancel_type"] = json.Number("2")
|
||||
|
||||
res := CurPurchaseHandler.onAfsOrderMsg(msg)
|
||||
fmt.Println(res)
|
||||
}
|
||||
|
||||
func TestOnOrderDetail(t *testing.T) {
|
||||
orderID := "1554939646172038357"
|
||||
result, err := api.EbaiAPI.OrderGet(orderID)
|
||||
if err == nil {
|
||||
new(PurchaseHandler).OnOrderDetail(result, partner.CreatedPeration)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package ebai
|
||||
@@ -1,722 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"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/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"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
// acceptOrderDelay = 180 * time.Second
|
||||
// pickupOrderDelay = 260 * time.Second
|
||||
pickupOrderDelay = 1 * time.Minute
|
||||
|
||||
callDeliveryDelay = 10 * time.Minute
|
||||
callDeliveryDelayGap = 30
|
||||
|
||||
fakeAcceptOrder = "fake_accept_order"
|
||||
fakeOrderAdjustFinished = "fake_order_adjust_finished"
|
||||
fakeOrderCanceled = "fake_order_canceled"
|
||||
)
|
||||
|
||||
// 饿百的接单会直接召唤配送,为了统一将饿百的接单影射成拣货完成,然后模拟一个接单消息
|
||||
|
||||
var (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
ebaiapi.CmdOrderCreate: model.OrderStatusWaitAccepted,
|
||||
ebaiapi.OrderStatusNew: model.OrderStatusWaitAccepted,
|
||||
fakeAcceptOrder: model.OrderStatusAccepted,
|
||||
ebaiapi.OrderStatusAccepted: model.OrderStatusFinishedPickup,
|
||||
ebaiapi.OrderStatusCourierAccepted: model.OrderStatusDelivering,
|
||||
ebaiapi.OrderStatusCourierPickedup: model.OrderStatusDelivering,
|
||||
ebaiapi.OrderStatusFinished: model.OrderStatusFinished,
|
||||
ebaiapi.OrderStatusCanceled: model.OrderStatusCanceled,
|
||||
|
||||
fakeOrderAdjustFinished: model.OrderStatusAdjust,
|
||||
fakeOrderCanceled: model.OrderStatusCanceled,
|
||||
}
|
||||
|
||||
skuActTypeMap = map[string]int{
|
||||
ebaiapi.OrderSkuDiscountTypeZhe: 1,
|
||||
ebaiapi.OrderSkuDiscountTypeReduce: 1,
|
||||
ebaiapi.OrderSkuDiscountTypeTe: 1,
|
||||
}
|
||||
deliveryTypeMap = map[int]string{
|
||||
ebaiapi.DeliveryPartyFengElmSelf: model.OrderDeliveryTypeStoreSelf,
|
||||
}
|
||||
)
|
||||
|
||||
func mapDeliveryType(ebaiDeliveryParty int, businessType int) (deliveryType string) {
|
||||
if businessType == ebaiapi.DeliveryBusinessTypeZT {
|
||||
return model.OrderDeliveryTypeSelfTake
|
||||
} else {
|
||||
deliveryType = deliveryTypeMap[ebaiDeliveryParty]
|
||||
if deliveryType == "" {
|
||||
deliveryType = model.OrderDeliveryTypePlatform
|
||||
}
|
||||
}
|
||||
return deliveryType
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
|
||||
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
|
||||
return status
|
||||
}
|
||||
return model.OrderStatusUnknown
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) {
|
||||
order, _, err = p.getOrder(vendorOrderID)
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
|
||||
status, err = api.EbaiAPI.OrderStatusGet(vendorOrderID)
|
||||
if err == nil {
|
||||
status = p.getStatusFromVendorStatus(utils.Int2Str(status))
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) getOrder(vendorOrderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
|
||||
for i := 0; i < 2; i++ {
|
||||
orderMap, err = api.EbaiAPI.OrderGet(vendorOrderID)
|
||||
if err == nil {
|
||||
order = p.Map2Order(orderMap)
|
||||
// 饿百订单有时会出现取不到baidu_shop_id的情况,重试
|
||||
if order.VendorStoreID != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
return order, orderMap, 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"])
|
||||
giftSkus, discountMoney := getZengSkus(vendorOrderID, result1)
|
||||
order.DiscountMoney = discountMoney
|
||||
order.Skus = append(order.Skus, giftSkus...)
|
||||
order.ActualPayPrice = utils.MustInterface2Int64(result2["user_fee"])
|
||||
order.TotalShopMoney = utils.MustInterface2Int64(result2["shop_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 getZengSkus(orderID string, orderMan map[string]interface{}) (skus []*model.OrderSku, discountMoney int64) {
|
||||
discounts, _ := orderMan["discount"].([]interface{})
|
||||
for _, v := range discounts {
|
||||
discount := v.(map[string]interface{})
|
||||
discountType := utils.Interface2String(discount["type"])
|
||||
if discountType == ebaiapi.OrderSkuDiscountTypeZeng {
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDEBAI,
|
||||
Count: 1,
|
||||
SkuID: 0,
|
||||
VendorSkuID: "",
|
||||
SkuName: utils.Interface2String(discount["desc"]),
|
||||
VendorPrice: 0,
|
||||
}
|
||||
skus = append(skus, sku)
|
||||
}
|
||||
discountMoney += utils.Interface2Int64WithDefault(discount["fee"], 0)
|
||||
}
|
||||
return skus, discountMoney
|
||||
}
|
||||
|
||||
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 getExpectedDeliveredTime(orderMap map[string]interface{}) (expectedTime time.Time) {
|
||||
expectedTime = getTimeFromInterface(orderMap["latest_send_time"])
|
||||
if utils.IsTimeZero(expectedTime) {
|
||||
expectedTime = getTimeFromInterface(orderMap["send_time"])
|
||||
}
|
||||
return expectedTime
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
result := orderData
|
||||
shopMap := result["shop"].(map[string]interface{})
|
||||
orderMap := result["order"].(map[string]interface{})
|
||||
userMap := result["user"].(map[string]interface{})
|
||||
vendorOrderID := orderMap["order_id"].(string)
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: vendorOrderID,
|
||||
VendorOrderID2: utils.Interface2String(orderMap["eleme_order_id"]),
|
||||
VendorID: model.VendorIDEBAI,
|
||||
VendorStoreID: utils.Interface2String(shopMap["baidu_shop_id"]),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(shopMap["id"]), 0)),
|
||||
StoreName: utils.Interface2String(shopMap["name"]),
|
||||
VendorUserID: utils.Interface2String(userMap["user_id"]),
|
||||
ConsigneeName: utils.Interface2String(userMap["name"]),
|
||||
ConsigneeMobile: jxutils.FormalizeMobile(utils.Interface2String(userMap["phone"])),
|
||||
ConsigneeAddress: utils.Interface2String(userMap["address"]),
|
||||
CoordinateType: model.CoordinateTypeMars,
|
||||
BuyerComment: utils.TrimBlankChar(utils.Interface2String(orderMap["remark"])),
|
||||
ExpectedDeliveredTime: getExpectedDeliveredTime(orderMap),
|
||||
PickDeadline: utils.DefaultTimeValue,
|
||||
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(orderMap["status"])),
|
||||
OrderSeq: int(utils.ForceInterface2Int64(orderMap["order_index"])),
|
||||
StatusTime: getTimeFromInterface(orderMap["create_time"]),
|
||||
OrderCreatedAt: getTimeFromInterface(orderMap["create_time"]),
|
||||
// OrderFinishedAt: getTimeFromInterface(orderMap["finished_time"]),
|
||||
OriginalData: string(utils.MustMarshal(result)),
|
||||
ActualPayPrice: utils.ForceInterface2Int64(orderMap["user_fee"]),
|
||||
BaseFreightMoney: utils.ForceInterface2Int64(orderMap["send_fee"]),
|
||||
TotalShopMoney: utils.ForceInterface2Int64(orderMap["shop_fee"]),
|
||||
DeliveryType: mapDeliveryType(int(utils.ForceInterface2Int64(orderMap["delivery_party"])), int(utils.ForceInterface2Int64(orderMap["business_type"]))),
|
||||
|
||||
InvoiceTitle: utils.Interface2String(orderMap["invoice_title"]),
|
||||
InvoiceTaxerID: utils.Interface2String(orderMap["taxer_id"]),
|
||||
InvoiceEmail: jxutils.GetOneEmailFromStr(utils.Interface2String(orderMap["remark"])),
|
||||
|
||||
VendorOrgCode: utils.Interface2String(result["source"]),
|
||||
}
|
||||
finishTime := getTimeFromInterface(orderMap["finished_time"])
|
||||
if finishTime == utils.ZeroTimeValue {
|
||||
order.OrderFinishedAt = utils.DefaultTimeValue
|
||||
} else {
|
||||
order.OrderFinishedAt = finishTime
|
||||
}
|
||||
if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) {
|
||||
order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 饿百要求在5分钟内拣货,不然订单会被取消
|
||||
}
|
||||
if order.ConsigneeMobile == "" {
|
||||
if mobileInfo, err := api.EbaiAPI.OrderPrivateInfo(vendorOrderID); err == nil {
|
||||
order.ConsigneeMobile = jxutils.FormalizeMobile(mobileInfo.ShortNumber)
|
||||
}
|
||||
}
|
||||
if order.StoreID > math.MaxInt32 {
|
||||
order.StoreID = 0
|
||||
}
|
||||
order.Status = p.getStatusFromVendorStatus(order.VendorStatus)
|
||||
if utils.MustInterface2Int64(orderMap["send_immediately"]) == 1 {
|
||||
order.BusinessType = model.BusinessTypeImmediate
|
||||
} else {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
if utils.IsTimeZero(order.ExpectedDeliveredTime) {
|
||||
order.ExpectedDeliveredTime = getTimeFromInterface(orderMap["latest_send_time"])
|
||||
}
|
||||
}
|
||||
|
||||
deliveryGeo := userMap["coord_amap"].(map[string]interface{})
|
||||
originalLng := utils.Interface2Float64WithDefault(deliveryGeo["longitude"], 0.0) // 饿百的订单在过一段时间后,经纬度信息会变成字符串"**"
|
||||
originalLat := utils.Interface2Float64WithDefault(deliveryGeo["latitude"], 0.0)
|
||||
// lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysBaidu)
|
||||
// if err2 == nil {
|
||||
// originalLng = lng
|
||||
// originalLat = lat
|
||||
// order.CoordinateType = model.CoordinateTypeMars
|
||||
// }
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
|
||||
|
||||
products := result["products"].([]interface{})[0].([]interface{})
|
||||
for _, product2 := range products {
|
||||
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: productAmount,
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
|
||||
VendorSkuID: utils.Interface2String(product["baidu_product_id"]),
|
||||
SkuName: skuName,
|
||||
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 = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
|
||||
}
|
||||
// if product["isGift"].(bool) {
|
||||
// sku.SkuType = 1
|
||||
// }
|
||||
order.Skus = append(order.Skus, sku)
|
||||
}
|
||||
giftSkus, discountMoney := getZengSkus(vendorOrderID, orderData)
|
||||
order.DiscountMoney = discountMoney
|
||||
order.Skus = append(order.Skus, giftSkus...)
|
||||
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 {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderConfirm(order.VendorOrderID)
|
||||
utils.AfterFuncWithRecover(time.Minute, func() {
|
||||
err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID)
|
||||
})
|
||||
}
|
||||
p.postFakeMsg(order.VendorOrderID, fakeAcceptOrder)
|
||||
} else {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, "bu")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
// err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID)
|
||||
}
|
||||
if err == nil {
|
||||
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusAccepted)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
|
||||
return err
|
||||
}
|
||||
|
||||
// 将订单从购物平台配送转为自送
|
||||
func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if err = api.EbaiAPI.OrderSwitchselfdelivery(order.VendorOrderID); err != nil {
|
||||
if utils.IsErrMatch(err, "301251", nil) {
|
||||
if deliveryStatus, err2 := api.EbaiAPI.OrderDeliveryGet(order.VendorOrderID); err2 == nil {
|
||||
deliveryStatus := utils.Int64ToStr(utils.MustInterface2Int64(deliveryStatus["status"]))
|
||||
if deliveryStatus == ebaiapi.WaybillStatusSelfDelivery {
|
||||
err = nil
|
||||
} else if deliveryStatus == ebaiapi.WaybillStatusDeliveryCancled {
|
||||
p.trySyncCancelStatus(order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
// 饿百不会发送配送中,模拟发送
|
||||
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) trySyncCancelStatus(vendorOrderID string) (err error) {
|
||||
orderInfo, err := api.EbaiAPI.OrderGet2(vendorOrderID)
|
||||
if err == nil {
|
||||
if utils.Int2Str(orderInfo.Order.Status) == ebaiapi.OrderStatusCanceled {
|
||||
p.postFakeMsg(vendorOrderID, fakeOrderCanceled)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 将订单从购物平台配送转为自送后又送达
|
||||
func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
// todo 饿百转商家自送后,没有确认送达的概念,空操作
|
||||
return err
|
||||
}
|
||||
|
||||
// 完全自送的门店表示开始配送
|
||||
func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderSendOut(order.VendorOrderID, userName)
|
||||
}
|
||||
if err == nil {
|
||||
// 饿百不会发送配送中,模拟发送
|
||||
p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 完全自送的门店表示配送完成
|
||||
func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderComplete(order.VendorOrderID, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//
|
||||
func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
|
||||
if c.isAfsMsg(msg) {
|
||||
retVal = c.onAfsOrderMsg(msg)
|
||||
} else {
|
||||
status := c.callbackMsg2Status(msg)
|
||||
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 {
|
||||
// 处理饿百降级订单的情况
|
||||
// 是否降级;1:是,0:否;极少数订单因网络或信息交互异常,导致订单部分字段(如订单金额)生成延迟,此时订单会被标记为“已降级”状态,需开发者重新调用查看订单详情接口获取完整订单数据。
|
||||
// toto sku是否也需要处理?
|
||||
if status.Status == model.OrderStatusDelivering || status.Status == model.OrderStatusFinished {
|
||||
if order, err2 := partner.CurOrderManager.LoadOrder(status.VendorOrderID, status.VendorID); err2 == nil {
|
||||
if order.TotalShopMoney == 0 {
|
||||
if order2, err2 := c.GetOrder(msg.Source, status.VendorOrderID); err2 == nil {
|
||||
order.TotalShopMoney = order2.TotalShopMoney
|
||||
order.PmSubsidyMoney = order2.PmSubsidyMoney
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"TotalShopMoney", "PmSubsidyMoney"})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged(msg.Source, status)
|
||||
}
|
||||
}
|
||||
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
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 {
|
||||
// 饿百订单有时会出现取不到baidu_shop_id的情况,返回错误让服务器重试
|
||||
if order.VendorStoreID == "" {
|
||||
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, fmt.Errorf("订单%s的baidu_shop_id为空", order.VendorOrderID), "")
|
||||
}
|
||||
if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.OnOrderDetail(orderMap, partner.CreatedPeration)
|
||||
})
|
||||
}
|
||||
}
|
||||
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, map[string]interface{}{
|
||||
"source_order_id": vendorOrderID,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) {
|
||||
orderID := GetOrderIDFromMsg(msg)
|
||||
orderStatus = &model.OrderStatus{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDEBAI,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: orderID,
|
||||
RefVendorID: model.VendorIDEBAI,
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
VendorStatus: msg.Cmd,
|
||||
}
|
||||
if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||||
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 /* || msgType == ebaiapi.OrderUserCancelCSIntervene */ {
|
||||
orderStatus.Status = model.OrderStatusApplyCancel
|
||||
} else if msgType == ebaiapi.OrderUserCancelCSRefused ||
|
||||
msgType == ebaiapi.OrderUserCancelMerchantRefused {
|
||||
orderStatus.Status = model.OrderStatusVendorRejectCancel
|
||||
} else if msgType == ebaiapi.OrderUserCancelInvalid {
|
||||
orderStatus.Status = model.OrderStatusUndoApplyCancel
|
||||
} else if msgType == ebaiapi.OrderUserCancelCSAgreed ||
|
||||
msgType == ebaiapi.OrderUserCancelMerchantAgreed {
|
||||
orderStatus.Status = model.OrderStatusVendorAgreeCancel
|
||||
}
|
||||
}
|
||||
} else if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||||
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
|
||||
}
|
||||
} else if status, ok := msg.Body["status"]; ok {
|
||||
if vendorStatus, ok := status.(string); ok {
|
||||
orderStatus.VendorStatus = vendorStatus
|
||||
} else {
|
||||
orderStatus.VendorStatus = utils.Int64ToStr(utils.MustInterface2Int64(status))
|
||||
}
|
||||
orderStatus.Remark = utils.Interface2String(msg.Body["reason"])
|
||||
}
|
||||
if orderStatus.Status == 0 {
|
||||
orderStatus.Status = c.getStatusFromVendorStatus(orderStatus.VendorStatus)
|
||||
}
|
||||
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分钟内拣货,不然订单会被取消
|
||||
Timeout: pickupOrderDelay,
|
||||
}
|
||||
} else if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusFinishedPickup {
|
||||
params = &partner.StatusActionParams{ // 立即达订单有效,自配送延时召唤配送
|
||||
Timeout: callDeliveryDelay,
|
||||
TimeoutGap: callDeliveryDelayGap,
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) getOrderStoreDeliveryType(order *model.GoodsOrder) (deliveryType int) {
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM store_map t1
|
||||
WHERE t1.vendor_store_id = ?
|
||||
AND t1.vendor_id = ?
|
||||
AND t1.deleted_at = ?
|
||||
`
|
||||
db := dao.GetDB()
|
||||
var storeMap *model.StoreMap
|
||||
if err := dao.GetRow(db, &storeMap, sql, order.VendorStoreID, model.VendorIDEBAI, utils.DefaultTimeValue); err == nil {
|
||||
return int(storeMap.DeliveryType)
|
||||
} else if !dao.IsNoRowsError(err) {
|
||||
globals.SugarLogger.Warnf("getOrderStoreDeliveryType orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return scheduler.StoreDeliveryTypeByPlatform
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) postFakeMsg(vendorOrderID, vendorStatus string) {
|
||||
msg := &ebaiapi.CallbackMsg{
|
||||
Cmd: ebaiapi.CmdOrderStatus,
|
||||
Timestamp: time.Now().Unix(),
|
||||
Body: map[string]interface{}{
|
||||
"status": vendorStatus,
|
||||
"order_id": vendorOrderID,
|
||||
},
|
||||
}
|
||||
utils.CallFuncAsync(func() {
|
||||
OnCallbackMsg(msg)
|
||||
})
|
||||
}
|
||||
|
||||
func getTimeFromInterface(timeValue interface{}) time.Time {
|
||||
var timeStamp int64
|
||||
if timeStr, ok := timeValue.(string); ok {
|
||||
timeStamp = utils.Str2Int64WithDefault(timeStr, 0)
|
||||
} else {
|
||||
timeStamp = utils.Interface2Int64WithDefault(timeValue, 0)
|
||||
}
|
||||
if timeStamp < 1538103149 { // 立即达订单给的是1(而不是空,0),1538103149不是特殊值,只是一个任意之前的时间,这样写可以处理
|
||||
return utils.DefaultTimeValue
|
||||
}
|
||||
return utils.Timestamp2Time(timeStamp)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
|
||||
mobile, err = api.EbaiAPI.GetRealMobile4Order(order.VendorOrderID)
|
||||
return mobile, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if isAgree {
|
||||
err = api.EbaiAPI.OrderAgreeRefund(order.VendorOrderID)
|
||||
} else {
|
||||
err = api.EbaiAPI.OrderDisagreeRefund(order.VendorOrderID, reason)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
// 饿百必须要确认订单后才能调整单
|
||||
if order.Status < model.OrderStatusFinishedPickup {
|
||||
err = c.PickupGoods(order, false, ctx.GetUserName())
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
|
||||
if utils.IsTimeZero(queryDate) {
|
||||
return nil, fmt.Errorf("queryDate必须指定")
|
||||
}
|
||||
fromDate := utils.Time2Date(queryDate)
|
||||
toDate := fromDate.Add(24*time.Hour - 1)
|
||||
var vendorStoreIDs []string
|
||||
if vendorStoreID == "" {
|
||||
vendorStoreIDs, err = c.GetAllStoresVendorID(ctx, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
vendorStoreIDs = []string{vendorStoreID}
|
||||
}
|
||||
task := tasksch.NewParallelTask("ebai ListOrders", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorStoreID := batchItemList[0].(string)
|
||||
orderList, err := api.EbaiAPI.OrderListAll("", utils.Str2Int64(vendorStoreID), fromDate.Unix(), toDate.Unix(), 0)
|
||||
if err == nil {
|
||||
retVal = orderList
|
||||
}
|
||||
return retVal, err
|
||||
}, vendorStoreIDs)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
orderList, err := task.GetResult(0)
|
||||
if err == nil && len(orderList) > 0 {
|
||||
vendorOrderIDs = make([]string, len(orderList))
|
||||
for k, v := range orderList {
|
||||
orderInfo := v.(*ebaiapi.ListOrderItemInfo)
|
||||
vendorOrderIDs[k] = orderInfo.OrderID
|
||||
}
|
||||
}
|
||||
return vendorOrderIDs, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
|
||||
orderInfo, err := api.EbaiAPI.GetStoreOrderInfo(vendorOrderID)
|
||||
if err == nil {
|
||||
if orderBasic, _ := orderInfo["order_basic"].(map[string]interface{}); orderBasic != nil {
|
||||
tipFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(orderBasic["delivery_tip_amount"], 0))
|
||||
}
|
||||
}
|
||||
return tipFee, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ModifyTip4OrderWaybill(vendorOrderID, "", jxutils.IntPrice2Standard(tipFee), 0)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "HTTP code is not 200") {
|
||||
return fmt.Errorf("饿百此订单暂不支持加小费!")
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
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,
|
||||
|
||||
VendorOrgCode: msg.Source,
|
||||
// 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 afsOrder = c.createAfsOrder(msg); afsOrder != nil {
|
||||
// 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 (p *PurchaseHandler) createAfsOrder(msg *ebaiapi.CallbackMsg) (afsOrder *model.AfsOrder) {
|
||||
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
|
||||
afsOrder, err := partner.CurOrderManager.CreateAfsOrderFromOrder(utils.Int64ToStr(cancelData.OrderID), model.VendorIDEBAI)
|
||||
if err == nil {
|
||||
afsOrder.AfsOrderID = afsOrder.VendorOrderID
|
||||
afsOrder.AfsCreatedAt = utils.Timestamp2Time(msg.Timestamp)
|
||||
} else {
|
||||
afsOrder = nil
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 发起全款退款
|
||||
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
return c.PartRefundOrder(ctx, order, order.Skus, reason)
|
||||
}
|
||||
|
||||
// 发起部分退款
|
||||
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, orderSkus2AfsSkus(refundSkuList))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func orderSkus2AfsSkus(refundSkuList []*model.OrderSku) (removeSkuList []*ebaiapi.RefundSku) {
|
||||
for _, v := range refundSkuList {
|
||||
refundSku := &ebaiapi.RefundSku{
|
||||
CustomeSkuID: utils.Int2Str(v.SkuID),
|
||||
Number: utils.Int2Str(v.Count),
|
||||
}
|
||||
removeSkuList = append(removeSkuList, refundSku)
|
||||
}
|
||||
return removeSkuList
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// 饿百的评价不是一点一点出来的,而是一下把前一天的全部崩出来。。。
|
||||
|
||||
const (
|
||||
RefreshCommentTime = 84 * time.Hour
|
||||
RefreshCommentTimeInterval = 60 * time.Minute
|
||||
EBAI_BAD_COMMENTS_MAX_MODIFY_TIME = 24 // 小时
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) StartRefreshComment() {
|
||||
utils.AfterFuncWithRecover(5*time.Second, func() {
|
||||
c.refreshCommentOnce()
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) refreshCommentOnce() {
|
||||
c.RefreshComment(time.Now().Add(-RefreshCommentTime), time.Now())
|
||||
utils.AfterFuncWithRecover(RefreshCommentTimeInterval, func() {
|
||||
c.refreshCommentOnce()
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) RefreshComment(fromTime, toTime time.Time) (err error) {
|
||||
globals.SugarLogger.Debugf("RefreshComment fromTime:%s, toTime:%s", utils.Time2Str(fromTime), utils.Time2Str(toTime))
|
||||
var orderCommentList []*model.OrderComment
|
||||
stepGap := 24 * time.Hour
|
||||
stepFromTime := fromTime
|
||||
for {
|
||||
stepToTime := stepFromTime.Add(stepGap - time.Second)
|
||||
if stepToTime.Sub(toTime) > 0 {
|
||||
stepToTime = toTime
|
||||
}
|
||||
if stepToTime.Sub(stepFromTime) == 0 {
|
||||
break
|
||||
}
|
||||
resultList, err2 := api.EbaiAPI.GetEleCommentList(stepFromTime, stepToTime, "", "", ebaiapi.ReplyStatusAll, ebaiapi.CommentLevelAll, ebaiapi.CommentContentAll)
|
||||
if err = err2; err == nil {
|
||||
for _, result := range resultList {
|
||||
orderComment := &model.OrderComment{
|
||||
VendorOrderID: utils.Interface2String(result["order_id"]),
|
||||
VendorID: model.VendorIDELM,
|
||||
UserCommentID: utils.Int64ToStr(utils.MustInterface2Int64(result["comment_id"])),
|
||||
// VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["shop_id"])), // 这个shop_id是饿了么ID,不是饿百ID
|
||||
TagList: "",
|
||||
Score: int8(utils.MustInterface2Int64(result["service_rating"])),
|
||||
Content: utils.Interface2String(result["content"]),
|
||||
CommentCreatedAt: utils.Str2Time(utils.Interface2String(result["create_time"])),
|
||||
IsReplied: int8(1 - utils.MustInterface2Int64(result["can_reply"])),
|
||||
ModifyDuration: EBAI_BAD_COMMENTS_MAX_MODIFY_TIME,
|
||||
OriginalMsg: string(utils.MustMarshal(result)),
|
||||
}
|
||||
// 直接得到的订单是饿了么的,尝试统一成饿百
|
||||
if order, err := partner.CurOrderManager.LoadOrder2(orderComment.VendorOrderID, model.VendorIDEBAI); err == nil {
|
||||
orderComment.VendorOrderID = order.VendorOrderID
|
||||
orderComment.VendorOrderID2 = order.VendorOrderID2
|
||||
orderComment.VendorID = model.VendorIDEBAI
|
||||
|
||||
orderComment.VendorStoreID = order.VendorStoreID
|
||||
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile
|
||||
} else {
|
||||
globals.SugarLogger.Infof("RefreshComment, load orderID:%s failed", orderComment.VendorOrderID)
|
||||
}
|
||||
orderCommentList = append(orderCommentList, orderComment)
|
||||
}
|
||||
} else {
|
||||
// globals.SugarLogger.Warnf("RefreshComment stepFromTime:%s, stepToTime:%s failed with error:%v", utils.Time2Str(stepFromTime), utils.Time2Str(stepToTime), err)
|
||||
// break //?
|
||||
}
|
||||
if stepToTime.Sub(toTime) == 0 {
|
||||
break
|
||||
}
|
||||
stepFromTime = stepToTime.Add(time.Second)
|
||||
}
|
||||
if err == nil && len(orderCommentList) > 0 {
|
||||
err = partner.CurOrderManager.OnOrderComments(orderCommentList)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string,orderComment *model.OrderComment, replyComment string) (err error) {
|
||||
if orderComment.VendorStoreID != "" && orderComment.UserCommentID != "" {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.OrderRatesReply("", utils.Str2Int64(orderComment.VendorStoreID), orderComment.UserCommentID, replyComment)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
)
|
||||
|
||||
func TestGetOrder4PartRefund(t *testing.T) {
|
||||
order, err := CurPurchaseHandler.GetOrder4PartRefund("1556529608021993938")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
t.Log(utils.Format4Output(order, false))
|
||||
}
|
||||
}
|
||||
|
||||
func TestListOrders(t *testing.T) {
|
||||
order, err := CurPurchaseHandler.ListOrders(jxcontext.AdminCtx, "", nil, utils.GetCurDate(), "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
t.Log(utils.Format4Output(order, false))
|
||||
}
|
||||
}
|
||||
@@ -1,552 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"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/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"
|
||||
)
|
||||
|
||||
type tEbaiStoreInfo struct {
|
||||
model.Store
|
||||
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
|
||||
VendorStoreID string `orm:"column(vendor_store_id)"`
|
||||
RealLastOperator string
|
||||
EbaiStoreStatus int
|
||||
SyncStatus int
|
||||
|
||||
ProvinceID int `orm:"column(province_id)"`
|
||||
CityID int `orm:"column(city_id)"`
|
||||
DistrictID int `orm:"column(district_id)"`
|
||||
VendorStoreName string
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStore(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
|
||||
var store tEbaiStoreInfo
|
||||
sql := `
|
||||
SELECT t1.*, t2.status ebai_store_status, t2.vendor_store_id,
|
||||
IF(t1.updated_at > t2.updated_at, t1.last_operator, t2.last_operator) real_last_operator, t2.sync_status,
|
||||
province.ebai_code province_id, city.ebai_code city_id, district.ebai_code district_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 district ON t1.district_code = district.code
|
||||
JOIN place city ON t1.city_code = city.code
|
||||
JOIN place province ON city.parent_code = province.code
|
||||
WHERE t1.id = ? AND t2.id IS NULL;
|
||||
`
|
||||
if err = dao.GetRow(db, &store, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil {
|
||||
params := genStoreMapFromStore(&store)
|
||||
params["shop_id"] = store.ID
|
||||
params["business_form_id"] = "179"
|
||||
params["service_phone"] = store.Tel1
|
||||
params["invoice_support"] = 2
|
||||
params["package_box_price"] = 0
|
||||
params["encrypt"] = ""
|
||||
|
||||
params["category1"] = ""
|
||||
params["category2"] = ""
|
||||
params["category3"] = ""
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
intVendorStoreID, err2 := api.EbaiAPI.ShopCreate(params)
|
||||
if err = err2; err == nil {
|
||||
return utils.Int64ToStr(intVendorStoreID), err
|
||||
}
|
||||
} else {
|
||||
return utils.Int64ToStr(jxutils.GenFakeID()), nil
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 2019-07-26 疑似饿百将门店返回的坐标类型从float64改为string了
|
||||
func getCoordintate(data interface{}) float64 {
|
||||
if str, ok := data.(string); ok {
|
||||
return utils.Str2Float64WithDefault(str, 0)
|
||||
}
|
||||
return utils.MustInterface2Float64(data)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (*dao.StoreDetail, error) {
|
||||
baiduShopID := utils.Str2Int64WithDefault(vendorStoreID, 0)
|
||||
if baiduShopID == 0 {
|
||||
return nil, fmt.Errorf("饿百门店ID:%s非法,应该是一个整数", vendorStoreID)
|
||||
}
|
||||
result, err := api.EbaiAPI.ShopGet("", baiduShopID)
|
||||
if err == nil {
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(result, false))
|
||||
retVal := &dao.StoreDetail{
|
||||
Store: model.Store{
|
||||
Address: utils.Interface2String(result["address"]),
|
||||
Tel1: utils.Interface2String(result["phone"]),
|
||||
},
|
||||
}
|
||||
retVal.OriginalName = utils.Interface2String(result["name"])
|
||||
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreNameEbai)
|
||||
retVal.DeliveryType = EbaiDeliveryType2Jx(utils.Interface2String(result["delivery_type"]))
|
||||
|
||||
retVal.SetOpTime(ebaiOpTime2Jx(result["business_time"]))
|
||||
retVal.Status, _ = p.GetStoreStatus(ctx, vendorOrgCode, 0, vendorStoreID)
|
||||
|
||||
tel2 := utils.Interface2String(result["ivr_phone"])
|
||||
if tel2 != "" && tel2 != retVal.Tel1 {
|
||||
retVal.Tel2 = tel2
|
||||
}
|
||||
|
||||
lng := getCoordintate(result["longitude"])
|
||||
lat := getCoordintate(result["latitude"])
|
||||
if utils.Interface2String(result["coord_type"]) == ebaiapi.CoordTypeBaidu {
|
||||
var err2 error
|
||||
if lng, lat, err2 = api.AutonaviAPI.CoordinateConvert(lng, lat, autonavi.CoordSysBaidu); err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
}
|
||||
retVal.Lng = jxutils.StandardCoordinate2Int(lng)
|
||||
retVal.Lat = jxutils.StandardCoordinate2Int(lat)
|
||||
|
||||
db := dao.GetDB()
|
||||
if city, err2 := dao.GetPlaceByName(db, utils.Interface2String(result["city"]), model.PlaceLevelCity, 0); err2 == nil {
|
||||
retVal.CityCode = city.Code
|
||||
retVal.CityName = utils.Interface2String(result["city"])
|
||||
districtName := utils.Interface2String(result["county"])
|
||||
if retVal.CityCode != 0 && districtName != "" {
|
||||
if district, err2 := dao.GetPlaceByName(db, utils.Interface2String(result["county"]), model.PlaceLevelDistrict, city.Code); err2 == nil {
|
||||
retVal.DistrictCode = district.Code
|
||||
}
|
||||
}
|
||||
}
|
||||
if retVal.DistrictCode == 0 {
|
||||
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
|
||||
if retVal.CityCode == 0 {
|
||||
if district, err := dao.GetPlaceByCode(db, retVal.DistrictCode); err == nil {
|
||||
retVal.CityCode = district.ParentCode
|
||||
}
|
||||
}
|
||||
}
|
||||
retVal.VendorStoreID = vendorStoreID
|
||||
retVal.ID = int(utils.Str2Int64WithDefault(utils.Interface2String(result["shop_id"]), 0))
|
||||
retVal.DeliveryRangeType = model.DeliveryRangeTypePolygon
|
||||
retVal.DeliveryRange = EbaiDeliveryRegion2Jx(result["delivery_region"])
|
||||
|
||||
return retVal, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("ebai UpdateStore storeID:%d, userName:%s", storeID, userName)
|
||||
|
||||
var stores []*tEbaiStoreInfo
|
||||
sql := `
|
||||
SELECT
|
||||
t1.*,
|
||||
t2.status ebai_store_status, t2.vendor_store_id, t2.vendor_org_code,
|
||||
IF(t1.updated_at > t2.updated_at, t1.last_operator, t2.last_operator) real_last_operator, t2.sync_status, t2.vendor_store_name
|
||||
FROM store t1
|
||||
JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND (t2.deleted_at = ?)
|
||||
WHERE t1.id = ?
|
||||
ORDER BY t2.updated_at
|
||||
`
|
||||
if err = dao.GetRows(db, &stores, sql, model.VendorIDEBAI, utils.DefaultTimeValue, storeID); err == nil {
|
||||
for _, store := range stores {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
shopID := 0
|
||||
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
|
||||
shopID = store.ID
|
||||
}
|
||||
store2, err2 := p.ReadStore(jxcontext.AdminCtx, store.VendorOrgCode, store.VendorStoreID)
|
||||
// globals.SugarLogger.Debugf("ebai UpdateStore2 store2:%s, err2:%v", utils.Format4Output(store2, true), err2)
|
||||
if err = err2; err == nil {
|
||||
if store2.ID == store.ID {
|
||||
shopID = -1
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if shopID > 0 {
|
||||
err = p.UpdateStoreCustomID(jxcontext.AdminCtx, "", store.VendorStoreID, int64(shopID))
|
||||
} else if shopID == 0 {
|
||||
// todo remove out shop id
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
|
||||
mergeStatus := jxutils.MergeStoreStatus(store.Status, store.EbaiStoreStatus)
|
||||
if err = p.UpdateStoreStatus(jxcontext.AdminCtx, store.VendorOrgCode, storeID, store.VendorStoreID, mergeStatus); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
params := genStoreMapFromStore(store)
|
||||
if err = api.EbaiAPI.ShopUpdate(params); err == nil {
|
||||
if store.PromoteInfo != "" {
|
||||
err = api.EbaiAPI.ShopAnnouncementSet("", utils.Str2Int64(store.VendorStoreID), store.PromoteInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isStoreStatusSame(status1, status2 int) bool {
|
||||
if status1 == model.StoreStatusHaveRest {
|
||||
status1 = model.StoreStatusClosed
|
||||
}
|
||||
if status2 == model.StoreStatusHaveRest {
|
||||
status2 = model.StoreStatusClosed
|
||||
}
|
||||
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
|
||||
const stepCount = 3
|
||||
var stores []*tEbaiStoreInfo
|
||||
db := dao.GetDB()
|
||||
rootTask := tasksch.NewSeqTask("ebai RefreshAllStoresID", ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
err = dao.GetRows(db, &stores, `
|
||||
SELECT t1.*, t2.vendor_store_id
|
||||
FROM store t1
|
||||
JOIN store_map t2 ON t1.id = t2.store_id AND t2.deleted_at = ? AND t2.vendor_id = ?
|
||||
WHERE t1.deleted_at = ?
|
||||
`, utils.DefaultTimeValue, model.VendorIDEBAI, utils.DefaultTimeValue)
|
||||
default:
|
||||
taskName := "ebai RefreshAllStoresID update to custom id"
|
||||
if step != stepCount-1 {
|
||||
taskName = "ebai RefreshAllStoresID update to uuid"
|
||||
}
|
||||
task1 := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetBatchSize(batchSize), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
baiduShopIDs := make([]string, len(batchItemList))
|
||||
shopIDs := make([]string, len(batchItemList))
|
||||
for k, v := range batchItemList {
|
||||
store := v.(*tEbaiStoreInfo)
|
||||
baiduShopIDs[k] = store.VendorStoreID
|
||||
shopIDs[k] = utils.Int2Str(store.ID)
|
||||
if step != stepCount-1 {
|
||||
shopIDs[k] = utils.GetUUID()
|
||||
}
|
||||
}
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopIDBatchUpdate(baiduShopIDs, shopIDs)
|
||||
}
|
||||
return nil, err
|
||||
}, stores)
|
||||
task.AddChild(task1).Run()
|
||||
_, err = task1.GetResult(0)
|
||||
}
|
||||
return nil, err
|
||||
}, stepCount)
|
||||
|
||||
tasksch.HandleTask(rootTask, parentTask, false).Run()
|
||||
if !isAsync {
|
||||
_, err = rootTask.GetResult(0)
|
||||
}
|
||||
return rootTask.ID, err
|
||||
}
|
||||
|
||||
// todo 此函数只考虑了在饿了么侧开店的情况
|
||||
func EbaiDeliveryType2Jx(deliveryType string) int8 {
|
||||
spIndex := strings.Index(deliveryType, "|")
|
||||
elmDeliveryType := utils.Str2Int64(deliveryType[:spIndex])
|
||||
switch elmDeliveryType {
|
||||
case ebaiapi.DeliveryTypeElmFengNiaoZS,
|
||||
ebaiapi.DeliveryTypeElmFengNiaoZSKA,
|
||||
ebaiapi.DeliveryTypeElmFengNiaoKS,
|
||||
ebaiapi.DeliveryTypeElmNewRetail,
|
||||
ebaiapi.DeliveryTypeElmEPeiSong,
|
||||
ebaiapi.DeliveryTypeElmFengNiaoHybrid,
|
||||
ebaiapi.DeliveryTypeElmFengNiaoNiubee:
|
||||
return scheduler.StoreDeliveryTypeByPlatform
|
||||
case ebaiapi.DeliveryTypeElmXingHuoZBTrial,
|
||||
ebaiapi.DeliveryTypeElmXingHuoZB,
|
||||
ebaiapi.DeliveryTypeElmXingHuoZBKA:
|
||||
return scheduler.StoreDeliveryTypeCrowdSourcing
|
||||
case ebaiapi.DeliveryTypeElmNone,
|
||||
ebaiapi.DeliveryTypeElmXingHuoTrial,
|
||||
ebaiapi.DeliveryTypeElmXingHuo,
|
||||
ebaiapi.DeliveryTypeElmEBase,
|
||||
ebaiapi.DeliveryTypeElmXingHuoKA:
|
||||
return scheduler.StoreDeliveryTypeByStore
|
||||
default:
|
||||
return scheduler.StoreDeliveryTypeCrowdSourcing
|
||||
}
|
||||
}
|
||||
|
||||
func EbaiDeliveryRegion2Jx(deliveryRegion interface{}) string {
|
||||
realDeliveryRegion := deliveryRegion.([]interface{})
|
||||
if len(realDeliveryRegion) > 0 {
|
||||
region := deliveryRegion.([]interface{})[0].(map[string]interface{})["region"].([]interface{})[0].([]interface{})
|
||||
coords := make([]string, len(region))
|
||||
for k, v := range region {
|
||||
mapV := v.(map[string]interface{})
|
||||
coords[k] = fmt.Sprintf("%.6f,%.6f", utils.MustInterface2Float64(mapV["longitude"]), utils.MustInterface2Float64(mapV["latitude"]))
|
||||
}
|
||||
return strings.Join(coords, ";")
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func JxDeliveryRegion2Ebai(store *model.Store) (deliveryRegion interface{}) {
|
||||
rangeStr := strings.Trim(store.DeliveryRange, ";")
|
||||
if store.DeliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
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 = ""
|
||||
}
|
||||
}
|
||||
rangeStr = "" // todo 暂时禁止同步配送区域
|
||||
if rangeStr != "" {
|
||||
pointPairs := strings.Split(rangeStr, ";")
|
||||
region := make([]map[string]interface{}, 0)
|
||||
for _, v := range pointPairs {
|
||||
pointPair := strings.Split(v, ",")
|
||||
if len(pointPair) == 2 {
|
||||
region = append(region, map[string]interface{}{
|
||||
"longitude": utils.Str2Float64(pointPair[0]),
|
||||
"latitude": utils.Str2Float64(pointPair[1]),
|
||||
})
|
||||
}
|
||||
}
|
||||
deliveryRegion = []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "主要配送区",
|
||||
"delivery_fee": 600,
|
||||
"delivery_time": "60",
|
||||
"min_buy_free": "0",
|
||||
"min_order_price": "0",
|
||||
"region": []interface{}{
|
||||
region,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
return deliveryRegion
|
||||
}
|
||||
|
||||
func fillOpTimeParams(params map[string]interface{}, opTimeList []int16) map[string]interface{} {
|
||||
if params == nil {
|
||||
params = make(map[string]interface{})
|
||||
}
|
||||
var pairList []map[string]string
|
||||
opTimeListLen := len(opTimeList)
|
||||
if opTimeListLen > 4 {
|
||||
opTimeListLen = 4
|
||||
}
|
||||
opTimeListLen = opTimeListLen / 2 * 2
|
||||
for k := 0; k < len(opTimeList); k += 2 {
|
||||
if opTimeList[k] != 0 {
|
||||
pairList = append(pairList, map[string]string{
|
||||
"start": jxutils.JxOperationTime2StrTime(opTimeList[k]),
|
||||
"end": jxutils.JxOperationTime2StrTime(opTimeList[k+1]),
|
||||
})
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
params["business_time"] = pairList
|
||||
return params
|
||||
}
|
||||
|
||||
func ebaiOpTime2Jx(businessTime interface{}) (opTimeList []int16) {
|
||||
businessTimeList, _ := businessTime.([]interface{})
|
||||
for _, v := range businessTimeList {
|
||||
vMap := v.(map[string]interface{})
|
||||
opTimeList = append(opTimeList, jxutils.StrTime2JxOperationTime(utils.Interface2String(vMap["start"])+":00", 700),
|
||||
jxutils.StrTime2JxOperationTime(utils.Interface2String(vMap["end"])+":00", 2000))
|
||||
}
|
||||
return opTimeList
|
||||
}
|
||||
|
||||
func genStoreMapFromStore(store *tEbaiStoreInfo) map[string]interface{} {
|
||||
params := fillOpTimeParams(nil, store.GetOpTimeList())
|
||||
// tel := store.Tel1
|
||||
// if tel == "" {
|
||||
// tel = store.Tel2
|
||||
// }
|
||||
// if tel != "" {
|
||||
// // params["phone"] = tel // 外卖客服联系电话,这个有时能修改,有时不能修改,暂时统一不改
|
||||
// params["ivr_phone"] = tel // 订单提醒电话
|
||||
// }
|
||||
phone := ""
|
||||
if store.MarketManPhone != "" {
|
||||
phone = store.MarketManPhone
|
||||
} else {
|
||||
phone = model.VendorStoreTel
|
||||
}
|
||||
params["ivr_phone"] = phone //统一改为这个电话
|
||||
|
||||
if store.VendorStoreID != "" {
|
||||
params["baidu_shop_id"] = store.VendorStoreID
|
||||
}
|
||||
if false { //store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
|
||||
if store.VendorStoreName != "" {
|
||||
params["name"] = store.VendorStoreName
|
||||
} else {
|
||||
params["name"] = jxutils.ComposeStoreName(store.Name, model.VendorIDEBAI)
|
||||
}
|
||||
}
|
||||
boxFee, _ := dao.GetSysConfigAsInt64(dao.GetDB(), model.ConfigSysEbaiBoxFee)
|
||||
params["package_box_price"] = jxutils.IntPrice2Standard(boxFee)
|
||||
params["service_phone"] = store.Tel1
|
||||
params["address"] = store.Address
|
||||
// todo 饿百 开店审核通过后不允许修改商户信息
|
||||
if store.SyncStatus&(model.SyncFlagNewMask /*|model.SyncFlagStoreAddress*/) != 0 {
|
||||
// todo 这里应该要做坐标转换吧
|
||||
params["longitude"] = jxutils.IntCoordinate2Standard(store.Lng)
|
||||
params["latitude"] = jxutils.IntCoordinate2Standard(store.Lat)
|
||||
params["coord_type"] = ebaiapi.CoordTypeAutonavi
|
||||
// if deliveryRegion := JxDeliveryRegion2Ebai(&store.Store); deliveryRegion != nil {
|
||||
// params["delivery_region"] = deliveryRegion
|
||||
// }
|
||||
if store.ProvinceID != 0 {
|
||||
params["province"] = store.ProvinceID
|
||||
}
|
||||
if store.CityID != 0 {
|
||||
params["city"] = store.CityID
|
||||
}
|
||||
if store.DistrictID != 0 {
|
||||
params["county"] = store.DistrictID
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
|
||||
ebaiStatus, err := api.EbaiAPI.ShopBusStatusGet("", utils.Str2Int64(vendorStoreID), ebaiapi.PlatformFlagElm)
|
||||
if err == nil {
|
||||
storeStatus = EbaiBusStatus2JxStatus(ebaiStatus)
|
||||
}
|
||||
return storeStatus, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onShopMsgPush(msg *ebaiapi.CallbackMsg) (response *ebaiapi.CallbackResponse) {
|
||||
var err error
|
||||
vendorStoreID := utils.Interface2String(msg.Body["baidu_shop_id"])
|
||||
storeID := int(utils.Interface2Int64WithDefault(msg.Body["shop_id"], 0))
|
||||
storeStatus := model.StoreStatusOpened
|
||||
switch utils.Interface2String(msg.Body["msg_type"]) {
|
||||
case "online", "offline":
|
||||
storeStatus, err = c.GetStoreStatus(jxcontext.AdminCtx, "", storeID, vendorStoreID)
|
||||
case "shop_open", "shop_pause", "shop_close":
|
||||
if int(utils.ForceInterface2Int64(msg.Body["business_ele"])) == 1 {
|
||||
storeStatus = model.StoreStatusOpened
|
||||
} else {
|
||||
storeStatus = model.StoreStatusClosed
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDEBAI, storeStatus)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if status == model.StoreStatusOpened {
|
||||
err = api.EbaiAPI.ShopOpen("", utils.Str2Int64(vendorStoreID))
|
||||
} else if status == model.StoreStatusHaveRest || status == model.StoreStatusClosed {
|
||||
err = api.EbaiAPI.ShopClose("", utils.Str2Int64(vendorStoreID))
|
||||
} else if status == model.StoreStatusDisabled {
|
||||
err = api.EbaiAPI.ShopClose("", utils.Str2Int64(vendorStoreID))
|
||||
// err = api.EbaiAPI.ShopOffline("", utils.Str2Int64(vendorStoreID))
|
||||
}
|
||||
if err != nil {
|
||||
if remoteStatus, err2 := c.GetStoreStatus(ctx, vendorOrgCode, storeID, vendorStoreID); err2 == nil && remoteStatus == status {
|
||||
err = nil
|
||||
} else if intErr, ok := err.(*utils.ErrorWithCode); ok && intErr.IntCode() == 201100 || intErr.IntCode() == 201101 { // 兼容假错误:商户开业饿了么侧成功
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
|
||||
params := map[string]interface{}{
|
||||
ebaiapi.KeyBaiduShopID: vendorStoreID,
|
||||
}
|
||||
fillOpTimeParams(params, opTimeList)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
api.EbaiAPI.ShopUpdate(params)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
|
||||
shopList, err := api.EbaiAPI.ShopList(ebaiapi.SysStatusAll)
|
||||
if err == nil && len(shopList) > 0 {
|
||||
vendorStoreIDs = make([]string, len(shopList))
|
||||
for k, v := range shopList {
|
||||
vendorStoreIDs[k] = utils.Int64ToStr(v.BaiduShopID)
|
||||
}
|
||||
}
|
||||
return vendorStoreIDs, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode string, vendorStoreID string, storeID int64) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = api.EbaiAPI.ShopIDBatchUpdate([]string{vendorStoreID}, []string{utils.Int64ToStr(storeID)})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetShopListByPage(status, proxy_business_state int) (shopList []*ebaiapi.ShopList, err error) {
|
||||
var (
|
||||
pageCount = 500
|
||||
pageNum = 1
|
||||
)
|
||||
for {
|
||||
shopListPage, _, err2 := api.EbaiAPI.GetShopListByPage(status, proxy_business_state, pageCount, pageNum)
|
||||
err = err2
|
||||
shopList = append(shopList, shopListPage...)
|
||||
if len(shopList) < pageCount {
|
||||
break
|
||||
}
|
||||
pageNum++
|
||||
}
|
||||
return shopList, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetShopIDsByPage() (vendorStoreIDs []string, err error) {
|
||||
shopList, err := c.GetShopListByPage(ebaiapi.ShopStatusOnLine, ebaiapi.ProxyBusinessState)
|
||||
for _, v := range shopList {
|
||||
vendorStoreIDs = append(vendorStoreIDs, v.Wid)
|
||||
}
|
||||
return vendorStoreIDs, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
|
||||
return vendorStoreID, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,596 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
defVendorCatID = 201222934 // 其他蔬菜
|
||||
)
|
||||
|
||||
var (
|
||||
sensitiveWordRegexp = regexp.MustCompile(`商品名称中含有敏感词(\[.*\])`)
|
||||
categoryCheck = map[int]string{
|
||||
175: "赠品专区",
|
||||
18: "烧烤吧台",
|
||||
}
|
||||
|
||||
//果园果切的饿百分类ID
|
||||
gygqVendorCatID = map[int]int{
|
||||
201227732: 1,
|
||||
201220933: 1,
|
||||
201223525: 1,
|
||||
201220334: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
|
||||
switch funcID {
|
||||
case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice, partner.FuncDeleteStoreSkus:
|
||||
batchSize = ebaiapi.MaxStoreSkuBatchSize
|
||||
case partner.FuncCreateStoreSkus, partner.FuncUpdateStoreSkus:
|
||||
batchSize = 1
|
||||
case partner.FuncGetStoreSkusFullInfo:
|
||||
batchSize = 1
|
||||
case partner.FuncCreateActs, partner.FuncCancelActs:
|
||||
batchSize = 1
|
||||
}
|
||||
return batchSize
|
||||
}
|
||||
|
||||
// 门店分类
|
||||
func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
|
||||
remoteCats, err := api.EbaiAPI.ShopCategoryGet(utils.Int2Str(storeID))
|
||||
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) IsErrCategoryExist(err error) (isExist bool) {
|
||||
return ebaiapi.IsErrCategoryExist(err)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
|
||||
return ebaiapi.IsErrCategoryNotExist(err)
|
||||
}
|
||||
|
||||
func getCheckExdStoreNameAndSeq(storeID int, storeCat *dao.SkuStoreCatInfo) (name string, seq int, isCheck bool) {
|
||||
store, err := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDEBAI)
|
||||
if err != nil || store == nil {
|
||||
return storeCat.Name, storeCat.Seq, false
|
||||
}
|
||||
if strings.Contains(store.Name, model.ExdStoreName) {
|
||||
if categoryCheck[storeCat.ID] != "" {
|
||||
return storeCat.ExdName, storeCat.ExdSeq, true
|
||||
} else {
|
||||
return storeCat.ExdName, storeCat.ExdSeq, false
|
||||
}
|
||||
} else {
|
||||
return storeCat.Name, storeCat.Seq, false
|
||||
}
|
||||
return name, seq, false
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||||
var vendorCatID int64
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if catName, catSeq, isCheck := getCheckExdStoreNameAndSeq(storeID, storeCat); !isCheck {
|
||||
vendorCatID, err = api.EbaiAPI.ShopCategoryCreate(utils.Int2Str(storeID), utils.Str2Int64WithDefault(storeCat.ParentVendorCatID, 0), formatCatName(catName), jxCatSeq2Ebai(catSeq))
|
||||
}
|
||||
} else {
|
||||
vendorCatID = jxutils.GenFakeID()
|
||||
}
|
||||
storeCat.VendorCatID = utils.Int64ToStr(vendorCatID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if catName, catSeq, isCheck := getCheckExdStoreNameAndSeq(storeID, storeCat); !isCheck {
|
||||
err = api.EbaiAPI.ShopCategoryUpdate(utils.Int2Str(storeID), utils.Str2Int64WithDefault(storeCat.VendorCatID, 0), formatCatName(catName), jxCatSeq2Ebai(catSeq))
|
||||
}
|
||||
// todo, 饿百将一个分类重复改名,也会报分类名重复错,特殊处理一下,不过因为GetStoreCategory其实会拉取所有的门店分类,是比较耗时的操作
|
||||
if utils.IsErrMatch(err, "1", []string{"分类名称已经存在"}) {
|
||||
if cat, err2 := p.GetStoreCategory(ctx, storeID, vendorStoreID, storeCat.Name); err2 == nil {
|
||||
if cat.VendorCatID == storeCat.VendorCatID {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
err = api.EbaiAPI.ShopCategoryDelete(utils.Int2Str(storeID), utils.Str2Int64WithDefault(vendorCatID, 0))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 门店商品
|
||||
|
||||
// 多门店平台不需要实现这个接口
|
||||
|
||||
func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
|
||||
return ebaiapi.IsErrSkuExist(err)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
|
||||
return ebaiapi.IsErrSkuNotExist(err)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) updateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo, isNeedMapCat bool) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
storeSku := storeSkuList[0]
|
||||
strStoreID := utils.Int2Str(storeID)
|
||||
isExd := false
|
||||
if strings.Contains(storeSku.StoreName, model.ExdStoreName) {
|
||||
isExd = true
|
||||
}
|
||||
params := genSkuParamsFromStoreSkuInfo2(storeSku, false, isExd)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
_, err = api.EbaiAPI.SkuUpdate(ctx.GetTrackInfo(), strStoreID, utils.Str2Int64(storeSku.VendorSkuID), params)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品基础信息")
|
||||
}
|
||||
if isNeedMapCat && !isExd {
|
||||
utils.CallFuncAsync(func() {
|
||||
api.EbaiAPI.SkuShopCategoryMap(strStoreID, utils.Str2Int64(storeSku.VendorSkuID), "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku))
|
||||
})
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
return p.updateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, true)
|
||||
}
|
||||
|
||||
// 对于多门店平台来说,storeSkuList中只有SkuID与VendorSkuID有意义
|
||||
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
storeSku := storeSkuList[0]
|
||||
var (
|
||||
vendorSkuID int64
|
||||
isExd bool = false
|
||||
customSkuID int64
|
||||
)
|
||||
if strings.Contains(storeSku.StoreName, model.ExdStoreName) {
|
||||
isExd = true
|
||||
if storeSku.ExdSkuID == "" {
|
||||
customSkuID = 0
|
||||
} else {
|
||||
customSkuID = utils.Str2Int64(storeSku.ExdSkuID)
|
||||
}
|
||||
} else {
|
||||
isExd = false
|
||||
customSkuID = int64(storeSku.SkuID)
|
||||
}
|
||||
params := genSkuParamsFromStoreSkuInfo2(storeSku, true, isExd)
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
strStoreID := utils.Int2Str(storeID)
|
||||
if vendorSkuID, err = api.EbaiAPI.SkuCreate(ctx.GetTrackInfo(), strStoreID, customSkuID, params); err == nil && !isExd {
|
||||
utils.AfterFuncWithRecover(5*time.Second, func() {
|
||||
api.EbaiAPI.SkuShopCategoryMap(strStoreID, vendorSkuID, "", utils.Str2Int64(storeSku.VendorCatID), genSkuCatRank(storeSku))
|
||||
// 饿百平台有BUG,会导致新建一个之前删除的商品时,信息不会及时更新,强制刷新一下
|
||||
// 比如门店:100887, skuID:33805,订单:1577176719141226065
|
||||
p.updateStoreSkus(ctx, storeID, vendorStoreID, storeSkuList, false)
|
||||
})
|
||||
} else {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "创建商品")
|
||||
}
|
||||
} else {
|
||||
vendorSkuID = jxutils.GenFakeID()
|
||||
}
|
||||
err = nil
|
||||
storeSku.VendorSkuID = utils.Int64ToStr(vendorSkuID)
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func getFailedVendorSkuIDsFromOpResult(opResult *ebaiapi.BatchOpResult) (skuIDs []string) {
|
||||
if opResult != nil {
|
||||
for _, v := range opResult.FailedList {
|
||||
skuIDs = append(skuIDs, utils.Int64ToStr(v.SkuID))
|
||||
}
|
||||
}
|
||||
return skuIDs
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
opResult, err2 := api.EbaiAPI.SkuDelete(ctx.GetTrackInfo(), utils.Int2Str(storeID), partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDIntList(), nil)
|
||||
if err = err2; err2 != nil && opResult != nil {
|
||||
// if len(storeSkuList) > len(opResult.FailedList) {
|
||||
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "删除商品")
|
||||
// successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getFailedVendorSkuIDsFromOpResult(opResult))
|
||||
// }
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
vendorSkuIDs := partner.BareStoreSkuInfoList(storeSkuList).GetVendorSkuIDIntList()
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
var opResult *ebaiapi.BatchOpResult
|
||||
if status == model.SkuStatusNormal {
|
||||
if len(vendorSkuIDs) > 1 {
|
||||
opResult, err = api.EbaiAPI.SkuOnline(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs, nil, nil)
|
||||
} else if len(vendorSkuIDs) == 1 {
|
||||
err = api.EbaiAPI.SkuOnlineOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs[0], "", "")
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品状态")
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
} else {
|
||||
if len(vendorSkuIDs) > 1 {
|
||||
opResult, err = api.EbaiAPI.SkuOffline(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs, nil, nil)
|
||||
} else if len(vendorSkuIDs) == 1 {
|
||||
err = api.EbaiAPI.SkuOfflineOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), vendorSkuIDs[0], "", "")
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品状态")
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
}
|
||||
if err != nil && opResult != nil {
|
||||
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品状态")
|
||||
// failedList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getFailedVendorSkuIDsFromOpResult(opResult))
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func StoreSkuInfoList2Ebai(storeSkuList []*partner.StoreSkuInfo) (outList ebaiapi.ShopSkuInfoList) {
|
||||
outList = make(ebaiapi.ShopSkuInfoList, len(storeSkuList))
|
||||
for k, v := range storeSkuList {
|
||||
outList[k] = &ebaiapi.ShopSkuInfo{
|
||||
SkuID: utils.Str2Int64WithDefault(v.VendorSkuID, 0),
|
||||
// CustomSkuID: utils.Int2Str(v.SkuID),
|
||||
SalePrice: v.VendorPrice,
|
||||
Stock: v.Stock,
|
||||
}
|
||||
}
|
||||
return outList
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if len(storeSkuList) > 1 {
|
||||
opResult, err2 := api.EbaiAPI.SkuPriceUpdateBatch(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList), ebaiapi.SkuIDTypeSkuID)
|
||||
if err = err2; err != nil && opResult != nil {
|
||||
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品价格")
|
||||
}
|
||||
} else if len(storeSkuList) == 1 {
|
||||
_, err := api.EbaiAPI.SkuPriceUpdateOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList)[0])
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品价格")
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableEbaiStoreWrite {
|
||||
if len(storeSkuList) > 1 {
|
||||
opResult, err2 := api.EbaiAPI.SkuStockUpdateBatch(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList), ebaiapi.SkuIDTypeSkuID)
|
||||
if err = err2; err != nil && opResult != nil {
|
||||
failedList = SelectStoreSkuListByOpResult(storeSkuList, opResult, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品库存")
|
||||
// successList = putils.UnselectStoreSkuListByVendorSkuIDs(storeSkuList, getFailedVendorSkuIDsFromOpResult(opResult))
|
||||
}
|
||||
} else if len(storeSkuList) == 1 {
|
||||
err = api.EbaiAPI.SkuStockUpdateOne(ctx.GetTrackInfo(), utils.Int2Str(storeID), StoreSkuInfoList2Ebai(storeSkuList)[0])
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDEBAI], "更新商品库存")
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func genSkuParamsFromStoreSkuInfo2(storeSku *dao.StoreSkuSyncInfo, isCreate, isExd bool) (params map[string]interface{}) {
|
||||
var img string
|
||||
if storeSku.ImgMix != "" {
|
||||
img = storeSku.ImgMix
|
||||
} else {
|
||||
img = storeSku.Img
|
||||
}
|
||||
photos := []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"is_master": true,
|
||||
"url": img,
|
||||
},
|
||||
}
|
||||
if storeSku.Img2 != "" {
|
||||
photos = append(photos, map[string]interface{}{
|
||||
"is_master": false,
|
||||
"url": storeSku.Img2,
|
||||
})
|
||||
}
|
||||
if storeSku.Img3 != "" {
|
||||
photos = append(photos, map[string]interface{}{
|
||||
"is_master": false,
|
||||
"url": storeSku.Img3,
|
||||
})
|
||||
}
|
||||
params = map[string]interface{}{
|
||||
// "name": utils.LimitMixedStringLen(storeSku.SkuName, ebaiapi.MaxSkuNameByteCount),
|
||||
"left_num": model.MaxStoreSkuStockQty,
|
||||
// "category_id": utils.Str2Int64(storeSku.VendorCatID),
|
||||
"predict_cat": 0, // 不使用推荐类目
|
||||
// "cat3_id": getEbaiCat(storeSku.VendorVendorCatID),
|
||||
"weight": storeSku.Weight,
|
||||
"photos": photos,
|
||||
"preparation_time": storeSku.PreparationTime,
|
||||
}
|
||||
if !isExd {
|
||||
params["category_id"] = utils.Str2Int64(storeSku.VendorCatID)
|
||||
params["name"] = utils.LimitMixedStringLen(storeSku.SkuName, ebaiapi.MaxSkuNameByteCount)
|
||||
params["cat3_id"] = getEbaiCat(storeSku.VendorVendorCatID)
|
||||
} else {
|
||||
params["upc"] = storeSku.Upc
|
||||
params["name"] = storeSku.Name
|
||||
params["cat3_id"] = storeSku.ExdCategoryThirdID
|
||||
params["category_id"] = utils.Str2Int64WithDefault(storeSku.VendorCatID, 0)
|
||||
}
|
||||
//证明是果园的几个果切分类,需要填加工服务
|
||||
if gygqVendorCatID[int(storeSku.VendorVendorCatID)] == 1 {
|
||||
params["process_type"] = model.YES
|
||||
processDetail := []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"type": "去皮",
|
||||
"time": 2,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"type": "不加工",
|
||||
"time": 0,
|
||||
},
|
||||
}
|
||||
params["process_detail"] = processDetail
|
||||
}
|
||||
if storeSku.DescImg != "" {
|
||||
params["rtf"] = storeSku.DescImg
|
||||
}
|
||||
if isCreate /*storeSku.SkuSyncStatus&(model.SyncFlagPriceMask| model.SyncFlagNewMask) != 0 */ {
|
||||
params["sale_price"] = storeSku.VendorPrice
|
||||
}
|
||||
if storeSku.SkuSyncStatus&(model.SyncFlagSaleMask|model.SyncFlagNewMask) != 0 {
|
||||
params["status"] = jxSkuStatus2Ebai(storeSku.MergedStatus)
|
||||
}
|
||||
// todo 饿百如果给的UPC是空要报错,但如果我要删除UPC怎么弄?
|
||||
// if storeSku.Upc != "" {
|
||||
// params["upc"] = storeSku.Upc
|
||||
// }
|
||||
return params
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func jxSkuStatus2Ebai(status int) int {
|
||||
if status <= 0 {
|
||||
return ebaiapi.SkuStatusOffline
|
||||
}
|
||||
return ebaiapi.SkuStatusOnline
|
||||
}
|
||||
|
||||
func getEbaiCat(catID int64) int64 {
|
||||
if catID == 0 {
|
||||
return defVendorCatID
|
||||
}
|
||||
return catID
|
||||
}
|
||||
|
||||
// 饿百的排序是从大到小
|
||||
func genSkuCatRank(storeSku *dao.StoreSkuSyncInfo) int {
|
||||
return int(ebaiapi.MaxSkuCatRank - storeSku.GetSeq())
|
||||
}
|
||||
|
||||
// 饿百的排序是从大到小
|
||||
func jxCatSeq2Ebai(seq int) int {
|
||||
return ebaiapi.MaxCatCatRank - seq
|
||||
}
|
||||
|
||||
func formatCatName(name string) string {
|
||||
return utils.LimitUTF8StringLen(name, ebaiapi.MaxCategoryNameLen)
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
|
||||
params := &ebaiapi.SkuListParams{
|
||||
PageSize: ebaiapi.MaxSkuListPageSize,
|
||||
}
|
||||
if len(storeSkuList) == 1 {
|
||||
if storeSkuList[0].SkuID > 0 {
|
||||
params.CustomSkuID = utils.Int2Str(storeSkuList[0].SkuID)
|
||||
}
|
||||
if storeSkuList[0].VendorSkuID != "" {
|
||||
params.SkuID = utils.Str2Int64WithDefault(storeSkuList[0].VendorSkuID, 0)
|
||||
}
|
||||
}
|
||||
page1, err := api.EbaiAPI.SkuList(utils.Int2Str(storeID), params)
|
||||
if err == nil {
|
||||
skuNameList = append(skuNameList, vendorSkuList2Jx(page1.List)...)
|
||||
if page1.Pages > 1 {
|
||||
pages := make([]int, page1.Pages-1)
|
||||
for i := 2; i <= page1.Pages; i++ {
|
||||
pages[i-2] = i
|
||||
}
|
||||
task := tasksch.NewParallelTask("ebai GetStoreSkusFullInfo", nil, ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
callParams := &ebaiapi.SkuListParams{
|
||||
PageSize: ebaiapi.MaxSkuListPageSize,
|
||||
Page: batchItemList[0].(int),
|
||||
}
|
||||
pageSku, err2 := api.EbaiAPI.SkuList(utils.Int2Str(storeID), callParams)
|
||||
if err2 == nil {
|
||||
return pageSku.List, err2
|
||||
}
|
||||
return nil, err2
|
||||
}, pages)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
result, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
for _, v := range result {
|
||||
skuNameList = append(skuNameList, vendorSku2Jx(v.(*ebaiapi.SkuInfo)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return skuNameList, err
|
||||
}
|
||||
|
||||
func vendorSku2Jx(vendorSku *ebaiapi.SkuInfo) (skuName *partner.SkuNameInfo) {
|
||||
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(vendorSku.Name)
|
||||
weight := vendorSku.Weight
|
||||
if weight <= 0 {
|
||||
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
|
||||
}
|
||||
skuID := int(utils.Str2Int64WithDefault(vendorSku.CustomSkuID, 0))
|
||||
vendorSkuID := utils.Int64ToStr(vendorSku.SkuID)
|
||||
skuName = &partner.SkuNameInfo{
|
||||
NameID: skuID,
|
||||
VendorNameID: vendorSkuID,
|
||||
|
||||
Prefix: prefix,
|
||||
Name: name,
|
||||
Unit: unit,
|
||||
SkuList: []*partner.SkuInfo{
|
||||
&partner.SkuInfo{
|
||||
StoreSkuInfo: partner.StoreSkuInfo{
|
||||
VendorSkuID: vendorSkuID,
|
||||
SkuID: skuID,
|
||||
|
||||
Stock: vendorSku.LeftNum,
|
||||
VendorPrice: vendorSku.SalePrice,
|
||||
Status: ebaiSkuStatus2Jx(vendorSku.Status),
|
||||
},
|
||||
SkuName: vendorSku.Name,
|
||||
Comment: comment,
|
||||
SpecQuality: float64(specQuality),
|
||||
SpecUnit: specUnit,
|
||||
Weight: weight,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, v := range vendorSku.Photos {
|
||||
skuName.PictureList = append(skuName.PictureList, v.URL)
|
||||
}
|
||||
// todo, 看起来饿百只返回了最低一级的商家分类信息
|
||||
for _, v := range vendorSku.CustomCatList {
|
||||
skuName.VendorCatIDList = append(skuName.VendorCatIDList, v.CustomCatID)
|
||||
}
|
||||
return skuName
|
||||
}
|
||||
|
||||
func vendorSkuList2Jx(vendorSkuList []*ebaiapi.SkuInfo) (skuNameList []*partner.SkuNameInfo) {
|
||||
for _, vendorSku := range vendorSkuList {
|
||||
skuNameList = append(skuNameList, vendorSku2Jx(vendorSku))
|
||||
}
|
||||
return skuNameList
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
|
||||
return sensitiveWordRegexp
|
||||
}
|
||||
|
||||
//饿百api返回
|
||||
func SelectStoreSkuListByOpResult(storeSkuList []*partner.StoreSkuInfo, opResult *ebaiapi.BatchOpResult, storeID int, vendorName string, syncType string) (selectedStoreSkuList []*partner.StoreSkuInfoWithErr) {
|
||||
opResultMap := make(map[int64]string)
|
||||
if len(opResult.FailedList) > 0 {
|
||||
for _, v := range opResult.FailedList {
|
||||
if !(syncType == "删除商品" && ebaiapi.IsMsgSkuNotExist(v.ErrorMsg)) {
|
||||
opResultMap[v.SkuID] = v.ErrorMsg
|
||||
}
|
||||
}
|
||||
for _, v := range storeSkuList {
|
||||
if opResultMap[utils.Str2Int64(v.VendorSkuID)] != "" {
|
||||
opFailed := &partner.StoreSkuInfoWithErr{
|
||||
StoreSkuInfo: v,
|
||||
ErrMsg: opResultMap[utils.Str2Int64(v.VendorSkuID)],
|
||||
StoreID: storeID,
|
||||
VendoreName: vendorName,
|
||||
SyncType: syncType,
|
||||
}
|
||||
selectedStoreSkuList = append(selectedStoreSkuList, opFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
return selectedStoreSkuList
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
for _, v := range storeSkuList {
|
||||
if vendorActID, err2 := createOneShopAct(putils.GetFixDirectDownAct(vendorOrgCode, storeID, v.SkuID), utils.Int2Str(storeID), putils.StoreSku2ActStoreSku(model.SyncFlagNewMask, vendorStoreID, []*partner.StoreSkuInfo{v})); err2 != nil {
|
||||
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
|
||||
StoreSkuInfo: v,
|
||||
VendoreID: model.VendorIDEBAI,
|
||||
StoreID: storeID,
|
||||
ErrMsg: err2.Error(),
|
||||
})
|
||||
} else {
|
||||
v.VendorActID = vendorActID
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
for _, v := range storeSkuList {
|
||||
if err2 := ActivityDisable(utils.Str2Int64(v.VendorActID), utils.Int2Str(storeID), 0, 0); err2 != nil {
|
||||
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
|
||||
StoreSkuInfo: v,
|
||||
VendoreID: model.VendorIDJD,
|
||||
StoreID: storeID,
|
||||
ErrMsg: err2.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func TestGetStoreSkusFullInfo(t *testing.T) {
|
||||
skuNameList, err := CurPurchaseHandler.GetStoreSkusFullInfo(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, []*partner.StoreSkuInfo{
|
||||
&partner.StoreSkuInfo{
|
||||
SkuID: 4256,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(skuNameList, false))
|
||||
t.Log(len(skuNameList))
|
||||
}
|
||||
|
||||
func TestGetStoreSkusBareInfo(t *testing.T) {
|
||||
storeSkuList, err := CurPurchaseHandler.GetStoreSkusBareInfo(jxcontext.AdminCtx, "", nil, testShopID, testShopBaiduID, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(storeSkuList, false))
|
||||
t.Log(len(storeSkuList))
|
||||
}
|
||||
|
||||
func TestDeleteStoreAllSkus(t *testing.T) {
|
||||
err := CurPurchaseHandler.DeleteStoreAllSkus(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteStoreAllCategories(t *testing.T) {
|
||||
err := CurPurchaseHandler.DeleteStoreAllCategories(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
// func TestSyncStoresSkus(t *testing.T) {
|
||||
// skus := make([]int, 100)
|
||||
// for i := 0; i < 100; i++ {
|
||||
// skus[i] = i + 1
|
||||
// }
|
||||
// _, err := CurPurchaseHandler.SyncStoreSkus(jxcontext.AdminCtx, nil, testShopID, skus, false, false)
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
// time.Sleep(4 * time.Second)
|
||||
// }
|
||||
|
||||
// func TestSyncOneStoreCategoriesFromRemote2Local(t *testing.T) {
|
||||
// db := dao.GetDB()
|
||||
// err := CurPurchaseHandler.SyncLocalStoreCategory(db, testShopID, "autotest")
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestSyncOneStoreCategoriesFromLocal2Remote(t *testing.T) {
|
||||
// _, err := CurPurchaseHandler.SyncStoreCategory(jxcontext.AdminCtx, nil, testShopID, false)
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestGetAllRemoteSkus(t *testing.T) {
|
||||
result, err := CurPurchaseHandler.GetStoreSkusFullInfo(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
} else {
|
||||
t.Log(len(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRemoteSkus(t *testing.T) {
|
||||
err := CurPurchaseHandler.DeleteStoreAllSkus(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteRemoteCategories(t *testing.T) {
|
||||
err := new(PurchaseHandler).DeleteStoreAllCategories(jxcontext.AdminCtx, nil, testShopID, testShopBaiduID, true)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
func TestReadStore(t *testing.T) {
|
||||
result, err := CurPurchaseHandler.ReadStore(jxcontext.AdminCtx, "", testShopBaiduID)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestUpdateStore(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
err := CurPurchaseHandler.UpdateStore(db, testShopID, "autotest")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateStore(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
_, err := CurPurchaseHandler.CreateStore(db, 1, "autotest")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package ebai
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"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"
|
||||
)
|
||||
|
||||
const (
|
||||
timeout4WaybillCancel = 10 * time.Minute // 饿百发送运单取消消息10分钟后,如果没有转自送,就要取消订单,且不再发送订单取消消息
|
||||
)
|
||||
|
||||
var (
|
||||
VendorWaybillStatus2StatusMap = map[string]int{
|
||||
ebaiapi.WaybillStatusNew: model.WaybillStatusUnknown,
|
||||
ebaiapi.WaybillStatusRequestDelivery: model.WaybillStatusUnknown,
|
||||
ebaiapi.WaybillStatusWait4Courier: model.WaybillStatusNew,
|
||||
ebaiapi.WaybillStatusCourierAccepted: model.WaybillStatusAccepted,
|
||||
ebaiapi.WaybillStatusCourierPickedup: model.WaybillStatusDelivering,
|
||||
ebaiapi.WaybillStatusDeliveryCancled: model.WaybillStatusCanceled,
|
||||
ebaiapi.WaybillStatusFinished: model.WaybillStatusDelivered,
|
||||
// ebaiapi.WaybillStatusExceptional: model.WaybillStatusCanceled, // 饿百的配送异常不应该当成取消来处理,比如:1568651453228834871
|
||||
ebaiapi.WaybillStatusSelfDelivery: model.WaybillStatusUnknown,
|
||||
ebaiapi.WaybillStatusDontDeliver: model.WaybillStatusCanceled,
|
||||
ebaiapi.WaybillStatusDeliveryRejected: model.WaybillStatusCanceled,
|
||||
ebaiapi.WaybillStatusCourierArrived: model.WaybillStatusCourierArrived,
|
||||
}
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) GetWaybillStatusFromVendorStatus(vendorStatus string) int {
|
||||
if status, ok := VendorWaybillStatus2StatusMap[vendorStatus]; ok {
|
||||
return status
|
||||
}
|
||||
return model.WaybillStatusUnknown
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onWaybillMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
globals.SugarLogger.Debugf("ebai onWaybillMsg orderID:%s", order.VendorOrderID)
|
||||
if order.Status == model.WaybillStatusNew || order.Status == model.WaybillStatusAccepted { // 饿百新运单事件要查询快递员信息,因为可能事件错序
|
||||
if result, err := api.EbaiAPI.OrderDeliveryGet(order.VendorOrderID); err != nil {
|
||||
globals.SugarLogger.Warnf("ebai onWaybillMsg orderID:%s OrderDeliveryGet failed with error:%v", order.VendorOrderID, err)
|
||||
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, order.VendorOrderID)
|
||||
} else {
|
||||
order.CourierName = utils.Interface2String(result["name"])
|
||||
order.CourierMobile = utils.Interface2String(result["phone"])
|
||||
}
|
||||
if order.Status == model.WaybillStatusNew {
|
||||
order2, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.WaybillVendorID)
|
||||
if order2.Status == model.OrderStatusWaitAccepted {
|
||||
order2.Status = model.OrderStatusNew
|
||||
scheduler.CurrentScheduler.OnOrderNew(order2, false)
|
||||
}
|
||||
}
|
||||
} else if order.Status == model.WaybillStatusCanceled {
|
||||
utils.AfterFuncWithRecover(timeout4WaybillCancel, func() {
|
||||
if localOrder, err2 := partner.CurOrderManager.LoadOrder(order.VendorOrderID, model.VendorIDEBAI); err2 == nil {
|
||||
if localOrder.Status < model.OrderStatusEndBegin {
|
||||
c.trySyncCancelStatus(order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackMsg2Waybill(msg *ebaiapi.CallbackMsg) (retVal *model.Waybill) {
|
||||
vendorStatus := utils.Int64ToStr(utils.MustInterface2Int64(msg.Body["status"]))
|
||||
orderID := GetOrderIDFromMsg(msg)
|
||||
retVal = &model.Waybill{
|
||||
VendorOrderID: orderID,
|
||||
OrderVendorID: model.VendorIDEBAI,
|
||||
VendorWaybillID: orderID,
|
||||
WaybillVendorID: model.VendorIDEBAI,
|
||||
Status: c.GetWaybillStatusFromVendorStatus(vendorStatus),
|
||||
VendorStatus: vendorStatus,
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
|
||||
VendorOrgCode: msg.Source,
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
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) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
||||
return nil
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/elmapi"
|
||||
"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/api"
|
||||
)
|
||||
|
||||
var (
|
||||
curPurchaseHandler *PurchaseHandler
|
||||
)
|
||||
|
||||
type PurchaseHandler struct {
|
||||
partner.BasePurchasePlatform
|
||||
}
|
||||
|
||||
func init() {
|
||||
if api.ElmAPI != nil {
|
||||
curPurchaseHandler = new(PurchaseHandler)
|
||||
// partner.RegisterPurchasePlatform(curPurchaseHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetVendorID() int {
|
||||
return model.VendorIDELM
|
||||
}
|
||||
|
||||
func OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) {
|
||||
if curPurchaseHandler != nil {
|
||||
retVal = curPurchaseHandler.OnCallbackMsg(msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) {
|
||||
if msg.Type == elmapi.MsgTypeOrderValid {
|
||||
innerMsg := make(map[string]interface{})
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg["msgType"] = msg.Type
|
||||
retVal = c.OnOrderNewMsg(innerMsg)
|
||||
}
|
||||
} else if msg.Type > elmapi.MsgTypeOrderValid && msg.Type < elmapi.MsgTypeUserApplyCancel {
|
||||
var innerMsg elmapi.CallbackOrderStatusMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
retVal = c.OnOrderStatusMsg(&innerMsg)
|
||||
}
|
||||
} else if msg.Type >= elmapi.MsgTypeUserApplyCancel && msg.Type < elmapi.MsgTypeUserUrgeOrder {
|
||||
var innerMsg elmapi.CallbackOrderCancelRefundMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
retVal = c.OnOrderCancelRefundMsg(&innerMsg)
|
||||
}
|
||||
} else if msg.Type == elmapi.MsgTypeUserUrgeOrder {
|
||||
var innerMsg elmapi.CallbackOrderUrgeMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderUserUrgeOrder(&innerMsg)
|
||||
}, jxutils.ComposeUniversalOrderID(innerMsg.OrderID, model.VendorIDELM))
|
||||
}
|
||||
} else if msg.Type >= elmapi.MsgTypeWaybillWait4DeliveryVendor && msg.Type <= elmapi.MsgTypeRejectedSystemError {
|
||||
var innerMsg elmapi.CallbackWaybillStatusMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
retVal = c.OnWaybillStatusMsg(&innerMsg)
|
||||
}
|
||||
} else {
|
||||
retVal = elmapi.SuccessResponse
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
|
||||
return imgHint, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
return nil, fmt.Errorf("平台%s不支持此操作", jxutils.GetVendorName(model.VendorIDELM))
|
||||
}
|
||||
@@ -1,334 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/elmapi"
|
||||
"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/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"
|
||||
)
|
||||
|
||||
const (
|
||||
acceptOrderDelay = 270 * time.Second
|
||||
fakePickedUp = "fakefinishedpickup"
|
||||
)
|
||||
|
||||
var (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
elmapi.OrderStatusUnprocessed: model.OrderStatusNew,
|
||||
elmapi.OrderStatusValid: model.OrderStatusAccepted,
|
||||
elmapi.OrderStatusPending: model.OrderStatusNew,
|
||||
// elmapi.OrderStatusRefunding: model.OrderStatusApplyRefund,
|
||||
elmapi.OrderStatusInvalid: model.OrderStatusCanceled,
|
||||
elmapi.OrderStatusSettled: model.OrderStatusFinished,
|
||||
}
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderStatusMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderNew(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg["orderId"].(string), model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderCancelRefundMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusMsg) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.OrderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.OrderID,
|
||||
RefVendorID: model.VendorIDELM,
|
||||
VendorStatus: c.stateAndType2Str(msg.State, msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) cancelRefundMsg2Status(msg *elmapi.CallbackOrderCancelRefundMsg) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.OrderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.OrderID,
|
||||
RefVendorID: model.VendorIDELM,
|
||||
VendorStatus: c.stateAndType2Str(msg.RefundStatus, msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
status := c.orderStatusMsg2Status(msg)
|
||||
switch msg.MsgType {
|
||||
case elmapi.MsgTypeOrderAccepted:
|
||||
status.Status = model.OrderStatusAccepted
|
||||
case elmapi.MsgTypeOrderCanceled, elmapi.MsgTypeOrderInvalid, elmapi.MsgTypeOrderForceInvalid:
|
||||
status.Status = model.OrderStatusCanceled
|
||||
case elmapi.MsgTypeOrderFinished:
|
||||
status.Status = model.OrderStatusFinished
|
||||
default:
|
||||
globals.SugarLogger.Warnf("onOrderStatusMsg elm msg:%v not handled", msg)
|
||||
return elmapi.SuccessResponse
|
||||
}
|
||||
err := partner.CurOrderManager.OnOrderStatusChanged("", status)
|
||||
|
||||
// 直接跳到拣货完成
|
||||
if msg.MsgType == elmapi.MsgTypeOrderAccepted {
|
||||
status.Status = model.OrderStatusFinishedPickup
|
||||
status.VendorStatus = fakePickedUp
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged("", status)
|
||||
}
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyElmOrderStatusChanged(status)
|
||||
// }
|
||||
return elmapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
|
||||
status := c.cancelRefundMsg2Status(msg)
|
||||
switch msg.MsgType {
|
||||
case elmapi.MsgTypeUserApplyCancel:
|
||||
status.Status = model.OrderStatusApplyCancel
|
||||
case elmapi.MsgTypeUserApplyRefund:
|
||||
// status.Status = model.OrderStatusApplyRefund
|
||||
default:
|
||||
status.Status = model.OrderStatusUnknown
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged("", status), status.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) {
|
||||
result, err := api.ElmAPI.GetOrder(orderID)
|
||||
if err == nil {
|
||||
order = c.Map2Order(result)
|
||||
}
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
result := orderData
|
||||
orderID := result["id"].(string)
|
||||
phoneList := result["phoneList"].([]interface{})
|
||||
consigneeMobile := ""
|
||||
if len(phoneList) > 0 {
|
||||
consigneeMobile = utils.Interface2String(phoneList[0])
|
||||
}
|
||||
|
||||
// globals.SugarLogger.Debug(result)
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["shopId"])),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["openId"]), 0)),
|
||||
StoreName: result["shopName"].(string),
|
||||
ConsigneeName: result["consignee"].(string),
|
||||
ConsigneeMobile: jxutils.FormalizeMobile(consigneeMobile),
|
||||
ConsigneeAddress: result["address"].(string),
|
||||
BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["description"])),
|
||||
ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["deliverTime"]), utils.DefaultTimeValue),
|
||||
PickDeadline: utils.DefaultTimeValue,
|
||||
VendorStatus: utils.Interface2String(result["status"]), // 取订单的原始status,不合并消息类型(因为当前消息类型没有意义)
|
||||
OrderSeq: int(utils.MustInterface2Int64(result["daySn"])),
|
||||
StatusTime: utils.Str2Time(result["activeAt"].(string)),
|
||||
OriginalData: string(utils.MustMarshal(result)),
|
||||
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["totalPrice"])),
|
||||
Skus: []*model.OrderSku{},
|
||||
}
|
||||
order.Status = c.getStatusFromVendorStatus(order.VendorStatus)
|
||||
if result["book"].(bool) {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
} else {
|
||||
order.BusinessType = model.BusinessTypeImmediate
|
||||
}
|
||||
deliveryGeo := strings.Split(utils.Interface2String(result["deliveryGeo"]), ",")
|
||||
if len(deliveryGeo) == 2 {
|
||||
order.CoordinateType = model.CoordinateTypeMars
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(deliveryGeo[0]))
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(deliveryGeo[1]))
|
||||
}
|
||||
|
||||
for _, group2 := range result["groups"].([]interface{}) {
|
||||
group := group2.(map[string]interface{})
|
||||
for _, product2 := range group["items"].([]interface{}) {
|
||||
product := product2.(map[string]interface{})
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
Count: int(utils.MustInterface2Int64(product["quantity"])),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["extendCode"]), 0)),
|
||||
VendorSkuID: utils.Int64ToStr(utils.Interface2Int64WithDefault(product["vfoodId"], 0)),
|
||||
SkuName: product["name"].(string),
|
||||
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
|
||||
Weight: int(math.Round(utils.Interface2Float64WithDefault(product["weight"], 0.0))),
|
||||
}
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
sku.VendorSkuID = utils.Int64ToStr(utils.MustInterface2Int64(product["id"])) // 2018-09-28日,饿了么迁移到饿百后,这个字段发生了变化
|
||||
}
|
||||
order.Skus = append(order.Skus, sku)
|
||||
}
|
||||
}
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
return order
|
||||
}
|
||||
|
||||
//
|
||||
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, nil)
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyWriteElmOrder(order)
|
||||
// }
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(err, "elm onOrderNew")
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) *elmapi.CallbackResponse {
|
||||
status := &model.OrderStatus{
|
||||
VendorOrderID: msg.OrderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.OrderID,
|
||||
RefVendorID: model.VendorIDELM,
|
||||
Status: model.OrderStatusApplyUrgeOrder,
|
||||
VendorStatus: utils.Int2Str(msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
|
||||
}
|
||||
c.ClientUrgeOrder(msg.OrderID)
|
||||
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged("", status), status.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) stateAndType2Str(state string, msgType int) string {
|
||||
return fmt.Sprintf("%s-%d", state, msgType)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) spliltCompositeState(compositeState string) (state string, msgType int) {
|
||||
index := strings.Index(compositeState, "-")
|
||||
if index >= 0 {
|
||||
msgType = int(utils.Str2Int64(compositeState[index+1:]))
|
||||
if msgType == 0 {
|
||||
globals.SugarLogger.Debug(compositeState)
|
||||
}
|
||||
return compositeState[:index], msgType
|
||||
}
|
||||
return compositeState, 0
|
||||
}
|
||||
|
||||
// IPurchasePlatformHandler
|
||||
func (c *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int {
|
||||
state, _ := c.spliltCompositeState(vendorStatus)
|
||||
if status, ok := VendorStatus2StatusMap[state]; ok {
|
||||
return status
|
||||
}
|
||||
return model.OrderStatusUnknown
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("elm AcceptOrRefuseOrder orderID:%s", order.VendorOrderID)
|
||||
// if globals.EnableElmStoreWrite {
|
||||
// if isAcceptIt {
|
||||
// err = api.ElmAPI.ConfirmOrder(order.VendorOrderID)
|
||||
// } else {
|
||||
// err = api.ElmAPI.CancelOrder(order.VendorOrderID, elmapi.CancelOrderTypeOthers, "")
|
||||
// }
|
||||
// }
|
||||
return err
|
||||
}
|
||||
|
||||
// 饿了么没有拣货这个状态,直接返回成功
|
||||
// 真实流程中也不会调用这个方法,因为接收订单后状态会直接转移到已拣货
|
||||
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
// if globals.EnableElmStoreWrite {
|
||||
// err = api.ElmAPI.DeliveryBySelfLite(order.VendorOrderID)
|
||||
// }
|
||||
return err
|
||||
}
|
||||
|
||||
// 饿了么转商家自送后,没有确认送达的概念,空操作
|
||||
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
// if globals.EnableElmStoreWrite {
|
||||
// err = api.ElmAPI.StartDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
|
||||
// }
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
// if globals.EnableElmStoreWrite {
|
||||
// err = api.ElmAPI.CompleteDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
|
||||
// }
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *partner.StatusActionParams) {
|
||||
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusNew {
|
||||
params = &partner.StatusActionParams{ // 饿了么开了专送店的订单没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货
|
||||
Timeout: acceptOrderDelay,
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
|
||||
err = errors.New("饿了么还未实现GetOrderRealMobile")
|
||||
return mobile, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
// 发起全款退款
|
||||
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
return fmt.Errorf("饿了么不支持全款退款")
|
||||
}
|
||||
|
||||
// 发起部分退款
|
||||
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
return fmt.Errorf("饿了么不支持部分退款")
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
aliyunsmsclient "github.com/KenmyZhang/aliyun-communicate"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
ELM_SMS_REMINDERS_DAIPEISHONG_TEMPLATECODE = "SMS_175573181" //饿了么待配送模板ID
|
||||
ELM_SMS_REMINDERS_PEISHOGNZHONG_TEMPLATECODE = "SMS_175583155" //饿了么配送中模板ID
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) ClientUrgeOrder(orderID string) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
var err error
|
||||
globals.SugarLogger.Debugf("ClientUrgeOrder orderID:%s", orderID)
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDELM)
|
||||
if err = err2; err == nil {
|
||||
templateCode := ""
|
||||
var templateParams map[string]interface{}
|
||||
if order.Status == model.OrderStatusFinishedPickup {
|
||||
templateCode = ELM_SMS_REMINDERS_DAIPEISHONG_TEMPLATECODE
|
||||
templateParams = map[string]interface{}{
|
||||
"name": order.ConsigneeName,
|
||||
}
|
||||
} else if order.Status == model.OrderStatusDelivering {
|
||||
bill, err2 := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
|
||||
if err = err2; err == nil {
|
||||
templateCode = ELM_SMS_REMINDERS_PEISHOGNZHONG_TEMPLATECODE
|
||||
templateParams = map[string]interface{}{
|
||||
"name": order.ConsigneeName,
|
||||
"number": bill.CourierMobile,
|
||||
}
|
||||
}
|
||||
}
|
||||
if templateCode != "" {
|
||||
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
|
||||
if globals.ReallyCallPlatformAPI {
|
||||
_, err = smsClient.Execute(globals.AliKey, globals.AliSecret, order.ConsigneeMobile, globals.SMSSignName, templateCode, string(utils.MustMarshal(templateParams)))
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("ClientUrgeOrder orderID:%s failed with error:%v", orderID, err)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestGetOrder(t *testing.T) {
|
||||
orderID := "3025427524410871880"
|
||||
order, err := new(PurchaseHandler).GetOrder("", orderID)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
if order.VendorOrderID != orderID {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"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/dao"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode string, vendorStoreID string) (*dao.StoreDetail, error) {
|
||||
return nil, errors.New("饿了么还没实现")
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
|
||||
return storeStatus, err
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/elmapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillStatusMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
if msg.MsgType == elmapi.MsgTypeWaybillWait4Courier { //MsgTypeWaybillWait4Courier事件与JD的新运单事件的时间机制更相似
|
||||
order.Status = model.WaybillStatusNew
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillPickingUp {
|
||||
if result, err := api.ElmAPI.GetOrder(msg.OrderID); err == nil {
|
||||
order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(result["deliverFee"], 0.0) +
|
||||
utils.Interface2Float64WithDefault(result["vipDeliveryFeeDiscount"], 0.0))
|
||||
}
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillCourierArrived {
|
||||
order.Status = model.WaybillStatusCourierArrived
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillDelivering {
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillDelivered {
|
||||
order.Status = model.WaybillStatusDelivered
|
||||
} else if msg.MsgType >= elmapi.MsgTypeWaybillCanceledByMerchant && msg.MsgType <= elmapi.MsgTypeWaybillCanceledBySystem {
|
||||
order.Status = model.WaybillStatusCanceled
|
||||
} else if msg.MsgType >= elmapi.MsgTypeWaybillFailedCallLate &&
|
||||
msg.MsgType <= elmapi.MsgTypeRejectedSystemError &&
|
||||
msg.MsgType != elmapi.MsgTypeDeiverBySelf {
|
||||
order.Status = model.WaybillStatusFailed
|
||||
} else {
|
||||
// MsgTypeWaybillWait4DeliveryVendor
|
||||
// MsgTypeDeiverBySelf
|
||||
order.Status = model.WaybillStatusUnknown
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackMsg2Waybill(msg *elmapi.CallbackWaybillStatusMsg) (retVal *model.Waybill) {
|
||||
retVal = &model.Waybill{
|
||||
VendorOrderID: msg.OrderID,
|
||||
OrderVendorID: model.VendorIDELM,
|
||||
VendorWaybillID: msg.OrderID,
|
||||
WaybillVendorID: model.VendorIDELM,
|
||||
CourierName: msg.Name,
|
||||
CourierMobile: msg.Phone,
|
||||
VendorStatus: c.composeState(msg.State, msg.SubState, msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateAt / 1000),
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) composeState(state, subState string, msgType int) string {
|
||||
return fmt.Sprintf("%s-%d", state, msgType)
|
||||
}
|
||||
@@ -1,422 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"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"
|
||||
)
|
||||
|
||||
const (
|
||||
actMapDuration = 2 * time.Hour
|
||||
)
|
||||
|
||||
type LogicUpdateInfo struct {
|
||||
Item interface{}
|
||||
KVs map[string]interface{}
|
||||
Condition map[string]interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
jdSkuActStatusMap = map[int]int{
|
||||
jdapi.PromotionStateNotConfirm: model.ActStatusNA,
|
||||
jdapi.PromotionStateConfirmed: model.ActStatusCreated,
|
||||
jdapi.PromotionStateCanceled: model.ActStatusCanceled,
|
||||
jdapi.PromotionStateEnded: model.ActStatusEnded,
|
||||
}
|
||||
|
||||
actMap jxutils.SyncMapWithTimeout
|
||||
)
|
||||
|
||||
// 是否按单一门店商品维度创建活动
|
||||
func isCreateTypeSingleStoreSku() bool {
|
||||
return false
|
||||
// return !globals.IsProductEnv()
|
||||
}
|
||||
|
||||
func splitPromotionSku(skus []*jdapi.PromotionSku, maxCount int) (skusList [][]*jdapi.PromotionSku) {
|
||||
for {
|
||||
skusLen := len(skus)
|
||||
if skusLen <= maxCount {
|
||||
skusList = append(skusList, skus)
|
||||
break
|
||||
}
|
||||
skusList = append(skusList, skus[:maxCount])
|
||||
skus = skus[maxCount:]
|
||||
}
|
||||
return skusList
|
||||
}
|
||||
|
||||
func jdSkuActType2Jx(actType int) int {
|
||||
if actType == jdapi.PromotionTypeDirectDown {
|
||||
return model.ActSkuDirectDown
|
||||
} else if actType == jdapi.PromotionTypeSeckill || actType == jdapi.PromotionTypeLimitedTime {
|
||||
return model.ActSkuSecKill
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func jdSkuActStatus2Jx(jdActState int) int {
|
||||
return jdSkuActStatusMap[jdActState]
|
||||
}
|
||||
|
||||
func CreatePromotionInfos(vendorOrgCode string, promotionType int, name string, beginDate, endDate time.Time, outInfoId, advertising, traceId string) (infoId int64, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
infoId, err = getAPI(vendorOrgCode).CreatePromotionInfosSingle(name, beginDate, endDate, outInfoId, advertising, traceId)
|
||||
} else {
|
||||
infoId, err = getAPI(vendorOrgCode).CreatePromotionInfosLimitTime(name, beginDate, endDate, outInfoId, advertising, traceId)
|
||||
}
|
||||
} else {
|
||||
infoId = jxutils.GenFakeID()
|
||||
}
|
||||
if err == nil {
|
||||
actMap.StoreWithTimeout(infoId, 1, actMapDuration)
|
||||
}
|
||||
return infoId, err
|
||||
}
|
||||
|
||||
func CreatePromotionRules(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, limitDevice, limitPin, limitCount, limitDaily int, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
err = getAPI(vendorOrgCode).CreatePromotionRulesSingle(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
|
||||
} else {
|
||||
err = getAPI(vendorOrgCode).CreatePromotionRulesLimitTime(infoId, outInfoId, limitDevice, limitPin, limitCount, limitDaily, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CreatePromotionSku(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
for _, batchSkus := range splitPromotionSku(skus, jdapi.MaxPromotionSkuCount) {
|
||||
var tmpSkusResult []*jdapi.PromotionSku
|
||||
var tmpErr error
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
tmpSkusResult, tmpErr = getAPI(vendorOrgCode).CreatePromotionSkuSingle(infoId, outInfoId, batchSkus, traceId)
|
||||
} else {
|
||||
tmpSkusResult, tmpErr = getAPI(vendorOrgCode).CreatePromotionSkuLimitTime(infoId, outInfoId, batchSkus, traceId)
|
||||
}
|
||||
if err = tmpErr; err != nil {
|
||||
break
|
||||
}
|
||||
skusResult = append(skusResult, tmpSkusResult...)
|
||||
}
|
||||
}
|
||||
return skusResult, err
|
||||
}
|
||||
|
||||
func CancelPromotionSku(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
for _, batchSkus := range splitPromotionSku(skus, jdapi.MaxPromotionSkuCount) {
|
||||
var tmpErr error
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
tmpErr = getAPI(vendorOrgCode).CancelPromotionSkuSingle(infoId, outInfoId, batchSkus, traceId)
|
||||
} else {
|
||||
tmpErr = getAPI(vendorOrgCode).CancelPromotionSkuLimitTime(infoId, outInfoId, batchSkus, traceId)
|
||||
}
|
||||
if err = tmpErr; err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ConfirmPromotion(vendorOrgCode string, promotionType int, infoId int64, outInfoId, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
return getAPI(vendorOrgCode).ConfirmPromotionSingle(infoId, outInfoId, traceId)
|
||||
} else {
|
||||
return getAPI(vendorOrgCode).ConfirmPromotionLimitTime(infoId, outInfoId, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CancelPromotion(vendorOrgCode string, promotionType int, infoId int64, outInfoId, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
err = getAPI(vendorOrgCode).CancelPromotionSingle(infoId, outInfoId, traceId)
|
||||
} else {
|
||||
err = getAPI(vendorOrgCode).CancelPromotionLimitTime(infoId, outInfoId, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AdjustPromotionTime(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, endDate time.Time, traceId string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
err = getAPI(vendorOrgCode).AdjustPromotionTimeSingle(infoId, outInfoId, endDate, traceId)
|
||||
} else {
|
||||
err = getAPI(vendorOrgCode).AdjustPromotionTimeLimitTime(infoId, outInfoId, endDate, traceId)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AdjustPromotionSku(vendorOrgCode string, promotionType int, infoId int64, outInfoId string, skus []*jdapi.PromotionSku, traceId string) (skusResult []*jdapi.PromotionSku, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if promotionType == model.ActSkuDirectDown {
|
||||
skusResult, err = getAPI(vendorOrgCode).AdjustPromotionSkuSingle(infoId, outInfoId, skus, traceId)
|
||||
} else {
|
||||
skusResult, err = getAPI(vendorOrgCode).AdjustPromotionSkuLimitTime(infoId, outInfoId, skus, traceId)
|
||||
}
|
||||
}
|
||||
return skusResult, err
|
||||
}
|
||||
|
||||
func storeSku2Jd(actStoreSku []*model.ActStoreSku2, handler func(syncStatus int8) bool) (jdActStoreSku []*jdapi.PromotionSku) {
|
||||
for _, v := range actStoreSku {
|
||||
if handler(v.SyncStatus) {
|
||||
if v.VendorStoreID != "" && v.VendorSkuID != "" {
|
||||
jdActStoreSku = append(jdActStoreSku, &jdapi.PromotionSku{
|
||||
StationNo: utils.Str2Int64(v.VendorStoreID),
|
||||
SkuID: utils.Str2Int64(v.VendorSkuID),
|
||||
PromotionPrice: v.ActualActPrice,
|
||||
LimitSkuCount: v.Stock,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return jdActStoreSku
|
||||
}
|
||||
|
||||
func createSkuAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model.ActStoreSku2) (vendorActID string, err error) {
|
||||
traceInfo := ctx.GetTrackInfo()
|
||||
outInfoID := ""
|
||||
if act.VendorActID == "" {
|
||||
outInfoID = utils.Int2Str(act.ID)
|
||||
}
|
||||
infoID, err2 := CreatePromotionInfos(act.VendorOrgCode, act.Type, act.GetRealActName(), act.BeginAt, act.EndAt, outInfoID, act.Advertising, traceInfo)
|
||||
if err = err2; err == nil {
|
||||
vendorActID = utils.Int64ToStr(infoID)
|
||||
if err = CreatePromotionRules(act.VendorOrgCode, act.Type, infoID, "", act.LimitUser, act.LimitUser, act.LimitCount, 1, traceInfo); err == nil {
|
||||
if _, err = CreatePromotionSku(act.VendorOrgCode, act.Type, infoID, utils.Int2Str(act.ID), storeSku2Jd(actStoreSku, model.IsSyncStatusNeedCreate), traceInfo); err == nil {
|
||||
if err = ConfirmPromotion(act.VendorOrgCode, act.Type, infoID, "", traceInfo); err == nil {
|
||||
for _, v := range actStoreSku {
|
||||
v.VendorActID = vendorActID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
CancelPromotion(act.VendorOrgCode, act.Type, infoID, "", traceInfo)
|
||||
}
|
||||
}
|
||||
return vendorActID, err
|
||||
}
|
||||
|
||||
func proxyCreateSkuAct(ctx *jxcontext.Context, act *model.Act2, actStoreSku []*model.ActStoreSku2) (vendorActID string, err error) {
|
||||
if isCreateTypeSingleStoreSku() && len(actStoreSku) > 1 {
|
||||
errList := errlist.New()
|
||||
vendorActID := act.VendorActID
|
||||
act.VendorActID = "placeholder"
|
||||
for _, v := range actStoreSku {
|
||||
_, err := createSkuAct(ctx, act, []*model.ActStoreSku2{v})
|
||||
errList.AddErr(err)
|
||||
}
|
||||
act.VendorActID = vendorActID
|
||||
err = errList.GetErrListAsOne()
|
||||
} else {
|
||||
vendorActID, err = createSkuAct(ctx, act, actStoreSku)
|
||||
}
|
||||
return vendorActID, err
|
||||
}
|
||||
|
||||
func cancelSkuActSkus(ctx *jxcontext.Context, act *model.Act2, vendorActID string, actStoreSku []*model.ActStoreSku2) (err error) {
|
||||
if vendorActID != "" {
|
||||
if skuList := storeSku2Jd(actStoreSku, model.IsSyncStatusNeedDelete); len(skuList) > 0 {
|
||||
err = CancelPromotionSku(act.VendorOrgCode, act.Type, utils.Str2Int64(vendorActID), "", skuList, ctx.GetTrackInfo())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func cancelSkuAct(ctx *jxcontext.Context, act *model.Act2, vendorActID string) (err error) {
|
||||
if vendorActID != "" {
|
||||
err = CancelPromotion(act.VendorOrgCode, act.Type, utils.Str2Int64(vendorActID), "", ctx.GetTrackInfo())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
||||
globals.SugarLogger.Debugf("jd SyncAct, actID:%d", act.ID)
|
||||
vendorActInfoMap := make(map[string][]*model.ActStoreSku2)
|
||||
deleteActInfoMap := make(map[string][]*model.ActStoreSku2)
|
||||
var actStoreSkuList4Create []*model.ActStoreSku2
|
||||
var updateItems []*dao.KVUpdateItem
|
||||
|
||||
actStoreSkuMap := partner.SplitActStoreSku(actStoreSkuList)
|
||||
actSkuCount := 0
|
||||
toDelActSkuCount := 0
|
||||
for storeID := range actStoreSkuMap {
|
||||
for _, actStoreSku := range actStoreSkuMap[storeID] {
|
||||
vendorActID := actStoreSku.VendorActID
|
||||
if vendorActID == "" {
|
||||
vendorActID = act.VendorActID
|
||||
}
|
||||
actSkuCount++
|
||||
vendorActInfoMap[vendorActID] = append(vendorActInfoMap[vendorActID], actStoreSku)
|
||||
if model.IsSyncStatusDelete(actStoreSku.SyncStatus) {
|
||||
toDelActSkuCount++
|
||||
deleteActInfoMap[vendorActID] = append(deleteActInfoMap[vendorActID], actStoreSku)
|
||||
} else if model.IsSyncStatusNew(actStoreSku.SyncStatus) {
|
||||
actStoreSkuList4Create = append(actStoreSkuList4Create, actStoreSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果是全删,直接添加删除(即取消)标志
|
||||
if actSkuCount == toDelActSkuCount {
|
||||
act.SyncStatus |= model.SyncFlagDeletedMask
|
||||
}
|
||||
db := dao.GetDB()
|
||||
err = func() (err error) {
|
||||
if model.IsSyncStatusDelete(act.SyncStatus) {
|
||||
errList := errlist.New()
|
||||
for vendorActID := range vendorActInfoMap {
|
||||
if vendorActID != "" {
|
||||
if err = cancelSkuAct(ctx, act, vendorActID); err == nil {
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, vendorActInfoMap[vendorActID], model.SyncFlagModifiedMask)...)
|
||||
} else {
|
||||
errList.AddErr(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err = errList.GetErrListAsOne(); err == nil {
|
||||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
|
||||
}
|
||||
} else if model.IsSyncStatusNew(act.SyncStatus) {
|
||||
if act.VendorActID, err = proxyCreateSkuAct(ctx, act, actStoreSkuList4Create); err == nil {
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...)
|
||||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagNewMask))
|
||||
} else {
|
||||
if act.VendorActID != "" {
|
||||
actMap := partner.Act2ActMap(act)
|
||||
dao.UpdateEntity(db, actMap, model.FieldVendorActID)
|
||||
}
|
||||
}
|
||||
} else if model.IsSyncStatusUpdate(act.SyncStatus) {
|
||||
errList := errlist.New()
|
||||
if len(actStoreSkuList4Create) > 0 {
|
||||
if _, err = proxyCreateSkuAct(ctx, act, actStoreSkuList4Create); err == nil {
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, actStoreSkuList4Create, model.SyncFlagNewMask)...)
|
||||
} else {
|
||||
errList.AddErr(err)
|
||||
}
|
||||
}
|
||||
for vendorActID := range deleteActInfoMap {
|
||||
if vendorActID != "" {
|
||||
if len(vendorActInfoMap[vendorActID]) == len(deleteActInfoMap[vendorActID]) {
|
||||
err = cancelSkuAct(ctx, act, vendorActID)
|
||||
} else {
|
||||
err = cancelSkuActSkus(ctx, act, vendorActID, deleteActInfoMap[vendorActID])
|
||||
}
|
||||
if err == nil {
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...)
|
||||
} else {
|
||||
errList.AddErr(err)
|
||||
}
|
||||
} else {
|
||||
updateItems = append(updateItems, partner.ActStoreSku2Update(ctx, deleteActInfoMap[vendorActID], model.SyncFlagDeletedMask)...)
|
||||
}
|
||||
}
|
||||
if err = errList.GetErrListAsOne(); err == nil {
|
||||
updateItems = append(updateItems, partner.Act2Update(ctx, act, model.SyncFlagModifiedMask))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(updateItems, false))
|
||||
_, err2 := dao.BatchUpdateActEntity(db, model.IsSyncStatusDelete(act.SyncStatus), updateItems)
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func OnActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = CurPurchaseHandler.onActMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onActMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if msg.StatusID == jdapi.PromotionStatusSingleOK || msg.StatusID == jdapi.PromotionStatusLimitTimeOK {
|
||||
promotionID := msg.BillID
|
||||
intPromotionID := utils.Str2Int64(promotionID)
|
||||
if _, ok := actMap.Load(intPromotionID); !ok {
|
||||
utils.CallFuncAsync(func() {
|
||||
if !partner.CurActManager.IsVendorActExist(jxcontext.AdminCtx, promotionID, model.VendorIDJD) {
|
||||
act, actStoreSkuList, err := getActFromJD(AppKey2OrgCode(msg.AppKey), promotionID)
|
||||
if err == nil && len(actStoreSkuList) > 0 {
|
||||
_, err = partner.CurActManager.CreateActFromVendor(jxcontext.AdminCtx, act, actStoreSkuList)
|
||||
}
|
||||
if err != nil {
|
||||
retVal = jdapi.Err2CallbackResponse(err, promotionID)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
actMap.Delete(intPromotionID)
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func getActFromJD(vendorOrgCode, promotionID string) (act *model.Act2, actStoreSkuList []*model.ActStoreSku2, err error) {
|
||||
result, err := getAPI(vendorOrgCode).QueryPromotionInfo(utils.Str2Int64(promotionID))
|
||||
if err == nil && len(result.SkuResultList) > 0 {
|
||||
act = &model.Act2{
|
||||
Act: model.Act{
|
||||
Name: fmt.Sprintf("%s-%d", result.Source, result.PromotionInfoID),
|
||||
Type: jdSkuActType2Jx(result.PromotionType),
|
||||
Status: jdSkuActStatus2Jx(result.PromotionState),
|
||||
BeginAt: result.SkuResultList[0].BeginTime.GoTime(),
|
||||
EndAt: result.SkuResultList[0].EndTime.GoTime(),
|
||||
Source: result.Source,
|
||||
CreateType: model.ActCreateTypeCallback,
|
||||
PricePercentage: 0,
|
||||
LimitDaily: result.SkuResultList[0].LimitDaily,
|
||||
LimitCount: 1,
|
||||
},
|
||||
VendorID: model.VendorIDJD,
|
||||
VendorOrgCode: vendorOrgCode,
|
||||
VendorActID: promotionID,
|
||||
}
|
||||
if utils.IsTimeZero(act.BeginAt) {
|
||||
act.BeginAt = result.BeginTime.GoTime()
|
||||
}
|
||||
if utils.IsTimeZero(act.EndAt) {
|
||||
act.EndAt = result.EndTime.GoTime().Add(24*time.Hour - 1*time.Second)
|
||||
}
|
||||
if result.SkuResultList[0].LimitPin == 1 || result.SkuResultList[0].LimitDevice == 1 {
|
||||
act.LimitUser = 1
|
||||
}
|
||||
|
||||
for _, v := range result.SkuResultList {
|
||||
if v.PromotionState != jdapi.PromotionStateCanceled {
|
||||
actStoreSkuList = append(actStoreSkuList, &model.ActStoreSku2{
|
||||
VendorStoreID: utils.Int64ToStr(v.StationNo),
|
||||
VendorSkuID: utils.Int64ToStr(v.SkuID),
|
||||
ActualActPrice: int64(v.PromotionPrice),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return act, actStoreSkuList, err
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
)
|
||||
|
||||
func OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if CurPurchaseHandler != nil {
|
||||
retVal = CurPurchaseHandler.OnOrderMsg(AppKey2OrgCode(msg.AppKey), msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if CurPurchaseHandler != nil {
|
||||
retVal = CurPurchaseHandler.OnWaybillMsg(AppKey2OrgCode(msg.AppKey), msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func OnStoreMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if CurPurchaseHandler != nil {
|
||||
retVal = CurPurchaseHandler.OnStoreMsg(AppKey2OrgCode(msg.AppKey), msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func OnOrderInfoChangeMsg(msg *jdapi.CallbackOrderInfoChangeMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if CurPurchaseHandler != nil {
|
||||
retVal = CurPurchaseHandler.OnOrderInfoChangeMsg(AppKey2OrgCode(msg.AppKey), msg)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) OnFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
utils.CallFuncAsync(func() {
|
||||
retVal = p.onFinancialMsg(msg)
|
||||
})
|
||||
return retVal
|
||||
}
|
||||
|
||||
// 京东正向/退款订单类型处理--存储
|
||||
func (p *PurchaseHandler) onFinancialMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
var err error
|
||||
a := getAPI(AppKey2OrgCode(msg.AppKey))
|
||||
// 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 { // 如果是正向单
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(msg.BillID, model.VendorIDJD)
|
||||
if err = err2; err == nil {
|
||||
orderData, err2 := a.QuerySingleOrder(msg.BillID)
|
||||
if err = err2; err == nil {
|
||||
orderFinancial, err2 := CurPurchaseHandler.OrderDetail2Financial(a, orderData, false, order)
|
||||
if err = err2; err == nil {
|
||||
if msg.StatusID == jdapi.OrderStatusPayFinishedSettle {
|
||||
err = partner.CurOrderManager.SaveOrderFinancialInfo(orderFinancial, partner.CreatedPeration)
|
||||
} else {
|
||||
err = partner.CurOrderManager.SaveOrderFinancialInfo(orderFinancial, partner.UpdatedPeration)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
} else if msg.StatusID == jdapi.AfsServiceStateRefundSuccess || msg.StatusID == jdapi.AfsServiceStateReturnGoodsSuccess { // 如果是退款单
|
||||
orderData, err2 := a.GetAfsService(msg.BillID)
|
||||
if err = err2; err == nil {
|
||||
err = partner.CurOrderManager.SaveAfsOrderFinancialInfo(CurPurchaseHandler.AfsOrderDetail2Financial(orderData))
|
||||
}
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(nil, "jd OnFinancialMsg") // todo 强制返回成功
|
||||
}
|
||||
|
||||
// 处理京东正向订单信息
|
||||
func (p *PurchaseHandler) OrderDetail2Financial(a *jdapi.API, orderData map[string]interface{}, isFromOrderDetail bool, order *model.GoodsOrder) (orderFinancial *model.OrderFinancial, err error) {
|
||||
orderFinancial = &model.OrderFinancial{
|
||||
VendorID: model.VendorIDJD,
|
||||
VendorOrderID: utils.Int64ToStr(utils.MustInterface2Int64(orderData["orderId"])),
|
||||
ReceivableFreight: utils.MustInterface2Int64(orderData["orderReceivableFreight"]),
|
||||
FreightMoney: utils.MustInterface2Int64(orderData["orderFreightMoney"]),
|
||||
ActualPayMoney: utils.MustInterface2Int64(orderData["orderBuyerPayableMoney"]),
|
||||
DiscountMoney: utils.MustInterface2Int64(orderData["orderDiscountMoney"]),
|
||||
DistanceFreightMoney: utils.MustInterface2Int64(orderData["merchantPaymentDistanceFreightMoney"]),
|
||||
FreightTipsMoney: utils.MustInterface2Int64(orderData["tips"]),
|
||||
PointsDeductionMoney: utils.MustInterface2Int64(orderData["platformPointsDeductionMoney"]),
|
||||
// BoxMoney: utils.MustInterface2Int64(orderData["packagingMoney"]), // 京东包装(塑料袋)由京东提供,相应钱款也归京东,不记录/记录之后优化算法
|
||||
}
|
||||
skus := order.Skus
|
||||
if skus != nil {
|
||||
for _, x := range skus {
|
||||
orderFinancial.ShopPriceMoney += x.ShopPrice * int64(x.Count)
|
||||
}
|
||||
}
|
||||
if orderData["product"] != nil {
|
||||
product := orderData["product"].([]interface{})
|
||||
for _, x := range product {
|
||||
xMap := x.(map[string]interface{})
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: orderFinancial.VendorID,
|
||||
VendorOrderID: orderFinancial.VendorOrderID,
|
||||
// OrderFinancialID: orderFinancial.VendorOrderID,
|
||||
// ConfirmTime: utils.Str2Time(utils.Interface2String(orderData["orderStartTime"])),
|
||||
VendorStoreID: utils.Interface2String(orderData["deliveryStationNo"]),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["deliveryStationNoIsv"]), 0)),
|
||||
JxStoreID: order.JxStoreID,
|
||||
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(xMap["skuId"])),
|
||||
// SkuID: int(utils.Str2Int64(utils.Interface2String(xMap["skuIdIsv"]))),
|
||||
PromotionType: int(utils.MustInterface2Int64(xMap["promotionType"])),
|
||||
Name: utils.Interface2String(xMap["skuName"]),
|
||||
ShopPrice: utils.MustInterface2Int64(xMap["skuStorePrice"]),
|
||||
SalePrice: utils.MustInterface2Int64(xMap["skuJdPrice"]),
|
||||
Count: int(utils.MustInterface2Int64(xMap["skuCount"])),
|
||||
IsAfsOrder: 0,
|
||||
// MealBoxMoney: utils.MustInterface2Int64(xMap["canteenMoney"]), // 京东的目前不考虑结算餐盒费,因为都归京东所有
|
||||
}
|
||||
|
||||
// PromotionType 是一个关键数据,可能某商品活动限购,用户超出限购数量,超出部分不享受优惠,那么除了要在活动表根据skuId,活动起止日期,活动城市来查询,还需要判断活动类型PromotionType
|
||||
// 平台/京西单条sku补贴金额,应该去京西后台活动库去取,活动里针对单条SKU,如果京东/京西有补贴,应该有记录
|
||||
// orderSkuFinancial.PmSubsidyMoneyForSku =
|
||||
// orderSkuFinancial.JxSubsidyMoneyForSku =
|
||||
// orderFinancial.JxSubsidyMoneyToSku += orderSkuFinancial.JxSubsidyMoneyForSku
|
||||
// orderFinancial.JxSubsidyMoney += orderSkuFinancial.JxSubsidyMoneyForSku
|
||||
orderFinancial.SalePriceMoney += orderSkuFinancial.SalePrice * int64(orderSkuFinancial.Count)
|
||||
orderSkuFinancial.SkuID = int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["skuIdIsv"]), 0))
|
||||
if orderSkuFinancial.SkuID > math.MaxInt32 {
|
||||
orderSkuFinancial.SkuID = orderSkuFinancial.JxSkuID
|
||||
}
|
||||
orderFinancial.Skus = append(orderFinancial.Skus, orderSkuFinancial)
|
||||
}
|
||||
}
|
||||
// orderFinancial.DeliveryConfirmTime = utils.Str2TimeWithDefault(utils.Interface2String(orderData["deliveryConfirmTime"]), utils.DefaultTimeValue)
|
||||
if int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["deliveryCarrierNo"]), 0)) == jdapi.CarrierNoSelfDelivery {
|
||||
// 如果为自配送,自配送补贴=订单初始运费,远距离费=0
|
||||
orderFinancial.SelfDeliveryDiscountMoney = utils.MustInterface2Int64(orderData["orderReceivableFreight"])
|
||||
orderFinancial.DistanceFreightMoney = 0
|
||||
orderFinancial.FreightTipsMoney = 0
|
||||
// 通过本地数据库去取是否转美团/达达,并计算运费
|
||||
// wayBill, err2 := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
|
||||
// if err = err2; err == nil {
|
||||
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
// }
|
||||
}
|
||||
if orderData["discount"] != nil {
|
||||
discount := orderData["discount"].([]interface{})
|
||||
for _, x := range discount {
|
||||
xMap := x.(map[string]interface{})
|
||||
discountPrice := utils.MustInterface2Int64(xMap["discountPrice"])
|
||||
discountType := int(utils.MustInterface2Int64(xMap["discountType"]))
|
||||
if discountType == jdapi.FreightDiscountTypeByShop {
|
||||
orderFinancial.FreightDiscountMoney = discountPrice
|
||||
} else if discountType == jdapi.FreightDiscountTypeByVip || discountType == jdapi.FreightDiscountTypeByActivity {
|
||||
orderFinancial.PmFreightDiscountMoney = discountPrice
|
||||
} else if discountType == jdapi.FreightDiscountTypeByCoupons {
|
||||
if xMap["platPayMoney"] == nil {
|
||||
orderFinancial.PmFreightDiscountMoney = discountPrice
|
||||
} else {
|
||||
orderFinancial.PmFreightDiscountMoney = int64(utils.MustInterface2Float64(xMap["platPayMoney"]))
|
||||
orderFinancial.FreightDiscountMoney = discountPrice - orderFinancial.PmFreightDiscountMoney
|
||||
}
|
||||
}
|
||||
orderFinancial.TotalDiscountMoney += discountPrice
|
||||
if xMap["orderShareRatioData"] != nil {
|
||||
orderShareRatioData, _ := utils.HTTPBody2Values([]byte(utils.Interface2String(xMap["orderShareRatioData"])), false)
|
||||
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 +=
|
||||
}
|
||||
}
|
||||
}
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(orderFinancial.Discounts, false))
|
||||
}
|
||||
order1, err2 := a.OrderShoudSettlementService(orderFinancial.VendorOrderID)
|
||||
if err = err2; err == nil {
|
||||
orderFinancial.ShopMoney = utils.Interface2Int64WithDefault(order1["settlementAmount"], 0)
|
||||
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["goodsCommission"], 0)
|
||||
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["freightCommission"], 0)
|
||||
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["packageCommission"], 0)
|
||||
orderFinancial.PmMoney += utils.Interface2Int64WithDefault(order1["guaranteedCommission"], 0)
|
||||
orderFinancial.PmSkuSubsidyMoney = utils.Interface2Int64WithDefault(order1["platSkuGoodsDiscountMoney"], 0)
|
||||
orderFinancial.PmSubsidyMoney = utils.Interface2Int64WithDefault(order1["platOrderGoodsDiscountMoney"], 0) + orderFinancial.PmSkuSubsidyMoney
|
||||
}
|
||||
return orderFinancial, err
|
||||
}
|
||||
|
||||
// 处理京东售后订单结账信息
|
||||
func (p *PurchaseHandler) AfsOrderDetail2Financial(orderData map[string]interface{}) (afsOrder *model.AfsOrder) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: model.VendorIDJD,
|
||||
AfsOrderID: utils.Interface2String(orderData["afsServiceOrder"]),
|
||||
VendorOrderID: utils.Interface2String(orderData["orderId"]),
|
||||
VendorStoreID: utils.Interface2String(orderData["stationId"]),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(orderData["stationNumOutSystem"]), 0)),
|
||||
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"]),
|
||||
TongchengFreightMoney: utils.MustInterface2Int64(orderData["tongchengFreightMoney"]),
|
||||
SkuBoxMoney: utils.MustInterface2Int64(orderData["mealBoxMoney"]),
|
||||
VendorOrgCode: utils.Interface2String(orderData["venderId"]),
|
||||
}
|
||||
order, err := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
|
||||
if err == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("jd AfsOrderDetail2Financial, afsOrderID:%s is not found from partner.CurOrderManager.LoadOrder", afsOrder.VendorOrderID)
|
||||
}
|
||||
if orderData["afsDetailList"] != nil {
|
||||
refundDetail := orderData["afsDetailList"].([]interface{})
|
||||
for _, x := range refundDetail {
|
||||
xMap := x.(map[string]interface{})
|
||||
orderSku := &model.OrderSkuFinancial{
|
||||
VendorID: model.VendorIDJD,
|
||||
AfsOrderID: afsOrder.AfsOrderID,
|
||||
VendorOrderID: afsOrder.VendorOrderID,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
StoreID: afsOrder.StoreID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(xMap["wareId"])),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(xMap["skuIdIsv"]), 0)),
|
||||
Name: utils.Interface2String(xMap["wareName"]),
|
||||
UserMoney: utils.MustInterface2Int64(xMap["afsMoney"]),
|
||||
PmSkuSubsidyMoney: utils.MustInterface2Int64(xMap["platPayMoney"]),
|
||||
IsAfsOrder: 1,
|
||||
}
|
||||
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
|
||||
orderSku.PmSubsidyMoney += orderSku.PmSkuSubsidyMoney
|
||||
|
||||
if xMap["afsSkuDiscountList"] != nil {
|
||||
afsSkuDiscountList := xMap["afsSkuDiscountList"].([]interface{})
|
||||
for _, y := range afsSkuDiscountList {
|
||||
orderSku.PmSubsidyMoney += utils.MustInterface2Int64(y.(map[string]interface{})["platPayMoney"])
|
||||
}
|
||||
}
|
||||
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||||
}
|
||||
if len(refundDetail) <= 0 {
|
||||
globals.SugarLogger.Warnf("jd AfsOrderDetail2Financial, orderID:%s have no refund_detail", afsOrder.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("jd AfsOrderDetail2Financial, orderID:% refund_detail is nil", afsOrder.VendorOrderID)
|
||||
}
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) OnOrderDetail(a *jdapi.API, orderDetail map[string]interface{}, peration string) (err error) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(utils.MustInterface2Int64(orderDetail["orderId"])), model.VendorIDJD)
|
||||
if err == nil {
|
||||
orderFinancial, err2 := CurPurchaseHandler.OrderDetail2Financial(a, orderDetail, true, order)
|
||||
if err = err2; err == nil {
|
||||
err = partner.CurOrderManager.SaveOrderFinancialInfo(orderFinancial, peration)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
)
|
||||
|
||||
func TestOnFinancialMsg(t *testing.T) {
|
||||
msg := &jdapi.CallbackOrderMsg{
|
||||
BillID: "907315020000322",
|
||||
StatusID: "330902",
|
||||
}
|
||||
res := CurPurchaseHandler.onFinancialMsg(msg)
|
||||
fmt.Println(res)
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"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"
|
||||
)
|
||||
|
||||
type PurchaseHandler struct {
|
||||
partner.BasePurchasePlatform
|
||||
}
|
||||
|
||||
var (
|
||||
CurPurchaseHandler *PurchaseHandler
|
||||
)
|
||||
|
||||
func init() {
|
||||
globals.SugarLogger.Debug("init jd")
|
||||
CurPurchaseHandler = new(PurchaseHandler)
|
||||
partner.RegisterPurchasePlatform(CurPurchaseHandler)
|
||||
}
|
||||
|
||||
func getAPI(appOrgCode string) (apiObj *jdapi.API) {
|
||||
if appOrgCode == "" {
|
||||
globals.SugarLogger.Warnf("getAPI appOrgCode is empty")
|
||||
}
|
||||
return partner.CurAPIManager.GetAPI(model.VendorIDJD, appOrgCode).(*jdapi.API)
|
||||
}
|
||||
|
||||
func GetAPI(appOrgCode string) (apiObj *jdapi.API) {
|
||||
return getAPI(appOrgCode)
|
||||
}
|
||||
|
||||
func AppKey2OrgCode(appKey string) (vendorOrgCode string) {
|
||||
apiList := partner.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD)
|
||||
for _, v := range apiList {
|
||||
jdAPI := partner.CurAPIManager.GetAPI(model.VendorIDJD, v).(*jdapi.API)
|
||||
if jdAPI.GetAppKey() == appKey {
|
||||
vendorOrgCode = v
|
||||
break
|
||||
}
|
||||
}
|
||||
if vendorOrgCode == "" {
|
||||
globals.SugarLogger.Warnf("AppKey2OrgCode appKey:%s get empty vendorOrgCode", appKey)
|
||||
}
|
||||
return vendorOrgCode
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetVendorID() int {
|
||||
return model.VendorIDJD
|
||||
}
|
||||
|
||||
func JdOperationTime2JxOperationTime(value1 int) int16 {
|
||||
value := int16(value1)
|
||||
return (value/2)*100 + (value%2)*30
|
||||
}
|
||||
|
||||
func JxOperationTime2JdOperationTime(value int16) int16 {
|
||||
return (value/100)*2 + (value%100)/30
|
||||
}
|
||||
|
||||
func JdStoreStatus2JxStatus(yn, closeStatus int) int {
|
||||
if yn == 1 {
|
||||
return model.StoreStatusDisabled
|
||||
} else if closeStatus == 1 {
|
||||
return model.StoreStatusClosed
|
||||
}
|
||||
return model.StoreStatusOpened
|
||||
}
|
||||
|
||||
func JxStoreStatus2JdStatus(status int) (yn, closeStatus int) {
|
||||
switch status {
|
||||
case model.StoreStatusDisabled:
|
||||
return 1, 1
|
||||
case model.StoreStatusHaveRest, model.StoreStatusClosed:
|
||||
return 0, 1
|
||||
default:
|
||||
return 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
|
||||
return imgHint, err
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
_ "git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package jd
|
||||
@@ -1,617 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"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"
|
||||
"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 (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
jdapi.OrderStatusPurchased: model.OrderStatusNew,
|
||||
jdapi.OrderStatusWaitOutStore: model.OrderStatusAccepted,
|
||||
jdapi.StatusIDWaitOutStore: model.OrderStatusAccepted,
|
||||
jdapi.OrderStatusFinishedPickup: model.OrderStatusFinishedPickup,
|
||||
jdapi.OrderStatusDelivering: model.OrderStatusDelivering,
|
||||
jdapi.OrderStatusDelivered: model.OrderStatusFinished,
|
||||
jdapi.OrderStatusFinished: model.OrderStatusFinished, // todo 这个状态不是真正都完成的意思?
|
||||
jdapi.OrderStatusCanceled: model.OrderStatusCanceled,
|
||||
|
||||
jdapi.OrderStatusAdjust: model.OrderStatusAdjust,
|
||||
jdapi.OrderStatusUserApplyCancel: model.OrderStatusApplyCancel,
|
||||
jdapi.OrderStatusLocked: model.OrderStatusLocked,
|
||||
jdapi.OrderStatusUnlocked: model.OrderStatusUnlocked,
|
||||
|
||||
jdapi.OrderStatusVenderAgreeCancel: model.OrderStatusVendorAgreeCancel,
|
||||
jdapi.OrderStatusVenderRejectCancel: model.OrderStatusVendorRejectCancel,
|
||||
jdapi.CallbackMsgOrderAddTips: model.OrderStatusWaybillTipChanged,
|
||||
}
|
||||
deliveryTypeMap = map[int]string{
|
||||
jdapi.CarrierNoCrowdSourcing: model.OrderDeliveryTypePlatform,
|
||||
jdapi.CarrierNoSelfDelivery: model.OrderDeliveryTypeStoreSelf,
|
||||
jdapi.CarrierNoSelfTake: model.OrderDeliveryTypeSelfTake,
|
||||
}
|
||||
|
||||
selfTakeCodeReg = regexp.MustCompile(`等待用户凭提货码(\d+)于`)
|
||||
|
||||
afsMsgMap = map[string]bool{
|
||||
jdapi.CallbackMsgNewApplyAfterSaleBill: true,
|
||||
jdapi.CallbackMsgUpdateApplyAfterSaleBill: true,
|
||||
jdapi.CallbackMsgNewAfterSaleBill: true,
|
||||
jdapi.CallbackMsgAfterSaleBillStatus: true,
|
||||
}
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) OnOrderMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderMsg(vendorOrgCode, msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) updateOrderFinancialInfo(a *jdapi.API, orderID string) (err error) {
|
||||
order := &model.GoodsOrder{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDJD,
|
||||
}
|
||||
orderSettlement, err := a.OrderShoudSettlementService2(orderID)
|
||||
if err == nil {
|
||||
if orderSettlement != nil {
|
||||
updateOrderBySettleMent(order, orderSettlement)
|
||||
globals.SugarLogger.Debugf("updateOrderBySettleMent: %v , %v", order.NewEarningPrice, order.TotalShopMoney)
|
||||
err = partner.CurOrderManager.UpdateOrderFields(order, []string{ /*"WaybillTipMoney", */ "TotalShopMoney", "PmSubsidyMoney", "NewEarningPrice"})
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
a := getAPI(vendorOrgCode)
|
||||
if afsMsgMap[msg.MsgURL] {
|
||||
retVal = c.OnAfsOrderMsg(a, msg)
|
||||
} else {
|
||||
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)
|
||||
retVal = jdapi.Err2CallbackResponse(c.updateOrderFinancialInfo(a, msg.BillID), status.VendorStatus)
|
||||
} else {
|
||||
// 新订单事件,与订单状态有点冲突
|
||||
if jdapi.StatusIDNewOrder == msg.StatusID {
|
||||
retVal = c.onOrderNew(a, msg, status)
|
||||
} else if jdapi.OrderStatusAdjust == msg.StatusID {
|
||||
retVal = c.onOrderAdjust(a, msg, status)
|
||||
} else {
|
||||
if msg.StatusID == jdapi.OrderStatusAddComment || msg.StatusID == jdapi.OrderStatusModifyComment {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.onOrderComment2(a, msg)
|
||||
})
|
||||
}
|
||||
// if msg.StatusID == jdapi.OrderStatusVenderAgreeCancel {
|
||||
// order := &model.GoodsOrder{
|
||||
// VendorOrgCode: vendorOrgCode,
|
||||
// VendorOrderID: msg.BillID,
|
||||
// }
|
||||
// err2 := c.PickupGoods(order, false, jxcontext.AdminCtx.GetUserName())
|
||||
// if err2 != nil {
|
||||
// globals.SugarLogger.Warnf("京东取消拣货:%v", err2)
|
||||
// }
|
||||
// }
|
||||
err := partner.CurOrderManager.OnOrderStatusChanged(vendorOrgCode, status)
|
||||
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) OnOrderInfoChangeMsg(vendorOrgCode string, msg *jdapi.CallbackOrderInfoChangeMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderInfoChangeMsg(vendorOrgCode, msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderInfoChangeMsg(vendorOrgCode string, msg *jdapi.CallbackOrderInfoChangeMsg) (retVal *jdapi.CallbackResponse) {
|
||||
db := dao.GetDB()
|
||||
order, err := dao.GetSimpleOrder(db, msg.BillID)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debugf("onOrderInfoChangeMsg msg:%v", utils.Format4Output(msg, false))
|
||||
if msg.BuyerFullAddress != "" {
|
||||
order.ConsigneeAddress = msg.BuyerFullAddress
|
||||
}
|
||||
if msg.BuyerFullName != "" {
|
||||
order.ConsigneeName = msg.BuyerFullName
|
||||
}
|
||||
if msg.BuyerMobile != "" {
|
||||
order.ConsigneeMobile = msg.BuyerMobile
|
||||
}
|
||||
if msg.BuyerLat != "" {
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(msg.BuyerLat))
|
||||
}
|
||||
if msg.BuyerLng != "" {
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(msg.BuyerLng))
|
||||
}
|
||||
if msg.OrderBuyerRemark != "" {
|
||||
order.BuyerComment = msg.OrderBuyerRemark
|
||||
}
|
||||
_, err = dao.UpdateEntity(db, order, "ConsigneeAddress", "ConsigneeName", "ConsigneeMobile", "ConsigneeLat", "ConsigneeLng", "BuyerComment")
|
||||
weixinmsg.NotifyOrderChanged(order)
|
||||
}
|
||||
return jdapi.SuccessResponse
|
||||
}
|
||||
|
||||
func updateOrderBySettleMent(order *model.GoodsOrder, orderSettlement *jdapi.OrderSettlementInfo) {
|
||||
if orderSettlement != nil {
|
||||
order.TotalShopMoney = orderSettlement.SettlementAmount
|
||||
order.PmSubsidyMoney = orderSettlement.PlatOrderGoodsDiscountMoney + orderSettlement.PlatSkuGoodsDiscountMoney
|
||||
if order.TotalShopMoney > 0 {
|
||||
if jxutils.GetSaleStoreIDFromOrder(order) != 0 {
|
||||
storeDetail, err := partner.CurOrderManager.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
|
||||
if storeDetail != nil && err == nil {
|
||||
jxutils.RefreshOrderEarningPrice2(order, storeDetail.PayPercentage)
|
||||
}
|
||||
} else {
|
||||
order2, err := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
|
||||
if order2 != nil && err == nil {
|
||||
storeDetail, err := partner.CurOrderManager.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order2), order.VendorID)
|
||||
if storeDetail != nil && err == nil {
|
||||
jxutils.RefreshOrderEarningPrice2(order, storeDetail.PayPercentage)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
order.NewEarningPrice = order.EarningPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) getOrder(a *jdapi.API, orderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) {
|
||||
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 = a.QuerySingleOrder(orderID)
|
||||
if err == nil {
|
||||
order = c.Map2Order(orderMap)
|
||||
realMobile, _ = a.GetRealMobile4Order(orderID, order.VendorStoreID)
|
||||
if realMobile != "" {
|
||||
order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile)
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
orderSettlement, _ = a.OrderShoudSettlementService2(orderID)
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1})
|
||||
task.Run()
|
||||
_, err = task.GetResult(0)
|
||||
if order != nil && orderSettlement != nil {
|
||||
updateOrderBySettleMent(order, orderSettlement)
|
||||
err = partner.CurOrderManager.UpdateOrderFields(order, []string{"NewEarningPrice"})
|
||||
}
|
||||
return order, orderMap, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) {
|
||||
order, _, err = c.getOrder(getAPI(vendorOrgCode), orderID)
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
|
||||
order, err := getAPI(vendorOrgCode).QuerySingleOrder2(vendorOrderID)
|
||||
if err == nil {
|
||||
status = getStatusFromVendorStatus(utils.Int2Str(order.OrderStatus))
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
return Map2Order(orderData)
|
||||
}
|
||||
|
||||
func 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为空
|
||||
statusTimeField = "orderStartTime"
|
||||
}
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDJD,
|
||||
VendorStoreID: utils.Interface2String(result["produceStationNo"]),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["produceStationNoIsv"]), 0)),
|
||||
StoreName: utils.Interface2String(result["produceStationName"]),
|
||||
VendorUserID: utils.Interface2String(result["buyerPin"]),
|
||||
ConsigneeName: utils.Interface2String(result["buyerFullName"]),
|
||||
ConsigneeMobile: jxutils.FormalizeMobile(utils.Interface2String(result["buyerMobile"])),
|
||||
ConsigneeAddress: utils.Interface2String(result["buyerFullAddress"]),
|
||||
CoordinateType: model.CoordinateTypeMars,
|
||||
BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["orderBuyerRemark"])),
|
||||
ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["orderPreEndDeliveryTime"]), utils.DefaultTimeValue),
|
||||
PickDeadline: utils.Str2TimeWithDefault(utils.Interface2String(result["pickDeadline"]), utils.DefaultTimeValue), // 813951615000022 pickDeadline为空
|
||||
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["orderStatus"])),
|
||||
OrderSeq: int(utils.MustInterface2Int64(result["orderNum"])),
|
||||
StatusTime: utils.Str2Time(result[statusTimeField].(string)),
|
||||
OrderCreatedAt: utils.Str2Time(result[statusTimeField].(string)),
|
||||
// OrderFinishedAt: utils.Str2Time(result["orderStatusTime"].(string)),
|
||||
OriginalData: string(utils.MustMarshal(result)),
|
||||
ActualPayPrice: utils.MustInterface2Int64(result["orderBuyerPayableMoney"]),
|
||||
BaseFreightMoney: utils.Interface2Int64WithDefault(result["orderBaseFreightMoney"], 0),
|
||||
DistanceFreightMoney: utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0),
|
||||
DeliveryType: deliveryTypeMap[int(utils.Str2Int64WithDefault(utils.Interface2String(result["deliveryCarrierNo"]), 0))],
|
||||
VendorOrgCode: utils.Interface2String(result["orgCode"]),
|
||||
}
|
||||
if orderInvoice, ok := result["orderInvoice"].(map[string]interface{}); ok && orderInvoice != nil {
|
||||
order.InvoiceTitle = utils.Interface2String(orderInvoice["invoiceTitle"])
|
||||
order.InvoiceTaxerID = utils.Interface2String(orderInvoice["invoiceDutyNo"])
|
||||
order.InvoiceEmail = utils.Interface2String(orderInvoice["invoiceMail"])
|
||||
}
|
||||
order.Status = getStatusFromVendorStatus(order.VendorStatus)
|
||||
businessTage := utils.Interface2String(result["businessTag"])
|
||||
if strings.Index(businessTage, "dj_aging_immediately") >= 0 {
|
||||
order.BusinessType = model.BusinessTypeImmediate
|
||||
} else {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
}
|
||||
coordinateType := utils.Interface2Int64WithDefault(result["buyerCoordType"], 1)
|
||||
originalLng := utils.MustInterface2Float64(result["buyerLng"])
|
||||
originalLat := utils.MustInterface2Float64(result["buyerLat"])
|
||||
if coordinateType == 1 {
|
||||
lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysGPS)
|
||||
if err2 == nil {
|
||||
originalLng = lng
|
||||
originalLat = lat
|
||||
} else {
|
||||
// 如果没有转成功,保留原始数据
|
||||
order.CoordinateType = model.CoordinateTypeGPS
|
||||
}
|
||||
}
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
|
||||
discounts, _ := result["discount"].([]interface{})
|
||||
for _, v := range discounts {
|
||||
discount := v.(map[string]interface{})
|
||||
order.DiscountMoney += utils.Interface2Int64WithDefault(discount["discountPrice"], 0)
|
||||
}
|
||||
for _, product2 := range result["product"].([]interface{}) {
|
||||
product := product2.(map[string]interface{})
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDJD,
|
||||
Count: int(utils.MustInterface2Int64(product["skuCount"])),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["skuIdIsv"]), 0)),
|
||||
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"]),
|
||||
}
|
||||
if jdPromotionType := int(utils.MustInterface2Int64(product["promotionType"])); jdPromotionType != 0 && jdPromotionType != jdapi.PromotionTypeNormal {
|
||||
sku.StoreSubName = utils.Int2Str(jdPromotionType)
|
||||
}
|
||||
if skuCostumeProperty, ok := product["skuCostumeProperty"]; ok {
|
||||
sku.SkuName += skuCostumeProperty.(string)
|
||||
}
|
||||
if isGift, ok := product["isGift"].(bool); ok && isGift {
|
||||
sku.SkuType = 1
|
||||
}
|
||||
order.Skus = append(order.Skus, sku)
|
||||
}
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
return order
|
||||
}
|
||||
|
||||
//
|
||||
func (c *PurchaseHandler) onOrderNew(a *jdapi.API, msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) (response *jdapi.CallbackResponse) {
|
||||
globals.SugarLogger.Debugf("onOrderNew orderID:%s", msg.BillID)
|
||||
order, orderMap, err := c.getOrder(a, msg.BillID)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debugf("onOrderNew2 orderID:%s", msg.BillID)
|
||||
if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.OnOrderDetail(a, orderMap, partner.CreatedPeration)
|
||||
})
|
||||
}
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(err, "jd onOrderNew")
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onOrderAdjust(a *jdapi.API, msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) *jdapi.CallbackResponse {
|
||||
order, orderMap, err := c.getOrder(a, msg.BillID)
|
||||
if err == nil {
|
||||
err = partner.CurOrderManager.OnOrderAdjust(order, orderStatus)
|
||||
if err == nil {
|
||||
utils.CallFuncAsync(func() {
|
||||
c.OnOrderDetail(a, orderMap, partner.UpdatedPeration)
|
||||
})
|
||||
}
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(err, "jd onOrderAdjust")
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.BillID,
|
||||
VendorID: model.VendorIDJD,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.BillID,
|
||||
RefVendorID: model.VendorIDJD,
|
||||
VendorStatus: msg.StatusID,
|
||||
StatusTime: utils.Str2Time(msg.Timestamp),
|
||||
Remark: msg.Remark,
|
||||
}
|
||||
if msg.MsgURL == jdapi.CallbackMsgOrderAddTips {
|
||||
orderStatus.VendorStatus = jdapi.CallbackMsgOrderAddTips
|
||||
}
|
||||
orderStatus.Status = getStatusFromVendorStatus(orderStatus.VendorStatus)
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) postFakeMsg(vendorOrgCode, vendorOrderID, vendorStatus string) {
|
||||
msg := &jdapi.CallbackOrderMsg{
|
||||
CallbackMsg: &jdapi.CallbackMsg{
|
||||
AppKey: getAPI(vendorOrgCode).GetAppKey(),
|
||||
},
|
||||
BillID: vendorOrderID,
|
||||
StatusID: vendorStatus,
|
||||
Timestamp: utils.Time2Str(time.Now()),
|
||||
}
|
||||
utils.CallFuncAsync(func() {
|
||||
OnOrderMsg(msg)
|
||||
})
|
||||
}
|
||||
|
||||
// IPurchasePlatformHandler
|
||||
func getStatusFromVendorStatus(vendorStatus string) int {
|
||||
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
|
||||
return status
|
||||
}
|
||||
return model.OrderStatusUnknown
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).OrderAcceptOperate(order.VendorOrderID, isAcceptIt, userName)
|
||||
if isAcceptIt && err == nil {
|
||||
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.StatusIDWaitOutStore)
|
||||
}
|
||||
} else {
|
||||
if isAcceptIt {
|
||||
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.StatusIDWaitOutStore)
|
||||
} else {
|
||||
|
||||
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.OrderStatusCanceled)
|
||||
}
|
||||
}
|
||||
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.EnableJdStoreWrite {
|
||||
_, err = getAPI(order.VendorOrgCode).OrderJDZBDelivery(order.VendorOrderID, userName)
|
||||
} else {
|
||||
c.postFakeMsg(order.VendorOrgCode, order.VendorOrderID, jdapi.OrderStatusFinishedPickup)
|
||||
}
|
||||
if err == nil {
|
||||
orderSettlement, _ := getAPI(order.VendorOrgCode).OrderShoudSettlementService2(order.VendorOrderID)
|
||||
updateOrderBySettleMent(order, orderSettlement)
|
||||
globals.SugarLogger.Debugf("jd PickupGoods, %v", order.NewEarningPrice)
|
||||
err = partner.CurOrderManager.UpdateOrderFields(order, []string{"NewEarningPrice"})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).ReceiveFailedAudit(order.VendorOrderID, isAcceptIt, ctx.GetUserName(), "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).UrgeDispatching(order.VendorOrderID, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).ConfirmReceiveGoods(order.VendorOrderID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(order.VendorOrgCode).ModifySellerDelivery(order.VendorOrderID, userName)
|
||||
if err != nil {
|
||||
if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver failed with error:%v try get current status", err)
|
||||
if order2, err2 := c.GetOrder(order.VendorOrgCode, order.VendorOrderID); err2 == nil {
|
||||
var mapData map[string]interface{}
|
||||
if err2 = utils.UnmarshalUseNumber([]byte(order2.OriginalData), &mapData); err2 == nil {
|
||||
if utils.Interface2String(mapData["deliveryCarrierNo"]) == "2938" { // 当前已经是自送状态了
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(order.VendorOrgCode).DeliveryEndOrder(order.VendorOrderID, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(order.VendorOrgCode).OrderSerllerDelivery(order.VendorOrderID, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 京东送达接口都是一样的
|
||||
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("jd SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = c.Swtich2SelfDelivered(order, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
|
||||
mobile, err = getAPI(order.VendorOrgCode).GetRealMobile4Order(order.VendorOrderID, order.VendorStoreID)
|
||||
return mobile, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).OrderCancelOperate(order.VendorOrderID, isAgree, ctx.GetUserName(), reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err1 := c.Swtich2SelfDeliver(order, ctx.GetUserName())
|
||||
if err = getAPI(order.VendorOrgCode).CancelAndRefund(order.VendorOrderID, ctx.GetUserName(), reason); err != nil {
|
||||
if err1 != nil {
|
||||
err = fmt.Errorf("取消订单失败,京东取消订单是要先转为自送再处理,转自送失败:%v", err1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
order = jxutils.RemoveSkuFromOrder(order, removedSkuList)
|
||||
var oaosAdjustDTOList []*jdapi.OAOSAdjustDTO
|
||||
dtoMap := make(map[int]*jdapi.OAOSAdjustDTO)
|
||||
for _, sku := range order.Skus {
|
||||
skuID := jxutils.GetSkuIDFromOrderSku(sku)
|
||||
if dtoMap[skuID] == nil {
|
||||
dtoMap[skuID] = &jdapi.OAOSAdjustDTO{
|
||||
OutSkuID: utils.Int2Str(skuID),
|
||||
SkuCount: sku.Count,
|
||||
}
|
||||
oaosAdjustDTOList = append(oaosAdjustDTOList, dtoMap[skuID])
|
||||
} else {
|
||||
dtoMap[skuID].SkuCount += sku.Count
|
||||
}
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).AdjustOrder(order.VendorOrderID, ctx.GetUserName(), reason, oaosAdjustDTOList)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
|
||||
if utils.IsTimeZero(queryDate) {
|
||||
return nil, fmt.Errorf("queryDate必须指定")
|
||||
}
|
||||
fromDate := utils.Time2Date(queryDate)
|
||||
toDate := fromDate.Add(24*time.Hour - 1)
|
||||
queryParam := &jdapi.OrderQueryParam{
|
||||
OrderPurchaseTimeBegin: utils.Time2Str(fromDate),
|
||||
OrderPurchaseTimeEnd: utils.Time2Str(toDate),
|
||||
PageNo: jdapi.AllPage,
|
||||
}
|
||||
if vendorStoreID != "" {
|
||||
queryParam.DeliveryStationNo = vendorStoreID
|
||||
}
|
||||
orderList, _, err := getAPI(vendorOrgCode).OrderQuery2(queryParam)
|
||||
if err == nil {
|
||||
vendorOrderIDs = make([]string, len(orderList))
|
||||
for k, v := range orderList {
|
||||
vendorOrderIDs[k] = utils.Int64ToStr(v.OrderID)
|
||||
}
|
||||
}
|
||||
return vendorOrderIDs, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) {
|
||||
orderInfo, err := getAPI(vendorOrgCode).QuerySingleOrder2(vendorOrderID)
|
||||
if err == nil {
|
||||
tipFee = int64(orderInfo.Tips)
|
||||
}
|
||||
return tipFee, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) {
|
||||
curTipFee, err := c.GetWaybillTip(ctx, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2)
|
||||
if err == nil {
|
||||
if tipFee2Add := tipFee - curTipFee; tipFee2Add > 0 {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).OrderAddTips(vendorOrderID, int(tipFee2Add), ctx.GetUserName())
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetSelfTakeCode(ctx *jxcontext.Context, order *model.GoodsOrder) (selfTakeCode string, err error) {
|
||||
orderTrackList, err := getAPI(order.VendorOrgCode).GetByOrderNoForOaos(order.VendorOrderID)
|
||||
if err == nil {
|
||||
for _, v := range orderTrackList {
|
||||
if v.TagCode == 180 {
|
||||
searchResult := selfTakeCodeReg.FindStringSubmatch(v.MsgContent)
|
||||
if searchResult != nil && len(searchResult[1]) > 0 {
|
||||
selfTakeCode = searchResult[1]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return selfTakeCode, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(order.VendorOrgCode).CheckSelfPickCode(selfTakeCode, order.VendorOrderID, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
AfsVendorStatus2StatusMap = map[string]int{
|
||||
jdapi.AfsServiceStateWaiting4Audit: model.AfsOrderStatusWait4Approve, // 需要审核
|
||||
|
||||
jdapi.AfsServiceStateWaiting4CSFeedback: model.AfsOrderStatusNew,
|
||||
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.AfsReasonTypeGoodsAbsent: model.AfsReasonTypeGoodsAbsent,
|
||||
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(a *jdapi.API, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
retVal = c.onAfsOrderMsg(a, msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onAfsOrderMsg(a *jdapi.API, msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
afsInfo, err := a.GetAfsService2(msg.BillID)
|
||||
if err == nil {
|
||||
status := c.callbackAfsMsg2Status(msg, afsInfo)
|
||||
if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 {
|
||||
return nil
|
||||
}
|
||||
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),
|
||||
VendorOrgCode: afsInfo.VenderID,
|
||||
}
|
||||
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,
|
||||
}
|
||||
if x.PromotionType != 0 && x.PromotionType != jdapi.PromotionTypeNormal {
|
||||
orderSku.StoreSubName = utils.Int2Str(x.PromotionType)
|
||||
}
|
||||
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 = getAPI(order.VendorOrgCode).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 = getAPI(order.VendorOrgCode).ConfirmReceipt(order.AfsOrderID, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func orderSkus2AfsSkus(refundSkuList []*model.OrderSku) (list []*jdapi.VenderAfsSkuDTO) {
|
||||
for _, v := range refundSkuList {
|
||||
actType := int(utils.Str2Int64WithDefault(v.StoreSubName, 0))
|
||||
if actType == 0 { //!(actType == jdapi.PromotionTypeOverflowGiveGift || actType == jdapi.PromotionTypeBuyGiveGift) {
|
||||
actType = 1
|
||||
}
|
||||
list = append(list, &jdapi.VenderAfsSkuDTO{
|
||||
SkuID: utils.Str2Int64(v.VendorSkuID),
|
||||
SkuCount: v.Count,
|
||||
PromotionType: actType,
|
||||
})
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// 发起全款退款
|
||||
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
return c.PartRefundOrder(ctx, order, order.Skus, reason)
|
||||
}
|
||||
|
||||
// 发起部分退款
|
||||
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(order.VendorOrgCode).AfsSubmit(order.VendorOrderID, ctx.GetUserName(), utils.Int2Str(jdapi.AfsReasonTypeWrongGoods), reason, "", order.ConsigneeName, order.ConsigneeMobile, order.ConsigneeAddress, orderSkus2AfsSkus(refundSkuList))
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
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/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
JDDJ_BAD_COMMENTS_MAX_MODIFY_TIME = 72 // 小时
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) onOrderComment2(a *jdapi.API, msg *jdapi.CallbackOrderMsg) (err error) {
|
||||
intOrderID := utils.Str2Int64(msg.BillID)
|
||||
result, err := a.GetCommentByOrderId2(intOrderID)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debugf("onOrderComment comment:%s", utils.Format4Output(result, true))
|
||||
orderCommend := &model.OrderComment{
|
||||
VendorOrderID: utils.Int64ToStr(result.OrderID),
|
||||
VendorID: model.VendorIDJD,
|
||||
UserCommentID: "",
|
||||
VendorStoreID: utils.Int64ToStr(result.StoreID),
|
||||
TagList: string(utils.MustMarshal(result.VenderTags)),
|
||||
Score: int8(result.Score4),
|
||||
Content: result.Score4Content,
|
||||
ModifyDuration: JDDJ_BAD_COMMENTS_MAX_MODIFY_TIME,
|
||||
OriginalMsg: string(utils.MustMarshal(result)),
|
||||
}
|
||||
if result.CreateTime != nil {
|
||||
orderCommend.CommentCreatedAt = result.CreateTime.GoTime()
|
||||
}
|
||||
if result.OrgCommentContent != "" {
|
||||
orderCommend.IsReplied = 1
|
||||
}
|
||||
err = partner.CurOrderManager.OnOrderComments([]*model.OrderComment{orderCommend})
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("onOrderComment orderID:%s failed with error:%v", msg.BillID, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).OrgReplyComment(utils.Str2Int64(orderComment.VendorOrderID), orderComment.VendorStoreID, replyComment, ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
)
|
||||
|
||||
func TestSwitch2SelfDeliver(t *testing.T) {
|
||||
orderID := "817540316000041"
|
||||
if order, err := partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil {
|
||||
// globals.SugarLogger.Debug(order)
|
||||
if err = CurPurchaseHandler.Swtich2SelfDeliver(order, ""); err == nil {
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrder(t *testing.T) {
|
||||
_, err := CurPurchaseHandler.GetOrder("", "815536199000222")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrderStatus(t *testing.T) {
|
||||
status, err := CurPurchaseHandler.GetOrderStatus("", "929203144000041")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(status)
|
||||
}
|
||||
|
||||
func TestListOrders(t *testing.T) {
|
||||
result, err := CurPurchaseHandler.ListOrders(jxcontext.AdminCtx, "", nil, time.Now(), "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestGetSelfTakeCode(t *testing.T) {
|
||||
order, err := partner.CurOrderManager.LoadOrder("921160248000222", model.VendorIDJD)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
selfTakeCode, err := CurPurchaseHandler.GetSelfTakeCode(jxcontext.AdminCtx, order)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(selfTakeCode)
|
||||
}
|
||||
@@ -1,480 +0,0 @@
|
||||
package jd
|
||||
|
||||
// 这里函数取得的信息,除了与自身实体相关的ID(比如PARENT ID),都已经转换成了本地ID了
|
||||
|
||||
// type tSkuInfoExt struct {
|
||||
// model.SkuName
|
||||
// JdCatID int64 `orm:"column(jd_cat_id)"` // 商家类别
|
||||
// JdCategoryID int `orm:"column(jd_category_id)"` // 到家类别
|
||||
// SkuCatID int64 `orm:"column(sku_cat_id)"` // 商家特殊类别
|
||||
// Comment string `orm:"size(255)" json:"comment"`
|
||||
// }
|
||||
|
||||
// var (
|
||||
// skuAddParamsKeyMap = map[string]int{
|
||||
// jdapi.KeyUpcCode: 1,
|
||||
// }
|
||||
// )
|
||||
|
||||
// func (p *PurchaseHandler) CreateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) (err error) {
|
||||
// var jdPid int64
|
||||
// if cat.ParentID != 0 {
|
||||
// pCat := &model.SkuCategory{}
|
||||
// pCat.ID = cat.ParentID
|
||||
// if err = dao.GetEntity(db, pCat); err == nil {
|
||||
// jdPid = pCat.JdID
|
||||
// } else {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// result, err2 := getAPI("").AddShopCategory(jdPid, cat.Name, int(cat.Level), cat.Seq, userName)
|
||||
// if err = err2; err == nil {
|
||||
// if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
|
||||
// cat.JdID = jdID
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// cat.JdID = jxutils.GenFakeID()
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
// func (p *PurchaseHandler) UpdateCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error {
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// return getAPI("").UpdateShopCategory(cat.JdID, cat.Name)
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func (p *PurchaseHandler) DeleteCategory(db *dao.DaoDB, cat *model.SkuCategory, userName string) error {
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// return getAPI("").DelShopCategory(cat.JdID)
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func (p *PurchaseHandler) ReorderCategories(db *dao.DaoDB, parentCatID int, userName string) (err error) {
|
||||
// var parentJDID int64
|
||||
// if parentCatID != 0 {
|
||||
// cat := &model.SkuCategory{}
|
||||
// cat.ID = parentCatID
|
||||
// if err = dao.GetEntity(db, cat); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// parentJDID = cat.JdID
|
||||
// }
|
||||
// var cats []*model.SkuCategory
|
||||
// if err = dao.GetRows(db, &cats, `
|
||||
// SELECT *
|
||||
// FROM sku_category
|
||||
// WHERE parent_id = ? AND deleted_at = ?
|
||||
// ORDER BY seq`, parentCatID, utils.DefaultTimeValue); err == nil {
|
||||
// jdCatIDs := make([]int64, len(cats))
|
||||
// for k, v := range cats {
|
||||
// jdCatIDs[k] = v.JdID
|
||||
// }
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// err = getAPI("").ChangeShopCategoryOrder(parentJDID, jdCatIDs)
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
// 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.*, IF(t2.jd_category_id > 0, t2.jd_category_id, t3.jd_category_id) jd_category_id,
|
||||
// t3.jd_id jd_cat_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
|
||||
// LEFT JOIN sku_category t4 ON t1.category_id = t4.id
|
||||
// WHERE t1.id = ?
|
||||
// `, sku.ID)
|
||||
// if err == nil {
|
||||
// shopCategories := []int64{skuInfoExt.JdCatID}
|
||||
// // SPU只支持SPU的商家分类,不支持单独SKU的,去除SKU的分类
|
||||
// // if skuInfoExt.SkuCatID != 0 {
|
||||
// // shopCategories = append(shopCategories, skuInfoExt.SkuCatID)
|
||||
// // }
|
||||
// if skuInfoExt.JdCategoryID == 0 {
|
||||
// skuInfoExt.JdCategoryID = getDefJdCategoryID()
|
||||
// }
|
||||
// if skuInfoExt.BrandID == 0 {
|
||||
// skuInfoExt.BrandID = DefBrandID
|
||||
// }
|
||||
// addParams := map[string]interface{}{}
|
||||
|
||||
// if skuInfoExt.IsGlobal == 0 { //如果不是全国可售,要查可售区域
|
||||
// sellPlaces, err2 := dao.GetSellCities(db, skuInfoExt.ID, model.VendorIDJD)
|
||||
// if err = err2; err == nil && len(sellPlaces) > 0 {
|
||||
// sellCites := make([]int, len(sellPlaces))
|
||||
// for k, v := range sellPlaces {
|
||||
// sellCites[k] = v.JdCode
|
||||
// }
|
||||
// addParams["sellCities"] = sellCites
|
||||
// }
|
||||
// }
|
||||
// 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, jdapi.MaxSkuNameCharCount)
|
||||
// skuPrice := jxutils.CaculateSkuPrice(skuInfoExt.Price, sku.SpecQuality, sku.SpecUnit, skuInfoExt.Unit)
|
||||
// if skuInfoExt.Upc != "" {
|
||||
// addParams[jdapi.KeyUpcCode] = skuInfoExt.Upc
|
||||
// }
|
||||
// result, err2 := handler(&skuInfoExt, skuPrice, skuName, shopCategories, addParams)
|
||||
// if err = err2; err == nil {
|
||||
// if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
|
||||
// sku.JdID = jdID
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
// func (p *PurchaseHandler) CreateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
|
||||
// return p.cuSku(db, sku, func(skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (vendorSkuID string, err error) {
|
||||
// if skuExt.IsSpu == 0 {
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// vendorSkuID, err = getAPI("").AddSku(utils.Int2Str(sku.ID), skuExt.JdCategoryID, shopCategories, skuExt.BrandID, skuName, price, jxutils.IntWeight2Float(sku.Weight), jxutils.BatchString2Slice(skuExt.Img, skuExt.Img2), jxStatus2jdStatus(sku.Status), true, addParams)
|
||||
// if err != nil {
|
||||
// if jdSkuID := jdapi.GetJdSkuIDFromError(err); jdSkuID > 0 {
|
||||
// vendorSkuID = utils.Int64ToStr(jdSkuID)
|
||||
// err = nil
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// vendorSkuID = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
// }
|
||||
// } else {
|
||||
// vendorSkuID, err = p.syncSkuNameAsSpu(db, sku, skuExt, price, skuName, shopCategories, addParams)
|
||||
// }
|
||||
// return vendorSkuID, err
|
||||
// })
|
||||
// }
|
||||
|
||||
// // func (p *PurchaseHandler) ReadSku(ctx *jxcontext.Context, vendorOrgCode, vendorSkuID string) (skuNameExt *model.SkuNameExt, err error) {
|
||||
// // jdSkuID := utils.Str2Int64(vendorSkuID)
|
||||
// // a := getAPI(vendorOrgCode)
|
||||
// // skuList, _, err := a.QuerySkuInfos(&jdapi.QuerySkuParam{
|
||||
// // SkuID: jdSkuID,
|
||||
// // })
|
||||
// // if err == nil {
|
||||
// // if len(skuList) >= 1 {
|
||||
// // skuNameExt = &model.SkuNameExt{}
|
||||
// // if imgList, err2 := a.QueryListBySkuIds(&jdapi.QueryListBySkuIdsParam{
|
||||
// // SkuIDs: []int64{jdSkuID},
|
||||
// // }); err2 == nil && len(imgList) > 0 {
|
||||
// // skuNameExt.Img = imgList[0].SourceImgURL
|
||||
// // }
|
||||
// // sku := skuList[0]
|
||||
// // prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(sku.SkuName)
|
||||
// // if name == "" {
|
||||
// // name = sku.SkuName
|
||||
// // unit = "份"
|
||||
// // specUnit = "g"
|
||||
// // }
|
||||
// // skuNameExt.Prefix = prefix
|
||||
// // skuNameExt.Name = name
|
||||
// // skuNameExt.Unit = unit
|
||||
// // skuNameExt.Price = sku.SkuPrice
|
||||
// // skuNameExt.Skus = []*model.SkuWithVendor{
|
||||
// // &model.SkuWithVendor{
|
||||
// // Sku: &model.Sku{
|
||||
// // SpecQuality: specQuality,
|
||||
// // SpecUnit: specUnit,
|
||||
// // Weight: jxutils.FloatWeight2Int(float32(sku.Weight)),
|
||||
// // JdID: sku.SkuID,
|
||||
// // Status: jdStatus2jxStatus(sku.FixedStatus),
|
||||
// // Comment: comment,
|
||||
// // },
|
||||
// // },
|
||||
// // }
|
||||
// // skuNameExt.Skus[0].ID = int(utils.Str2Int64(sku.OutSkuID))
|
||||
|
||||
// // db := dao.GetDB()
|
||||
// // shopCategories := sku.ShopCategories
|
||||
// // if len(shopCategories) > 0 {
|
||||
// // skuCat := &model.SkuCategory{}
|
||||
// // skuCat.JdID = shopCategories[0]
|
||||
// // if dao.GetEntity(db, skuCat, "JdID") == nil {
|
||||
// // skuNameExt.CategoryID = skuCat.ID
|
||||
// // }
|
||||
// // }
|
||||
// // sellCities := sku.SellCities
|
||||
// // for _, v := range sellCities {
|
||||
// // if v == 0 {
|
||||
// // skuNameExt.IsGlobal = 1
|
||||
// // }
|
||||
// // }
|
||||
// // if len(sellCities) == 0 || skuNameExt.IsGlobal == 1 {
|
||||
// // skuNameExt.IsGlobal = 1
|
||||
// // } else {
|
||||
// // var places []*model.Place
|
||||
// // if err = dao.GetRows(db, &places, "SELECT * FROM place WHERE jd_code IN ("+dao.GenQuestionMarks(len(sellCities))+") AND level = 2", sellCities); err == nil {
|
||||
// // skuNameExt.Places = make([]int, len(places))
|
||||
// // for k, v := range places {
|
||||
// // skuNameExt.Places[k] = v.Code
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// // } else {
|
||||
// // err = partner.ErrCanNotFindItem
|
||||
// // }
|
||||
// // }
|
||||
// // return skuNameExt, err
|
||||
// // }
|
||||
|
||||
// func (p *PurchaseHandler) UpdateSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
|
||||
// return p.cuSku(db, sku, func(skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (vendorSkuID string, err error) {
|
||||
// params := utils.MergeMaps(addParams)
|
||||
// params[jdapi.KeyCategoryId] = skuExt.JdCategoryID
|
||||
// params[jdapi.KeyShopCategories] = shopCategories
|
||||
// params[jdapi.KeyBrandId] = skuExt.BrandID
|
||||
// params[jdapi.KeySkuName] = skuName
|
||||
// params[jdapi.KeyWeight] = jxutils.IntWeight2Float(sku.Weight)
|
||||
// params[jdapi.KeyImages] = jxutils.BatchString2Slice(skuExt.Img, skuExt.Img2)
|
||||
// params[jdapi.KeyFixedStatus] = jxStatus2jdStatus(sku.Status)
|
||||
// if skuExt.IsSpu == 0 {
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// vendorSkuID, err = getAPI("").UpdateSku(utils.Int2Str(sku.ID), params)
|
||||
// }
|
||||
// } else {
|
||||
// vendorSkuID, err = p.syncSkuNameAsSpu(db, sku, skuExt, price, skuName, shopCategories, addParams)
|
||||
// }
|
||||
// return vendorSkuID, err
|
||||
// })
|
||||
// }
|
||||
|
||||
// func (p *PurchaseHandler) DeleteSku(db *dao.DaoDB, sku *model.Sku, userName string) (err error) {
|
||||
// params := map[string]interface{}{
|
||||
// jdapi.KeyFixedStatus: jdapi.SkuFixedStatusDeleted,
|
||||
// }
|
||||
// sql := `
|
||||
// SELECT t2.*
|
||||
// FROM sku t1
|
||||
// JOIN sku_name t2 ON t1.name_id = t2.id
|
||||
// WHERE t1.id = ?
|
||||
// `
|
||||
// var skuExt tSkuInfoExt
|
||||
// err = dao.GetRow(db, &skuExt, sql, sku.ID)
|
||||
// if err == nil {
|
||||
// if skuExt.IsSpu == 0 {
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// _, err = getAPI("").UpdateSku(utils.Int2Str(sku.ID), params)
|
||||
// }
|
||||
// } else {
|
||||
// _, err = p.syncSkuNameAsSpu(db, sku, &skuExt, 0, "", nil, nil)
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // func (p *PurchaseHandler) RefreshAllSkusID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
|
||||
// // globals.SugarLogger.Debugf("jd RefreshAllSkusID")
|
||||
|
||||
// // db := dao.GetDB()
|
||||
// // var skuPairs []*jdapi.SkuIDPair
|
||||
// // const stepCount = 2
|
||||
|
||||
// // rootTask := tasksch.NewSeqTask("jd RefreshAllSkusID", ctx,
|
||||
// // func(rootTask *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
// // switch step {
|
||||
// // case 0:
|
||||
// // err = dao.GetRows(db, &skuPairs, `
|
||||
// // SELECT t1.id out_sku_id, t1.jd_id sku_id
|
||||
// // FROM sku t1
|
||||
// // WHERE t1.deleted_at = ?
|
||||
// // `, utils.DefaultTimeValue)
|
||||
// // default:
|
||||
// // taskName := "RefreshAllSkusID update id"
|
||||
// // if step != stepCount-1 {
|
||||
// // taskName = "RefreshAllSkusID update uuid"
|
||||
// // }
|
||||
// // task1 := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetBatchSize(jdapi.MaxBatchSize4BatchUpdateOutSkuId), ctx,
|
||||
// // func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// // skuPairs := make([]*jdapi.SkuIDPair, len(batchItemList))
|
||||
// // for k, v := range batchItemList {
|
||||
// // pair := v.(*jdapi.SkuIDPair)
|
||||
// // skuPairs[k] = &jdapi.SkuIDPair{
|
||||
// // SkuId: pair.SkuId,
|
||||
// // OutSkuId: pair.OutSkuId,
|
||||
// // }
|
||||
// // if step != stepCount-1 {
|
||||
// // skuPairs[k].OutSkuId = utils.GetUUID()
|
||||
// // }
|
||||
// // }
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(skuPairs, false))
|
||||
// // if globals.EnableJdStoreWrite {
|
||||
// // _, err = getAPI("").BatchUpdateOutSkuId(skuPairs)
|
||||
// // }
|
||||
// // return nil, err
|
||||
// // }, skuPairs)
|
||||
// // rootTask.AddChild(task1).Run()
|
||||
// // _, err = task1.GetResult(0)
|
||||
// // }
|
||||
// // return nil, err
|
||||
// // }, stepCount)
|
||||
// // tasksch.HandleTask(rootTask, parentTask, false).Run()
|
||||
// // if !isAsync {
|
||||
// // _, err = rootTask.GetResult(0)
|
||||
// // }
|
||||
// // return rootTask.ID, err
|
||||
// // }
|
||||
|
||||
// func splitAddParams(addParams map[string]interface{}) (spuAddParams, skuAddParams map[string]interface{}) {
|
||||
// if addParams != nil {
|
||||
// spuAddParams = make(map[string]interface{})
|
||||
// skuAddParams = make(map[string]interface{})
|
||||
// for key := range addParams {
|
||||
// if skuAddParamsKeyMap[key] == 1 {
|
||||
// skuAddParams[key] = addParams[key]
|
||||
// } else {
|
||||
// spuAddParams[key] = addParams[key]
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return spuAddParams, skuAddParams
|
||||
// }
|
||||
|
||||
// // 这个处理JD SPU,补丁形式
|
||||
// func (p *PurchaseHandler) syncSkuNameAsSpu(db *dao.DaoDB, sku *model.Sku, skuExt *tSkuInfoExt, price int, skuName string, shopCategories []int64, addParams map[string]interface{}) (vendorSkuID string, err error) {
|
||||
// // SPU的SKU NAME不需要规格信息
|
||||
// skuName = jxutils.ComposeSkuName(skuExt.Prefix, skuExt.Name, sku.Comment, "", 0, "", 0)
|
||||
// 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.IsEmptyID(skuNameJdID) && sku.JdSyncStatus&model.SyncFlagDeletedMask != 0 { // 删除SKU
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// err = getAPI("").UpdateSkuBaseInfo(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted))
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// updateFields := []string{}
|
||||
// if skuExt.JdSyncStatus&model.SyncFlagDeletedMask != 0 {
|
||||
// sql := `
|
||||
// SELECT COUNT(*) ct
|
||||
// FROM sku t1
|
||||
// WHERE t1.name_id = ? AND (t1.status <> ? OR t1.jd_sync_status <> 0)
|
||||
// `
|
||||
// var count struct {
|
||||
// Ct int
|
||||
// }
|
||||
// if err = dao.GetRow(db, &count, sql, sku.NameID, model.SkuStatusDeleted); err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// if count.Ct <= 1 && sku.JdSyncStatus&model.SyncFlagDeletedMask != 0 { // 1就是最后删的那个
|
||||
// updateFields = append(updateFields, model.FieldJdSyncStatus)
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// if err = getAPI("").UpdateSpu(utils.Int2Str(skuExt.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusOffline)); err == nil {
|
||||
// err = getAPI("").UpdateSpu(utils.Int2Str(skuExt.ID), utils.Params2Map(jdapi.KeyFixedStatus, jdapi.SkuFixedStatusDeleted))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if skuExt.JdSyncStatus&model.SyncFlagNewMask != 0 && jxutils.IsEmptyID(skuNameJdID) {
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// spuName := jxutils.ComposeSpuName(skuExt.Prefix, skuExt.Name, 0)
|
||||
// skus := []map[string]interface{}{
|
||||
// map[string]interface{}{
|
||||
// jdapi.KeyOutSkuId: utils.Int2Str(sku.ID),
|
||||
// jdapi.KeySkuName: skuName,
|
||||
// jdapi.KeyFixedStatus: jxStatus2jdStatus(sku.Status),
|
||||
// jdapi.KeySkuPrice: price,
|
||||
// jdapi.KeyWeight: jxutils.IntWeight2Float(sku.Weight),
|
||||
// jdapi.KeyIsSale: true,
|
||||
// jdapi.FakeKeySpecAttr: composeSkuSpec(sku.SpecQuality, sku.SpecUnit, skuExt.Unit),
|
||||
// },
|
||||
// }
|
||||
// skus[0] = utils.MergeMaps(skus[0], skuAddParams)
|
||||
// updateFields = append(updateFields, model.FieldJdSyncStatus)
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// vendorSpuID, skuPairs, err2 := getAPI("").AddSpu(utils.Int2Str(skuExt.ID), skuExt.JdCategoryID, shopCategories, skuExt.BrandID, spuName, []string{skuExt.Img}, jxStatus2jdStatus(skuExt.Status), spuAddParams, skus)
|
||||
// if err = err2; err == nil {
|
||||
// skuExt.JdID = vendorSpuID
|
||||
// // skuNameJdID = skuExt.JdID // 这个是故意去掉的,这样之后的首次SKU修改操作就会被忽略,下一条语句也就可以不用了
|
||||
// // sku.JdSyncStatus &= ^model.SyncFlagNewMask
|
||||
// vendorSkuID = utils.Int64ToStr(skuPairs[0].SkuId)
|
||||
// updateFields = append(updateFields, model.FieldJdID)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if skuExt.JdSyncStatus&model.SyncFlagModifiedMask != 0 {
|
||||
// params := utils.MergeMaps(map[string]interface{}{
|
||||
// jdapi.KeySpuName: jxutils.ComposeSpuName(skuExt.Prefix, skuExt.Name, 0),
|
||||
// jdapi.KeyShopCategories: shopCategories,
|
||||
// jdapi.KeyCategoryId: skuExt.JdCategoryID,
|
||||
// jdapi.KeyBrandId: skuExt.BrandID,
|
||||
// jdapi.KeyImages: []string{skuExt.Img},
|
||||
// jdapi.KeyFixedStatus: jxStatus2jdStatus(skuExt.Status),
|
||||
// }, spuAddParams)
|
||||
// updateFields = append(updateFields, model.FieldJdSyncStatus)
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// err = getAPI("").UpdateSpu(utils.Int2Str(skuExt.ID), params)
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// if skuExt.JdSyncStatus != 0 && len(updateFields) > 0 {
|
||||
// skuExt.JdSyncStatus = 0
|
||||
// _, err = dao.UpdateEntity(db, &skuExt.SkuName, updateFields...)
|
||||
// globals.SugarLogger.Debugf("syncSkuNameAsSpu4 sku.id=%d, skuName:%s, skuName:%s", sku.ID, skuExt.Name, utils.Format4Output(&skuExt.SkuName, false))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if err == nil && !jxutils.IsEmptyID(skuNameJdID) {
|
||||
// if sku.JdSyncStatus&model.SyncFlagNewMask != 0 { // 非首次新增SKU
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// vendorSkuID2, err2 := getAPI("").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)
|
||||
// if err = err2; err == nil {
|
||||
// vendorSkuID = utils.Int64ToStr(vendorSkuID2)
|
||||
// }
|
||||
// }
|
||||
// } else if sku.JdSyncStatus&model.SyncFlagModifiedMask != 0 {
|
||||
// params := make(map[string]interface{})
|
||||
// params[jdapi.KeySkuName] = skuName
|
||||
// params[jdapi.KeyImages] = []string{skuExt.Img}
|
||||
// params[jdapi.KeyFixedStatus] = jxStatus2jdStatus(sku.Status)
|
||||
// params[jdapi.KeyWeight] = jxutils.IntWeight2Float(sku.Weight)
|
||||
// params[jdapi.KeySkuPrice] = price
|
||||
// if globals.EnableJdStoreWrite {
|
||||
// err = getAPI("").UpdateSkuBaseInfo(utils.Int2Str(skuExt.ID), utils.Int2Str(sku.ID), utils.MergeMaps(params, skuAddParams))
|
||||
// if sku.JdSyncStatus&model.SyncFlagSpecMask != 0 {
|
||||
// skuIndex := sku.SkuIndex
|
||||
// if skuIndex > 0 {
|
||||
// saleAttrValue := composeSkuSpec(sku.SpecQuality, sku.SpecUnit, skuExt.Unit)
|
||||
// globals.SugarLogger.Debugf("syncSkuNameAsSpu outSuperId:%d, saleAttrId:%d, saleAttrValueId:%d, saleAttrValueName:%s", skuExt.ID, jdapi.SaleAttrIDBase, jdapi.SaleAttrValueIDBase+skuIndex-1, saleAttrValue)
|
||||
// err = getAPI("").UpdateSpuSaleAttr(utils.Int2Str(skuExt.ID), utils.Int2Str(jdapi.SaleAttrIDBase), "", utils.Int2Str(jdapi.SaleAttrValueIDBase+skuIndex-1), saleAttrValue)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// sku.JdSyncStatus = 0
|
||||
// }
|
||||
// }
|
||||
// return vendorSkuID, err
|
||||
// }
|
||||
|
||||
// func composeSkuSpec(specQuality float32, specUnit, unit string) string {
|
||||
// prefix := ""
|
||||
// if unit == model.SpecialUnit {
|
||||
// prefix = "约"
|
||||
// }
|
||||
// value := prefix + jxutils.ComposeSkuSpec(specQuality, specUnit)
|
||||
// suffix := "/" + unit
|
||||
// if utf8.RuneCountInString(value) <= 8-utf8.RuneCountInString(suffix) {
|
||||
// value += suffix
|
||||
// }
|
||||
// return value
|
||||
// }
|
||||
@@ -1,485 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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/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"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
const (
|
||||
DefBrandID = 35247
|
||||
|
||||
DefJdCategoryID = 20362
|
||||
DefJdCategoryID4Jxgy = 22410 // 其他国产水果
|
||||
)
|
||||
|
||||
func getDefJdCategoryID() int {
|
||||
if beego.BConfig.RunMode == "jxgy" {
|
||||
return DefJdCategoryID4Jxgy
|
||||
}
|
||||
return DefJdCategoryID
|
||||
}
|
||||
|
||||
func jdCat2Jx(jdCat *jdapi.CategoryInfo) (jxCat *partner.BareCategoryInfo) {
|
||||
return &partner.BareCategoryInfo{
|
||||
VendorCatID: utils.Int64ToStr(jdCat.Id),
|
||||
Level: jdCat.Level,
|
||||
Name: jdCat.Name,
|
||||
Seq: jdCat.Sort,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetAllCategories(ctx *jxcontext.Context, vendorOrgCode string) (cats []*partner.BareCategoryInfo, err error) {
|
||||
result, err := getAPI(vendorOrgCode).QueryCategoriesByOrgCode()
|
||||
if err == nil {
|
||||
catMap := make(map[int64]*partner.BareCategoryInfo)
|
||||
level := 1
|
||||
for {
|
||||
processedCount := 0
|
||||
for _, jdCat := range result {
|
||||
if jdCat.Level == level {
|
||||
processedCount++
|
||||
jxCat := jdCat2Jx(jdCat)
|
||||
if level == 1 {
|
||||
cats = append(cats, jxCat)
|
||||
} else {
|
||||
parentCat := catMap[jdCat.ParentId]
|
||||
if parentCat != nil {
|
||||
parentCat.Children = append(parentCat.Children, jxCat)
|
||||
}
|
||||
}
|
||||
catMap[jdCat.Id] = jxCat
|
||||
}
|
||||
}
|
||||
if processedCount == 0 {
|
||||
break
|
||||
}
|
||||
level++
|
||||
}
|
||||
}
|
||||
return cats, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("CreateCategory2 cat:%s", utils.Format4Output(cat, true))
|
||||
parentID := int64(0)
|
||||
if cat.Level != 1 {
|
||||
parentID = utils.Str2Int64(cat.ParentVendorCatID)
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
result, err2 := getAPI(cat.VendorOrgCode).AddShopCategory(parentID, cat.Name, int(cat.Level), cat.Seq, ctx.GetUserName())
|
||||
if err = err2; err == nil {
|
||||
if jdID := utils.Str2Int64WithDefault(result, 0); jdID != 0 {
|
||||
cat.VendorCatID = utils.Int64ToStr(jdID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cat.VendorCatID = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateCategory2(ctx *jxcontext.Context, cat *dao.SkuStoreCatInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("UpdateCategory2 cat:%s", utils.Format4Output(cat, true))
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(cat.VendorOrgCode).UpdateShopCategory(utils.Str2Int64(cat.VendorCatID), cat.Name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteCategory2(ctx *jxcontext.Context, vendorOrgCode, vendorCatID string) (err error) {
|
||||
globals.SugarLogger.Debugf("DeleteCategory2 vendorOrgCode:%s, vendorCatID:%s", vendorOrgCode, vendorCatID)
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).DelShopCategory(utils.Str2Int64(vendorCatID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ReorderCategories2(ctx *jxcontext.Context, vendorOrgCode, vendorParentCatID string, vendorCatIDList []string) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).ChangeShopCategoryOrder(utils.Str2Int64WithDefault(vendorParentCatID, 0), utils.StringSlice2Int64(vendorCatIDList))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) getVendorCategories(level int, pid int64) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
// 得到平台的分类,不需要指定分账号
|
||||
cats, err := api.JdAPI.QueryChildCategoriesForOP(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, v := range cats {
|
||||
if v.Status == 1 {
|
||||
cat := &model.SkuVendorCategory{
|
||||
VendorID: model.VendorIDJD,
|
||||
Name: v.Name,
|
||||
Level: level,
|
||||
VendorCategoryID: utils.Int64ToStr(v.Id),
|
||||
}
|
||||
if level > 1 {
|
||||
cat.ParentID = utils.Int64ToStr(v.ParentId)
|
||||
if level == 3 {
|
||||
cat.IsLeaf = 1
|
||||
}
|
||||
}
|
||||
vendorCats = append(vendorCats, cat)
|
||||
if level < 3 {
|
||||
childVendorCats, err2 := p.getVendorCategories(level+1, v.Id)
|
||||
if err2 == nil && len(childVendorCats) > 0 {
|
||||
vendorCats = append(vendorCats, childVendorCats...)
|
||||
} else {
|
||||
cat.IsLeaf = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return vendorCats, nil
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
vendorCats, err = p.getVendorCategories(1, 0)
|
||||
return vendorCats, err
|
||||
}
|
||||
|
||||
func skuInfo2Param(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (param *jdapi.OpSkuParam) {
|
||||
param = &jdapi.OpSkuParam{
|
||||
TraceID: ctx.GetTrackInfo(),
|
||||
OutSkuID: utils.Int2Str(sku.SkuID),
|
||||
ShopCategories: []int64{utils.Str2Int64(sku.VendorCatID)},
|
||||
CategoryID: sku.VendorVendorCatID,
|
||||
BrandID: DefBrandID,
|
||||
SkuName: utils.LimitUTF8StringLen(sku.SkuName, jdapi.MaxSkuNameCharCount),
|
||||
SkuPrice: int(sku.Price),
|
||||
Weight: float64(jxutils.IntWeight2Float(sku.Weight)),
|
||||
FixedStatus: jxStatus2jdStatus(sku.MergedStatus),
|
||||
IsSale: jdapi.IsSaleNo, // todo ?
|
||||
|
||||
Upc: sku.Upc,
|
||||
// Images: jxutils.BatchString2Slice(sku.Img, sku.Img2),
|
||||
}
|
||||
if sku.ImgMix != "" {
|
||||
param.Images = jxutils.BatchString2Slice(sku.ImgMix, sku.Img2)
|
||||
} else {
|
||||
param.Images = jxutils.BatchString2Slice(sku.Img, sku.Img2)
|
||||
}
|
||||
|
||||
if param.CategoryID == 0 {
|
||||
param.CategoryID = int64(getDefJdCategoryID())
|
||||
}
|
||||
// 京东强制要求upc的商品,如果没有设置upc,自动生成一个假的
|
||||
if param.Upc == "" && isSkuMustHaveUpc(sku.Unit, param.CategoryID) {
|
||||
param.Upc = jxutils.GenFakeUPC(sku.SkuID)
|
||||
}
|
||||
if sku.IsGlobal == 0 && len(sku.SellCities) > 0 {
|
||||
param.SellCities = utils.StringSlice2Int64(sku.SellCities)
|
||||
}
|
||||
if sku.DescImg != "" {
|
||||
param.ProductDesc = fmt.Sprintf(`<img src="%s" alt="一张图片" />`, sku.DescImg)
|
||||
}
|
||||
return param
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("CreateSku2 sku:%s", utils.Format4Output(sku, true))
|
||||
param := skuInfo2Param(ctx, sku)
|
||||
if globals.EnableJdStoreWrite {
|
||||
sku.VendorSkuID, err = getAPI(sku.VendorOrgCode).AddSku2(param)
|
||||
} else {
|
||||
sku.VendorSkuID = utils.Int64ToStr(jxutils.GenFakeID())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateSku2(ctx *jxcontext.Context, sku *dao.StoreSkuSyncInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("UpdateSku2 sku:%s", utils.Format4Output(sku, true))
|
||||
param := skuInfo2Param(ctx, sku)
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(sku.VendorOrgCode).UpdateSku2(param)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteSku2(ctx *jxcontext.Context, vendorOrgCode string, sku *partner.StoreSkuInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("DeleteSku2 vendorOrgCode:%s, sku:%s", vendorOrgCode, utils.Format4Output(sku, true))
|
||||
|
||||
// 京东到家只能通过商家ID删除SKU,如果没有的话,先绑定,再删除
|
||||
if sku.SkuID == 0 {
|
||||
skuPairList := []*jdapi.SkuIDPair{
|
||||
&jdapi.SkuIDPair{
|
||||
SkuId: utils.Str2Int64(sku.VendorSkuID),
|
||||
OutSkuId: sku.VendorSkuID,
|
||||
},
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(vendorOrgCode).BatchUpdateOutSkuId(skuPairList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID))
|
||||
}
|
||||
}
|
||||
param := &jdapi.OpSkuParam{
|
||||
TraceID: ctx.GetTrackInfo(),
|
||||
OutSkuID: utils.Int2Str(sku.SkuID),
|
||||
FixedStatus: jdapi.SkuFixedStatusDeleted,
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(vendorOrgCode).UpdateSku2(param)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetSkus(ctx *jxcontext.Context, vendorOrgCode string, skuID int, vendorSkuID string) (skuNameList []*partner.SkuNameInfo, err error) {
|
||||
param := &jdapi.QuerySkuParam{
|
||||
SkuID: utils.Str2Int64WithDefault(vendorSkuID, 0),
|
||||
IsFilterDel: jdapi.IsFilterDelTrue,
|
||||
PageNo: 1,
|
||||
PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds, // 为了同时取图,这个值不要大于jdapi.MaxSkuIDsCount4QueryListBySkuIds
|
||||
}
|
||||
for {
|
||||
skuList, _, err2 := getAPI(vendorOrgCode).QuerySkuInfos(param)
|
||||
if err = err2; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(skuList) > 0 {
|
||||
batchSkuNameList := make([]*partner.SkuNameInfo, len(skuList))
|
||||
for k, v := range skuList {
|
||||
batchSkuNameList[k] = vendorSku2Jx(v)
|
||||
}
|
||||
setSkuNameListPic(vendorOrgCode, batchSkuNameList)
|
||||
skuNameList = append(skuNameList, batchSkuNameList...)
|
||||
}
|
||||
if len(skuList) < param.PageSize {
|
||||
break
|
||||
}
|
||||
param.PageNo++
|
||||
}
|
||||
return skuNameList, err
|
||||
}
|
||||
|
||||
func setSkuNameListPic(vendorOrgCode string, skuNameList []*partner.SkuNameInfo) []*partner.SkuNameInfo {
|
||||
jdSkuIDs := make([]int64, len(skuNameList))
|
||||
for k, v := range skuNameList {
|
||||
jdSkuIDs[k] = utils.Str2Int64(v.SkuList[0].VendorSkuID)
|
||||
}
|
||||
|
||||
imgMap := make(map[int64]*jdapi.ImgHandleQueryResult)
|
||||
if imgList, err2 := getAPI(vendorOrgCode).QueryListBySkuIds(&jdapi.QueryListBySkuIdsParam{
|
||||
SkuIDs: jdSkuIDs,
|
||||
}); err2 == nil {
|
||||
for _, v := range imgList {
|
||||
if v.ImgType == jdapi.ImgTypeMain {
|
||||
imgResult := imgMap[v.SkuID]
|
||||
if imgResult == nil || imgResult.IsMain < v.IsMain {
|
||||
imgMap[v.SkuID] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用扒页面方式获取商品图片
|
||||
if false {
|
||||
var leftJdSkuIDs []int64
|
||||
for _, v := range jdSkuIDs {
|
||||
if imgMap[v] == nil {
|
||||
leftJdSkuIDs = append(leftJdSkuIDs, v)
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("jd setSkuNameListPic", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
jdSkuID := batchItemList[0].(int64)
|
||||
imgList, err := getAPI(vendorOrgCode).GetSkuPageImageInfo(jdSkuID)
|
||||
if err == nil && len(imgList) > 0 {
|
||||
retVal = [][]string{
|
||||
[]string{utils.Int64ToStr(jdSkuID), imgList[0].Big},
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, leftJdSkuIDs)
|
||||
task.Run()
|
||||
if resultList, err := task.GetResult(0); err == nil {
|
||||
for _, v := range resultList {
|
||||
strList := v.([]string)
|
||||
imgMap[utils.Str2Int64(strList[0])] = &jdapi.ImgHandleQueryResult{
|
||||
SourceImgURL: strList[1],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置商品图片
|
||||
for _, v := range skuNameList {
|
||||
if imgResult := imgMap[utils.Str2Int64(v.SkuList[0].VendorSkuID)]; imgResult != nil {
|
||||
v.PictureList = []string{imgResult.SourceImgURL}
|
||||
}
|
||||
}
|
||||
return skuNameList
|
||||
}
|
||||
|
||||
func vendorSku2Jx(vendorSku *jdapi.SkuMain) (skuName *partner.SkuNameInfo) {
|
||||
prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(vendorSku.SkuName)
|
||||
weight := int(vendorSku.Weight * 1000)
|
||||
if weight <= 0 {
|
||||
weight = jxutils.FormatSkuWeight(specQuality, specUnit)
|
||||
}
|
||||
skuID := int(utils.Str2Int64WithDefault(vendorSku.OutSkuID, 0))
|
||||
vendorSkuID := utils.Int64ToStr(vendorSku.SkuID)
|
||||
skuName = &partner.SkuNameInfo{
|
||||
NameID: skuID,
|
||||
VendorNameID: vendorSkuID,
|
||||
VendorCatIDList: []string{utils.Int64ToStr(vendorSku.CategoryID)},
|
||||
|
||||
Prefix: prefix,
|
||||
Name: name,
|
||||
Unit: unit,
|
||||
SkuList: []*partner.SkuInfo{
|
||||
&partner.SkuInfo{
|
||||
StoreSkuInfo: partner.StoreSkuInfo{
|
||||
VendorSkuID: vendorSkuID,
|
||||
SkuID: skuID,
|
||||
|
||||
VendorPrice: int64(vendorSku.SkuPrice),
|
||||
Status: jdStatus2jxStatus(vendorSku.FixedStatus),
|
||||
},
|
||||
SkuName: vendorSku.SkuName,
|
||||
Comment: comment,
|
||||
SpecQuality: float64(specQuality),
|
||||
SpecUnit: specUnit,
|
||||
Weight: weight,
|
||||
},
|
||||
},
|
||||
}
|
||||
return skuName
|
||||
}
|
||||
|
||||
func jdStatus2jxStatus(jdStatus int) (jxStatus int) {
|
||||
switch jdStatus {
|
||||
case jdapi.SkuFixedStatusOnline:
|
||||
jxStatus = model.SkuStatusNormal
|
||||
case jdapi.SkuFixedStatusOffline:
|
||||
jxStatus = model.SkuStatusDontSale
|
||||
case jdapi.SkuFixedStatusDeleted:
|
||||
jxStatus = model.SkuStatusDeleted
|
||||
}
|
||||
return jxStatus
|
||||
}
|
||||
|
||||
func jxStatus2jdStatus(jxStatus int) (jdStatus int) {
|
||||
switch jxStatus {
|
||||
case model.SkuStatusNormal:
|
||||
jdStatus = jdapi.SkuFixedStatusOnline
|
||||
case model.SkuStatusDontSale:
|
||||
jdStatus = jdapi.SkuFixedStatusOffline
|
||||
case model.SkuStatusDeleted:
|
||||
jdStatus = jdapi.SkuFixedStatusDeleted
|
||||
}
|
||||
return jdStatus
|
||||
}
|
||||
|
||||
func isSkuMustHaveUpc(unit string, vendorVendorCatID int64) bool {
|
||||
return unit != model.SpecialUnit || !upcLessMap[vendorVendorCatID]
|
||||
}
|
||||
|
||||
var (
|
||||
upcLessMap = map[int64]bool{
|
||||
20250: true,
|
||||
20252: true,
|
||||
20258: true,
|
||||
20259: true,
|
||||
20261: true,
|
||||
20262: true,
|
||||
20263: true,
|
||||
20264: true,
|
||||
20265: true,
|
||||
20266: true,
|
||||
20267: true,
|
||||
22822: true,
|
||||
20269: true,
|
||||
20270: true,
|
||||
20271: true,
|
||||
20272: true,
|
||||
20273: true,
|
||||
20275: true,
|
||||
20276: true,
|
||||
20277: true,
|
||||
20278: true,
|
||||
20279: true,
|
||||
20281: true,
|
||||
20282: true,
|
||||
20283: true,
|
||||
20285: true,
|
||||
20286: true,
|
||||
20287: true,
|
||||
22821: true,
|
||||
20289: true,
|
||||
20290: true,
|
||||
23018: true,
|
||||
20354: true,
|
||||
20355: true,
|
||||
20357: true,
|
||||
20359: true,
|
||||
23019: true,
|
||||
20294: true,
|
||||
20295: true,
|
||||
20296: true,
|
||||
20297: true,
|
||||
20298: true,
|
||||
20299: true,
|
||||
20300: true,
|
||||
20302: true,
|
||||
20303: true,
|
||||
20304: true,
|
||||
22840: true,
|
||||
22841: true,
|
||||
20317: true,
|
||||
20320: true,
|
||||
20321: true,
|
||||
20323: true,
|
||||
20325: true,
|
||||
20326: true,
|
||||
20328: true,
|
||||
20329: true,
|
||||
20331: true,
|
||||
20335: true,
|
||||
20337: true,
|
||||
20338: true,
|
||||
20339: true,
|
||||
22842: true,
|
||||
22843: true,
|
||||
23020: true,
|
||||
20309: true,
|
||||
20310: true,
|
||||
20311: true,
|
||||
20312: true,
|
||||
20313: true,
|
||||
20314: true,
|
||||
20315: true,
|
||||
22410: true,
|
||||
23050: true,
|
||||
20319: true,
|
||||
20322: true,
|
||||
20330: true,
|
||||
20332: true,
|
||||
20334: true,
|
||||
20336: true,
|
||||
20340: true,
|
||||
20342: true,
|
||||
23049: true,
|
||||
20356: true,
|
||||
20358: true,
|
||||
20360: true,
|
||||
20361: true,
|
||||
20362: true,
|
||||
20364: true,
|
||||
}
|
||||
)
|
||||
@@ -1,61 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
func TestCreateSku(t *testing.T) {
|
||||
// t.Log(beego.BConfig.RunMode)
|
||||
skuID := 21741
|
||||
sku := &model.Sku{}
|
||||
sku.ID = skuID
|
||||
dao.GetEntity(nil, sku)
|
||||
t.Log(sku)
|
||||
// err := CurPurchaseHandler.CreateSku(sku)
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
}
|
||||
|
||||
func TestGetAllCategories(t *testing.T) {
|
||||
result, err := CurPurchaseHandler.GetAllCategories(jxcontext.AdminCtx, "")
|
||||
if err != nil || len(result) == 0 {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
// func TestReadSku(t *testing.T) {
|
||||
// skuName, err := CurPurchaseHandler.ReadSku(jxcontext.AdminCtx, "", "2005582952")
|
||||
// t.Log(utils.Format4Output(skuName, false))
|
||||
// if err != nil {
|
||||
// t.Fatal(err.Error())
|
||||
// }
|
||||
// if skuName.Name != "味事达酱香鲜特级酿造酱油" || skuName.Skus[0].SpecUnit != "ml" {
|
||||
// t.Fatal("ReadSku return data wrong")
|
||||
// t.Log(string(utils.MustMarshal(skuName)))
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestGetVendorCategories(t *testing.T) {
|
||||
catList, err := CurPurchaseHandler.GetVendorCategories(jxcontext.AdminCtx)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(catList, false))
|
||||
}
|
||||
|
||||
func TestGetSkus(t *testing.T) {
|
||||
skuNameList, err := CurPurchaseHandler.GetSkus(jxcontext.AdminCtx, "", 0, "2023747677")
|
||||
t.Log(utils.Format4Output(skuNameList, false))
|
||||
t.Log(len(skuNameList))
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,520 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"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/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type tJdStoreInfo struct {
|
||||
model.Store
|
||||
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
|
||||
|
||||
FreightDeductionPack string `orm:"size(32)" json:"freightDeductionPack"` //
|
||||
|
||||
JdCityCode int
|
||||
JdDistrictCode int
|
||||
JdStoreStatus int
|
||||
VendorStoreID string `orm:"column(vendor_store_id)"`
|
||||
RealLastOperator string
|
||||
SyncStatus int
|
||||
VendorStoreName string
|
||||
}
|
||||
|
||||
var (
|
||||
specialDistrictMap = map[int]int{
|
||||
13989: 310032,
|
||||
}
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (*dao.StoreDetail, error) {
|
||||
a := getAPI(vendorOrgCode)
|
||||
result, err := a.GetStoreInfoByStationNo2(vendorStoreID)
|
||||
if err == nil {
|
||||
retVal := &dao.StoreDetail{
|
||||
Store: model.Store{
|
||||
Address: result.StationAddress,
|
||||
OpenTime1: JdOperationTime2JxOperationTime(result.ServiceTimeStart1),
|
||||
CloseTime1: JdOperationTime2JxOperationTime(result.ServiceTimeEnd1),
|
||||
OpenTime2: JdOperationTime2JxOperationTime(result.ServiceTimeStart2),
|
||||
CloseTime2: JdOperationTime2JxOperationTime(result.ServiceTimeEnd2),
|
||||
Status: JdStoreStatus2JxStatus(int(result.Yn), result.CloseStatus),
|
||||
Tel1: result.Phone,
|
||||
},
|
||||
}
|
||||
if result.IsAutoOrder == 0 {
|
||||
retVal.IsAutoOrder = 1
|
||||
} else {
|
||||
retVal.IsAutoOrder = -1
|
||||
}
|
||||
retVal.OriginalName = result.StationName
|
||||
_, retVal.Name = jxutils.SplitStoreName(retVal.OriginalName, partner.StoreNameSeparator, globals.StoreName)
|
||||
retVal.DeliveryType = JdDeliveryType2Jx(result.CarrierNo)
|
||||
|
||||
tel2 := result.Mobile
|
||||
if tel2 != "" && tel2 != retVal.Tel1 {
|
||||
retVal.Tel2 = tel2
|
||||
}
|
||||
lng := result.Lng
|
||||
lat := result.Lat
|
||||
retVal.Lng = jxutils.StandardCoordinate2Int(lng)
|
||||
retVal.Lat = jxutils.StandardCoordinate2Int(lat)
|
||||
|
||||
db := dao.GetDB()
|
||||
cityCode := result.City
|
||||
if cityCode != 0 {
|
||||
if place, err2 := dao.GetPlaceByJdCode(db, cityCode); err2 == nil {
|
||||
if place.Level == model.PlaceLevelCity {
|
||||
retVal.CityCode = place.Code
|
||||
retVal.CityName = utils.Interface2String(result.CityName)
|
||||
districtName := result.CountyName // 京东的市区号码与通用数据完全无法关联,只有通过名字来关联
|
||||
if retVal.CityCode != 0 && districtName != "" {
|
||||
if district, err2 := dao.GetPlaceByName(db, districtName, 3, place.Code); err2 == nil {
|
||||
retVal.DistrictCode = district.Code
|
||||
}
|
||||
}
|
||||
} else if place.Level == model.PlaceLevelDistrict {
|
||||
retVal.CityCode = place.ParentCode
|
||||
retVal.DistrictCode = place.Code
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("门店:%s的城市码:%d异常", vendorStoreID, cityCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
if retVal.DistrictCode == 0 {
|
||||
retVal.DistrictCode = api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat)
|
||||
if retVal.CityCode == 0 {
|
||||
if district, err := dao.GetPlaceByCode(db, retVal.DistrictCode); err == nil {
|
||||
retVal.CityCode = district.ParentCode
|
||||
}
|
||||
}
|
||||
}
|
||||
retVal.VendorStoreID = vendorStoreID
|
||||
retVal.ID = int(utils.Str2Int64WithDefault(result.OutSystemID, 0))
|
||||
deliveryRange, err2 := a.GetDeliveryRangeByStationNo2(vendorStoreID)
|
||||
if err = err2; err == nil {
|
||||
retVal.DeliveryRangeType = int8(deliveryRange.DeliveryRangeType)
|
||||
if retVal.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
retVal.DeliveryRange = strings.Trim(deliveryRange.DeliveryRange, ";")
|
||||
} else {
|
||||
retVal.DeliveryRange = utils.Int2Str(deliveryRange.DeliveryRangeRadius)
|
||||
}
|
||||
return retVal, nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// stoerIDs为nil表示所有
|
||||
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
|
||||
var stores []*tJdStoreInfo
|
||||
sql := `
|
||||
SELECT
|
||||
t1.*, city.jd_code jd_city_code, district.jd_code jd_district_code,
|
||||
t2.status jd_store_status, t2.vendor_store_id, IF(t1.updated_at > t2.updated_at, t1.last_operator,
|
||||
t2.last_operator) real_last_operator,
|
||||
t2.sync_status, t2.freight_deduction_pack, t2.vendor_org_code, t2.vendor_store_name
|
||||
FROM store t1
|
||||
JOIN store_map t2 ON t1.id = t2.store_id AND t2.vendor_id = ? AND (t2.deleted_at = ?)
|
||||
LEFT JOIN place city ON t1.city_code = city.code
|
||||
LEFT JOIN place district ON t1.district_code = district.code
|
||||
WHERE t1.id = ?
|
||||
ORDER BY t2.updated_at
|
||||
`
|
||||
if err = dao.GetRows(db, &stores, sql, model.VendorIDJD, utils.DefaultTimeValue, storeID); err == nil {
|
||||
for _, store := range stores {
|
||||
a := getAPI(store.VendorOrgCode)
|
||||
// phone := ""
|
||||
// if store.MarketManPhone != "" {
|
||||
// phone = store.MarketManPhone
|
||||
// } else {
|
||||
// phone = model.VendorStoreTel
|
||||
// }
|
||||
storeParams := &jdapi.OpStoreParams{
|
||||
StationNo: store.VendorStoreID,
|
||||
Operator: userName,
|
||||
Phone: store.Tel1,
|
||||
Mobile: store.Tel1,
|
||||
}
|
||||
if store.SyncStatus&model.SyncFlagDeletedMask == 0 {
|
||||
storeParams.OutSystemID = utils.Int2Str(int(store.ID))
|
||||
} else {
|
||||
storeParams.OutSystemID = store.VendorStoreID
|
||||
}
|
||||
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreName) != 0 {
|
||||
if store.VendorStoreName != "" {
|
||||
storeParams.StationName = store.VendorStoreName
|
||||
} else {
|
||||
storeParams.StationName = jxutils.ComposeStoreName(store.Name, model.VendorIDJD)
|
||||
}
|
||||
storeParams.StationName = utils.LimitUTF8StringLen(storeParams.StationName, jdapi.MaxStoreNameLen)
|
||||
}
|
||||
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreAddress) != 0 {
|
||||
storeParams.StationAddress = store.Address
|
||||
storeParams.CoordinateType = jdapi.CoordinateTypeAutonavi // 一直用高德
|
||||
storeParams.Lng = jxutils.IntCoordinate2Standard(store.Lng)
|
||||
storeParams.Lat = jxutils.IntCoordinate2Standard(store.Lat)
|
||||
if store.JdCityCode != 0 {
|
||||
storeParams.City = store.JdCityCode
|
||||
}
|
||||
if store.JdDistrictCode != 0 {
|
||||
storeParams.County = store.JdDistrictCode
|
||||
//TODO 彭州市做特殊处理 2020-05-25
|
||||
if store.JdDistrictCode == 49318 {
|
||||
storeParams.City = 49318
|
||||
storeParams.County = 310045
|
||||
}
|
||||
}
|
||||
|
||||
// storeParams.DeliveryRangeType = store.DeliveryRangeType
|
||||
// if store.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
// storeParams.CoordinatePoints = store.DeliveryRange
|
||||
// } else {
|
||||
// storeParams.DeliveryRangeRadius = int(utils.Str2Int64WithDefault(store.DeliveryRange, 0))
|
||||
// }
|
||||
}
|
||||
if specialDistrictMap[storeParams.County] != 0 {
|
||||
storeParams.City = storeParams.County
|
||||
storeParams.County = specialDistrictMap[storeParams.County]
|
||||
}
|
||||
storeParams.StoreNotice = store.PromoteInfo
|
||||
modifyCloseStatus := false
|
||||
if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagDeletedMask|model.SyncFlagStoreStatus) != 0 {
|
||||
modifyCloseStatus = true
|
||||
_, storeParams.CloseStatus = JxStoreStatus2JdStatus(jxutils.MergeStoreStatus(store.Status, store.JdStoreStatus))
|
||||
}
|
||||
fillOpTimeParams(storeParams, store.GetOpTimeList())
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(storeParams, false))
|
||||
errList := errlist.New()
|
||||
if globals.EnableJdStoreWrite {
|
||||
errList.AddErr(a.UpdateStoreInfo4Open2(storeParams, modifyCloseStatus))
|
||||
}
|
||||
if store.FreightDeductionPack != "" {
|
||||
storeDetail, err2 := dao.GetStoreDetail(db, store.ID, model.VendorIDJD)
|
||||
if err2 == nil {
|
||||
if storeDetail.FreightDeductionPackObj != nil {
|
||||
freightParams := &jdapi.UpdateStoreFreightParam{
|
||||
StationNo: store.VendorStoreID,
|
||||
UserPin: userName,
|
||||
OpenDistanceFreight: true,
|
||||
StartCharge: int64(storeDetail.FreightDeductionPackObj.StartPrice),
|
||||
}
|
||||
if len(storeDetail.FreightDeductionPackObj.FreightDeductionList) > 0 {
|
||||
for _, v := range storeDetail.FreightDeductionPackObj.FreightDeductionList {
|
||||
if v.DeductFreight > 0 {
|
||||
freightParams.FreeFreightInfoList = append(freightParams.FreeFreightInfoList, &jdapi.FreeFreightInfo{
|
||||
FullFreeMoney: int64(v.BeginPrice),
|
||||
FreeType: jdapi.FreightFreeTypePartBase,
|
||||
FreeMoney: int64(v.DeductFreight),
|
||||
FreeFreightTimes: []*jdapi.FreeFreightTime{
|
||||
&jdapi.FreeFreightTime{
|
||||
FreeBeginTime: utils.Time2Str(time.Now()),
|
||||
FreeEndTime: utils.Time2Str(time.Now().Add(24 * time.Hour * 365 * 2)),
|
||||
},
|
||||
},
|
||||
})
|
||||
break // 京东只能设置一个满减,之前理解有误
|
||||
}
|
||||
}
|
||||
}
|
||||
freightParams.IsFullFree = len(freightParams.FreeFreightInfoList) > 0
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(freightParams, false))
|
||||
if globals.EnableJdStoreWrite {
|
||||
errList.AddErr(a.UpdateStoreFreightConfigNew(freightParams))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("jd RefreshAllStoresID")
|
||||
const stepCount = 3
|
||||
var stores []*tJdStoreInfo
|
||||
db := dao.GetDB()
|
||||
rootTask := tasksch.NewSeqTask("jd RefreshAllStoresID", ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
err = dao.GetRows(db, &stores, `
|
||||
SELECT t1.*, t2.vendor_store_id
|
||||
FROM store t1
|
||||
JOIN store_map t2 ON t1.id = t2.store_id AND t2.deleted_at = ? AND t2.vendor_id = ?
|
||||
WHERE t1.deleted_at = ?
|
||||
`, utils.DefaultTimeValue, model.VendorIDJD, utils.DefaultTimeValue)
|
||||
default:
|
||||
taskName := "jd RefreshAllStoresID update outSystemId"
|
||||
if step != stepCount-1 {
|
||||
taskName = "jd RefreshAllStoresID update to uuid"
|
||||
}
|
||||
task1 := tasksch.NewParallelTask(taskName, nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
store := batchItemList[0].(*tJdStoreInfo)
|
||||
storeParams := &jdapi.OpStoreParams{
|
||||
StationNo: store.VendorStoreID,
|
||||
Operator: ctx.GetUserName(),
|
||||
OutSystemID: utils.Int2Str(int(store.ID)),
|
||||
}
|
||||
if step != stepCount-1 {
|
||||
storeParams.OutSystemID = store.VendorStoreID
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(store.VendorOrgCode).UpdateStoreInfo4Open2(storeParams, false)
|
||||
}
|
||||
return nil, err
|
||||
}, stores)
|
||||
task.AddChild(task1).Run()
|
||||
_, err = task1.GetResult(0)
|
||||
}
|
||||
return nil, err
|
||||
}, stepCount)
|
||||
|
||||
tasksch.HandleTask(rootTask, parentTask, false).Run()
|
||||
if !isAsync {
|
||||
_, err = rootTask.GetResult(0)
|
||||
}
|
||||
return rootTask.ID, err
|
||||
}
|
||||
|
||||
func JdDeliveryType2Jx(deliveryType int) int8 {
|
||||
if deliveryType == jdapi.CarrierNoSelfDelivery {
|
||||
return scheduler.StoreDeliveryTypeByStore
|
||||
} else if deliveryType == jdapi.CarrierNoCrowdSourcing {
|
||||
return scheduler.StoreDeliveryTypeCrowdSourcing
|
||||
}
|
||||
return scheduler.StoreDeliveryTypeByPlatform
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
|
||||
result, err := getAPI(vendorOrgCode).GetStoreInfoByStationNo2(vendorStoreID)
|
||||
if err == nil {
|
||||
storeStatus = JdStoreStatus2JxStatus(int(result.Yn), result.CloseStatus)
|
||||
}
|
||||
return storeStatus, err
|
||||
}
|
||||
|
||||
// 当前京东的storeCrud消息不会在门店状态改变时发送,所以意义不大,先放在这里
|
||||
func (c *PurchaseHandler) OnStoreMsg(vendorOrgCode string, msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
|
||||
var err error
|
||||
// if msg.StatusID == jdapi.StatusIDUpdateStore {
|
||||
// var storeStatus int
|
||||
// vendorStoreID := msg.BillID
|
||||
// if storeStatus, err = c.GetStoreStatus(jxcontext.AdminCtx, vendorStoreID); err == nil {
|
||||
// err = partner.CurStoreManager.OnStoreStatusChanged(vendorStoreID, model.VendorIDJD, storeStatus)
|
||||
// } else {
|
||||
// // 可能在门店删除的情况下会出查不到门店的错误
|
||||
// if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.IntCode() == 4 {
|
||||
// err = nil
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return jdapi.Err2CallbackResponse(err, "")
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
|
||||
_, err = getAPI(vendorOrgCode).UpdateStoreConfig4Open(vendorStoreID, isSetEnable)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
|
||||
_, closeStatus := JxStoreStatus2JdStatus(status)
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(&jdapi.OpStoreParams{
|
||||
StationNo: vendorStoreID,
|
||||
Operator: ctx.GetUserName(),
|
||||
CloseStatus: closeStatus,
|
||||
}, true)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func fillOpTimeParams(params *jdapi.OpStoreParams, opTimeList []int16) {
|
||||
index := 1
|
||||
opTimeListLen := len(opTimeList)
|
||||
if opTimeListLen > 4 {
|
||||
opTimeListLen = 4
|
||||
}
|
||||
opTimeListLen = opTimeListLen / 2 * 2
|
||||
for k := 0; k < len(opTimeList); k += 2 {
|
||||
if opTimeList[k] != 0 {
|
||||
if index == 1 {
|
||||
params.ServiceTimeStart1 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k])))
|
||||
params.ServiceTimeEnd1 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k+1])))
|
||||
} else {
|
||||
params.ServiceTimeStart2 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k])))
|
||||
params.ServiceTimeEnd2 = int(JxOperationTime2JdOperationTime(int16(opTimeList[k+1])))
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
|
||||
params := &jdapi.OpStoreParams{
|
||||
StationNo: vendorStoreID,
|
||||
Operator: ctx.GetUserName(),
|
||||
}
|
||||
fillOpTimeParams(params, opTimeList)
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(params, false)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
|
||||
vendorStoreIDs, err = getAPI(vendorOrgCode).GetStationsByVenderId()
|
||||
return vendorStoreIDs, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) storeUploadImgByURL(vendorOrgCode, inImgURL string) (imgURL string, err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
if vendorOrgCode == globals.JdOrgCode {
|
||||
imgURL, err = api.JdPageAPI.StoreUploadImgByURL(inImgURL)
|
||||
} else {
|
||||
imgURL, err = getAPI(vendorOrgCode).StoreUploadImgByURL(inImgURL)
|
||||
}
|
||||
} else {
|
||||
imgURL = utils.GetUUID()
|
||||
}
|
||||
return imgURL, err
|
||||
}
|
||||
|
||||
func addStoreInfo2Err(err error, storeID int) error {
|
||||
if err != nil {
|
||||
errExt, _ := err.(*utils.ErrorWithCode)
|
||||
if errExt == nil {
|
||||
errExt = utils.NewErrorCode(err.Error(), "999")
|
||||
}
|
||||
errExt.AddPrefixMsg(fmt.Sprintf("门店%d", storeID))
|
||||
err = errExt
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SyncQualify(ctx *jxcontext.Context, storeDetail *dao.StoreDetail) (err error) {
|
||||
if storeDetail.LicenceCode == "" || storeDetail.Licence == "" {
|
||||
return addStoreInfo2Err(fmt.Errorf("营业执照信息不全"), storeDetail.ID)
|
||||
}
|
||||
if storeDetail.IDCode == "" || storeDetail.IDCardFront == "" || storeDetail.IDCardBack == "" || storeDetail.IDValid == "" {
|
||||
return addStoreInfo2Err(fmt.Errorf("个人信息不全"), storeDetail.ID)
|
||||
}
|
||||
var qualifyList []*jdapi.QualifyItem
|
||||
licenceDetail, err := api.JdPageAPI.GetCorporationInfo(storeDetail.VendorStoreID, storeDetail.LicenceCode)
|
||||
if err != nil {
|
||||
return addStoreInfo2Err(err, storeDetail.ID)
|
||||
}
|
||||
licenceURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.Licence)
|
||||
if err != nil {
|
||||
return addStoreInfo2Err(err, storeDetail.ID)
|
||||
}
|
||||
expireStart, err := utils.TryStr2Time(licenceDetail.StartDate)
|
||||
if err != nil {
|
||||
return addStoreInfo2Err(fmt.Errorf("执照有效开始时间:%s非法,请手动处理", licenceDetail.StartDate), storeDetail.ID)
|
||||
}
|
||||
qualifyList = append(qualifyList, &jdapi.QualifyItem{
|
||||
QualifyType: jdapi.QualifyTypeCompany,
|
||||
QualifyURL: licenceURL,
|
||||
QualifyExpireStart: utils.Time2Str(expireStart),
|
||||
QualifyExpireForever: 0,
|
||||
QualifyName: licenceDetail.OperName,
|
||||
LicenceType: "-1",
|
||||
QualifyNumber: storeDetail.LicenceCode,
|
||||
QualifyAddress: licenceDetail.Address,
|
||||
LicenceName: licenceDetail.Name,
|
||||
EconKind: licenceDetail.EconKind,
|
||||
Scope: licenceDetail.Scope,
|
||||
})
|
||||
|
||||
idFrondURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.IDCardFront)
|
||||
if err != nil {
|
||||
return addStoreInfo2Err(err, storeDetail.ID)
|
||||
}
|
||||
// 个体经营,个体工商户
|
||||
if storeDetail.LicenceType == 0 { // 个人
|
||||
personQualify := &jdapi.QualifyItem{
|
||||
QualifyType: jdapi.QualifyTypePerson,
|
||||
QualifyURL: idFrondURL,
|
||||
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
|
||||
QualifyExpireForever: 0,
|
||||
|
||||
QualifyNumber: storeDetail.IDCode,
|
||||
QualifyOwner: storeDetail.LicenceOwnerName,
|
||||
}
|
||||
if storeDetail.IDExpire != "" {
|
||||
personQualify.QualifyExpireForever = 1
|
||||
personQualify.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
|
||||
}
|
||||
qualifyList = append(qualifyList, personQualify)
|
||||
} else {
|
||||
addInfo := &jdapi.QualifyItem{
|
||||
QualifyType: jdapi.QualifyTypeAddInfo,
|
||||
QualifyURL: idFrondURL,
|
||||
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
|
||||
QualifyExpireForever: 0,
|
||||
}
|
||||
if storeDetail.IDExpire != "" {
|
||||
addInfo.QualifyExpireForever = 1
|
||||
addInfo.QualifyExpireEnd = utils.Time2Str(utils.Str2Time(storeDetail.IDExpire))
|
||||
}
|
||||
qualifyList = append(qualifyList, addInfo)
|
||||
}
|
||||
if storeDetail.IDExpire == "" {
|
||||
idBackURL, err := c.storeUploadImgByURL(storeDetail.VendorOrgCode, storeDetail.IDCardBack)
|
||||
if err != nil {
|
||||
return addStoreInfo2Err(err, storeDetail.ID)
|
||||
}
|
||||
qualifyList = append(qualifyList, &jdapi.QualifyItem{
|
||||
QualifyType: jdapi.QualifyTypeAddInfo,
|
||||
QualifyURL: idBackURL,
|
||||
QualifyExpireStart: utils.Time2Str(utils.Str2Time(storeDetail.IDValid)),
|
||||
QualifyExpireForever: 0,
|
||||
})
|
||||
}
|
||||
globals.SugarLogger.Debug(utils.Format4Output(qualifyList, false))
|
||||
if globals.EnableJdStoreWrite {
|
||||
globals.SugarLogger.Debugf("SaveQualifyTest4,[%v]", utils.Format4Output(qualifyList, false))
|
||||
err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeCommit, qualifyList)
|
||||
// err = api.JdPageAPI.SaveQualify(storeDetail.VendorStoreID, jdapi.SaveQualifyActionTypeSave, qualifyList)
|
||||
}
|
||||
return addStoreInfo2Err(err, storeDetail.ID)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).UpdateStoreInfo4Open2(
|
||||
&jdapi.OpStoreParams{
|
||||
StationNo: vendorStoreID,
|
||||
Operator: ctx.GetUserName(),
|
||||
OutSystemID: utils.Int2Str(int(storeID)),
|
||||
}, false)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
|
||||
return vendorStoreID, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
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/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
|
||||
switch funcID {
|
||||
case partner.FuncUpdateStoreSkusStock, partner.FuncUpdateStoreSkusStatus, partner.FuncUpdateStoreSkusPrice:
|
||||
batchSize = jdapi.MaxStoreSkuBatchSize
|
||||
case partner.FuncCreateActs, partner.FuncCancelActs:
|
||||
batchSize = 1
|
||||
}
|
||||
return batchSize
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) getStoreSkusBareInfoLimitSize(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, 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 = getAPI(vendorOrgCode).QueryOpenUseable(batchSkuInfoList)
|
||||
} else {
|
||||
priceInfo, err = getAPI(vendorOrgCode).GetStationInfoList(vendorStoreID, batchSkuList)
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
_, err = task.GetResult(0)
|
||||
if err == nil {
|
||||
storeSkuMap := putils.StoreSkuList2MapByVendorSkuID(inStoreSkuList)
|
||||
for _, v := range stockInfo {
|
||||
sku := storeSkuMap[utils.Int64ToStr(v.SkuID)]
|
||||
sku.Status = jdStoreSkuStatus2Jx(v.Vendibility)
|
||||
sku.Stock = v.UsableQty
|
||||
if sku.Stock > 0 {
|
||||
outStoreSkuList = append(outStoreSkuList, sku)
|
||||
}
|
||||
}
|
||||
for _, v := range priceInfo {
|
||||
sku := storeSkuMap[utils.Int64ToStr(v.SkuID)]
|
||||
sku.VendorPrice = v.Price
|
||||
}
|
||||
}
|
||||
}
|
||||
return outStoreSkuList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusBareInfo(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, err error) {
|
||||
result, err := putils.FreeBatchStoreSkuInfo("获取门店商品信息", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
list, err := p.getStoreSkusBareInfoLimitSize(ctx, vendorOrgCode, task, storeID, vendorStoreID, batchedStoreSkuList)
|
||||
if err == nil {
|
||||
result = list
|
||||
}
|
||||
return result, len(list), err
|
||||
}, ctx, parentTask, inStoreSkuList, jdapi.MaxStoreSkuBatchSize, true)
|
||||
for _, v := range result {
|
||||
outStoreSkuList = append(outStoreSkuList, v.(*partner.StoreSkuInfo))
|
||||
}
|
||||
return outStoreSkuList, err
|
||||
}
|
||||
|
||||
func jdStoreSkuStatus2Jx(jdStoreSkuStatus int) (jxSkuStatus int) {
|
||||
if jdStoreSkuStatus == 0 {
|
||||
jxSkuStatus = model.SkuStatusNormal
|
||||
} else {
|
||||
jxSkuStatus = model.SkuStatusDontSale
|
||||
}
|
||||
return jxSkuStatus
|
||||
}
|
||||
|
||||
func jxStoreSkuStatus2Jd(jxStoreSkuStatus int) (isSale bool) {
|
||||
return jxStoreSkuStatus == model.SkuStatusNormal
|
||||
}
|
||||
|
||||
func isErrPartialFailed(err error) bool {
|
||||
if errExt, ok := err.(*utils.ErrorWithCode); ok && errExt.Code() == jdapi.ResponseInnerCodePartialFailed {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getStrOutSkuIDs(l []*jdapi.StoreSkuBatchUpdateResponse, isSuccess bool) (outSkuIDs []string) {
|
||||
for _, v := range l {
|
||||
if isSuccess && jdapi.IsCodeSuccess(v.Code) {
|
||||
outSkuIDs = append(outSkuIDs, v.OutSkuID)
|
||||
} else if !isSuccess && !jdapi.IsCodeSuccess(v.Code) {
|
||||
outSkuIDs = append(outSkuIDs, v.OutSkuID)
|
||||
}
|
||||
}
|
||||
return outSkuIDs
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
var skuVendibilityList []*jdapi.StockVendibility
|
||||
jdStatus := jxStoreSkuStatus2Jd(status)
|
||||
for _, v := range storeSkuList {
|
||||
skuVendibilityList = append(skuVendibilityList, &jdapi.StockVendibility{
|
||||
OutSkuId: utils.Int2Str(v.SkuID),
|
||||
DoSale: jdStatus,
|
||||
})
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
var responseList []*jdapi.StoreSkuBatchUpdateResponse
|
||||
var err2 error
|
||||
if vendorOrgCode != apimanager.FakeJdOrgCode {
|
||||
responseList, err2 = getAPI(vendorOrgCode).BatchUpdateVendibility(ctx.GetTrackInfo(), "", vendorStoreID, skuVendibilityList, ctx.GetUserName())
|
||||
} else {
|
||||
responseList, err2 = getAPI(vendorOrgCode).FakeBatchUpdateVendibility(ctx.GetTrackInfo(), "", vendorStoreID, skuVendibilityList, ctx.GetUserName())
|
||||
}
|
||||
if err = err2; err != nil {
|
||||
failedList = SelectStoreSkuListByResponseList(storeSkuList, responseList, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品状态")
|
||||
// successList = putils.UnselectStoreSkuListBySkuIDs(storeSkuList, utils.StringSlice2Int(getStrOutSkuIDs(responseList, false)))
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if len(storeSkuList) == 1 && vendorOrgCode != apimanager.FakeJdOrgCode {
|
||||
if globals.EnableJdStoreWrite {
|
||||
_, err = getAPI(vendorOrgCode).UpdateStationPrice(ctx.GetTrackInfo(), utils.Str2Int64WithDefault(storeSkuList[0].VendorSkuID, 0), vendorStoreID, int(storeSkuList[0].VendorPrice))
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品价格")
|
||||
}
|
||||
} else {
|
||||
var skuPriceInfoList []*jdapi.SkuPriceInfo
|
||||
for _, v := range storeSkuList {
|
||||
skuPriceInfoList = append(skuPriceInfoList, &jdapi.SkuPriceInfo{
|
||||
OutSkuId: utils.Int2Str(v.SkuID),
|
||||
Price: int(v.VendorPrice),
|
||||
})
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
var responseList []*jdapi.StoreSkuBatchUpdateResponse
|
||||
var err2 error
|
||||
if vendorOrgCode != apimanager.FakeJdOrgCode {
|
||||
responseList, err2 = getAPI(vendorOrgCode).UpdateVendorStationPrice(ctx.GetTrackInfo(), "", vendorStoreID, skuPriceInfoList)
|
||||
} else {
|
||||
responseList, err2 = getAPI(vendorOrgCode).FakeUpdateVendorStationPrice(ctx.GetTrackInfo(), "", vendorStoreID, skuPriceInfoList)
|
||||
}
|
||||
if err = err2; err != nil {
|
||||
failedList = SelectStoreSkuListByResponseList(storeSkuList, responseList, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品价格")
|
||||
}
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if len(storeSkuList) == 1 && vendorOrgCode != apimanager.FakeJdOrgCode {
|
||||
if globals.EnableJdStoreWrite {
|
||||
err = getAPI(vendorOrgCode).UpdateCurrentQty(ctx.GetTrackInfo(), vendorStoreID, utils.Str2Int64WithDefault(storeSkuList[0].VendorSkuID, 0), storeSkuList[0].Stock)
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品库存")
|
||||
}
|
||||
} else {
|
||||
var skuStockList []*jdapi.SkuStock
|
||||
for _, v := range storeSkuList {
|
||||
skuStockList = append(skuStockList, &jdapi.SkuStock{
|
||||
OutSkuId: utils.Int2Str(v.SkuID),
|
||||
StockQty: v.Stock,
|
||||
})
|
||||
}
|
||||
if globals.EnableJdStoreWrite {
|
||||
var responseList []*jdapi.StoreSkuBatchUpdateResponse
|
||||
var err2 error
|
||||
if vendorOrgCode != apimanager.FakeJdOrgCode {
|
||||
responseList, err2 = getAPI(vendorOrgCode).BatchUpdateCurrentQtys(ctx.GetTrackInfo(), "", vendorStoreID, skuStockList, ctx.GetUserName())
|
||||
} else {
|
||||
responseList, err2 = getAPI(vendorOrgCode).FakeBatchUpdateCurrentQtys(ctx.GetTrackInfo(), "", vendorStoreID, skuStockList, ctx.GetUserName())
|
||||
}
|
||||
if err = err2; err != nil {
|
||||
failedList = SelectStoreSkuListByResponseList(storeSkuList, responseList, storeID, model.VendorChineseNames[model.VendorIDJD], "更新商品库存")
|
||||
// successList = putils.UnselectStoreSkuListBySkuIDs(storeSkuList, utils.StringSlice2Int(getStrOutSkuIDs(responseList, false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) SyncStoreProducts(ctx *jxcontext.Context, vendorOrgCode string, 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 := getAPI(vendorOrgCode).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
|
||||
}
|
||||
|
||||
//京东api返回
|
||||
func SelectStoreSkuListByResponseList(storeSkuList []*partner.StoreSkuInfo, responseList []*jdapi.StoreSkuBatchUpdateResponse, storeID int, vendorName, syncType string) (selectedStoreSkuList []*partner.StoreSkuInfoWithErr) {
|
||||
responseMap := make(map[string]string)
|
||||
if len(responseList) > 0 {
|
||||
for _, v := range responseList {
|
||||
if v.Code != "0" {
|
||||
responseMap[v.OutSkuID] = v.Msg
|
||||
}
|
||||
}
|
||||
for _, v := range storeSkuList {
|
||||
if responseMap[utils.Int2Str(v.SkuID)] != "" {
|
||||
respFailed := &partner.StoreSkuInfoWithErr{
|
||||
StoreSkuInfo: v,
|
||||
ErrMsg: responseMap[utils.Int2Str(v.SkuID)],
|
||||
StoreID: storeID,
|
||||
VendoreName: vendorName,
|
||||
SyncType: syncType,
|
||||
}
|
||||
selectedStoreSkuList = append(selectedStoreSkuList, respFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
return selectedStoreSkuList
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStoreSkusAct(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
for _, v := range storeSkuList {
|
||||
if vendorActID, err2 := createSkuAct(ctx, putils.GetFixDirectDownAct(vendorOrgCode, storeID, v.SkuID), putils.StoreSku2ActStoreSku(model.SyncFlagNewMask, vendorStoreID, []*partner.StoreSkuInfo{v})); err2 != nil {
|
||||
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
|
||||
StoreSkuInfo: v,
|
||||
VendoreID: model.VendorIDJD,
|
||||
StoreID: storeID,
|
||||
ErrMsg: err2.Error(),
|
||||
})
|
||||
} else {
|
||||
v.VendorActID = vendorActID
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CancelActs(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
for _, v := range storeSkuList {
|
||||
if err2 := cancelSkuAct(ctx, putils.GetFixDirectDownAct(vendorOrgCode, storeID, v.SkuID), v.VendorActID); err2 != nil {
|
||||
failedList = append(failedList, &partner.StoreSkuInfoWithErr{
|
||||
StoreSkuInfo: v,
|
||||
VendoreID: model.VendorIDJD,
|
||||
StoreID: storeID,
|
||||
ErrMsg: err2.Error(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusSpecTag(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
)
|
||||
|
||||
func TestGetStoreSkusBareInfo(t *testing.T) {
|
||||
// list := []*partner.StoreSkuInfo{
|
||||
// &partner.StoreSkuInfo{
|
||||
// SkuID: 2212,
|
||||
// VendorSkuID: "2019458103",
|
||||
// },
|
||||
// }
|
||||
// for i := 0; i < 30-1; i++ {
|
||||
// list = append(list, list[0])
|
||||
// }
|
||||
skuNameList, err := CurPurchaseHandler.GetSkus(jxcontext.AdminCtx, "", 0, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
list := putils.StoreSkuFullList2Bare(skuNameList)
|
||||
|
||||
storeSkuList, err := CurPurchaseHandler.GetStoreSkusBareInfo(jxcontext.AdminCtx, "", nil, 2, "11053496", list)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
var focusedStoreSkuList []*partner.StoreSkuInfo
|
||||
for _, v := range storeSkuList {
|
||||
if v.Stock > 0 {
|
||||
focusedStoreSkuList = append(focusedStoreSkuList, v)
|
||||
}
|
||||
}
|
||||
t.Log(utils.Format4Output(focusedStoreSkuList, false))
|
||||
t.Log(len(focusedStoreSkuList))
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
const (
|
||||
TestStoreNo = 100164
|
||||
TestJdStoreNo = "11736989"
|
||||
)
|
||||
|
||||
func TestReadStore(t *testing.T) {
|
||||
result, err := new(PurchaseHandler).ReadStore(jxcontext.AdminCtx, "", TestJdStoreNo)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
}
|
||||
|
||||
func TestUpdateStore(t *testing.T) {
|
||||
handler := new(PurchaseHandler)
|
||||
result, err := handler.ReadStore(jxcontext.AdminCtx, "", TestJdStoreNo)
|
||||
|
||||
// result := &model.Store{}
|
||||
// result.ID = 100164
|
||||
// err := dao.GetEntity(nil, result)
|
||||
db := dao.GetDB()
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
result.Name += "h"
|
||||
newName := result.Name
|
||||
err = handler.UpdateStore(db, TestStoreNo, "autotest")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
// same
|
||||
result, err = handler.ReadStore(jxcontext.AdminCtx, "", TestJdStoreNo)
|
||||
if result.Name != newName {
|
||||
t.Fatalf("result is not same, desired newName:%s, newName:%s", newName, result.Name)
|
||||
}
|
||||
|
||||
// restore
|
||||
result.Name = strings.Trim(result.Name, "h")
|
||||
err = handler.UpdateStore(db, TestStoreNo, "autotest")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateStore2(t *testing.T) {
|
||||
handler := new(PurchaseHandler)
|
||||
|
||||
// result := &model.Store{}
|
||||
// result.ID = 100164
|
||||
// err := dao.GetEntity(nil, result)
|
||||
db := dao.GetDB()
|
||||
// restore
|
||||
err := handler.UpdateStore(db, 1, "autotest")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// func TestCoordRangeConversion(t *testing.T) {
|
||||
// jxRange := "108841759,34332892;108842271,34330820;108846013,34331422;108846110,34333189;108847722,34331853;108856703,34331729;108866149,34327507;108873423,34320980;108877737,34312856;108877727,34299624;108870105,34287988;108855137,34290911;108867884,34286298;108858260,34281316;108854162,34283490;108853803,34280145;108846110,34279291;108830587,34282539;108818806,34291500;108814493,34299624;108813596,34308465;108818797,34320980;108830582,34329941;108841759,34332892"
|
||||
// jdRange := "108.841759,34.332892;108.842271,34.330820;108.846013,34.331422;108.846110,34.333189;108.847722,34.331853;108.856703,34.331729;108.866149,34.327507;108.873423,34.320980;108.877737,34.312856;108.877727,34.299624;108.870105,34.287988;108.855137,34.290911;108.867884,34.286298;108.858260,34.281316;108.854162,34.283490;108.853803,34.280145;108.846110,34.279291;108.830587,34.282539;108.818806,34.291500;108.814493,34.299624;108.813596,34.308465;108.818797,34.320980;108.830582,34.329941;108.841759,34.332892"
|
||||
|
||||
// if JdRange2JxRange(jdRange) != jxRange {
|
||||
// t.Fatal("result doesn't match")
|
||||
// }
|
||||
|
||||
// if JxRange2JdRange(jxRange) != jdRange {
|
||||
// t.Fatal("result doesn't match")
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestSyncQualify(t *testing.T) {
|
||||
storeDetail, err := dao.GetStoreDetail(dao.GetDB(), 102610, model.VendorIDJD)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
err = CurPurchaseHandler.SyncQualify(jxcontext.AdminCtx, storeDetail)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
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/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) OnWaybillMsg(vendorOrgCode string, msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(vendorOrgCode, msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) onWaybillMsg(vendorOrgCode string, msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
switch msg.DeliveryStatus {
|
||||
case jdapi.DeliveryStatusWait4Grap:
|
||||
order.Status = model.WaybillStatusNew
|
||||
case jdapi.DeliveryStatusAccepted, jdapi.DeliveryStatusCourierChaged: // 将更换配送员也当成接单消息
|
||||
// todo 性能问题,暂时取消调用
|
||||
// if result, err := getAPI(vendorOrgCode).QuerySingleOrder(msg.OrderID); err == nil {
|
||||
// // 默认配送费=订单应付运费(orderReceivableFreight)
|
||||
// //订单应付运费为未优惠前应付运费(满免优惠,运费优惠券,VIP免基础运费,用户小费)ps:用户小费是用户给配送员的小费
|
||||
// order.DesiredFee = utils.Interface2Int64WithDefault(result["orderReceivableFreight"], 0) +
|
||||
// utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0) +
|
||||
// utils.Interface2Int64WithDefault(result["tips"], 0)
|
||||
// }
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
case jdapi.DeliveryStatusCourierCanceled:
|
||||
order.Status = model.WaybillStatusAcceptCanceled
|
||||
case jdapi.DeliveryStatusCourierArrived:
|
||||
order.Status = model.WaybillStatusCourierArrived
|
||||
case jdapi.DeliveryStatusFailedGetGoodsWaiting:
|
||||
order.Status = model.WaybillStatusApplyFailedGetGoods
|
||||
case jdapi.DeliveryStatusFailedGetGoodsRejected:
|
||||
order.Status = model.WaybillStatusRefuseFailedGetGoods
|
||||
case jdapi.DeliveryStatusFailedGetGoods:
|
||||
order.Status = model.WaybillStatusAgreeFailedGetGoods
|
||||
case jdapi.DeliveryStatusGotGoods:
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
case jdapi.DeliveryStatusFailedDelivery:
|
||||
order.Status = model.WaybillStatusDeliverFailed
|
||||
case jdapi.DeliveryStatusFinished:
|
||||
order.Status = model.WaybillStatusDelivered
|
||||
default:
|
||||
order.Status = model.WaybillStatusUnknown
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) callbackMsg2Waybill(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *model.Waybill) {
|
||||
retVal = &model.Waybill{
|
||||
VendorOrderID: msg.OrderID,
|
||||
OrderVendorID: model.VendorIDJD,
|
||||
VendorWaybillID: msg.OrderID,
|
||||
WaybillVendorID: model.VendorIDJD,
|
||||
CourierName: msg.DeliveryManName,
|
||||
CourierMobile: msg.DeliveryManPhone,
|
||||
VendorStatus: msg.DeliveryStatus,
|
||||
StatusTime: utils.Str2Time(msg.DeliveryStatusTime),
|
||||
Remark: msg.Remark,
|
||||
|
||||
VendorOrgCode: AppKey2OrgCode(msg.AppKey),
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
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) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jcqapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/common"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"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 OnCallbackMsg(msg *jdshopapi.CallBackResult) (err error) {
|
||||
msgType := msg.MsgType
|
||||
switch msgType {
|
||||
case jcqapi.TopicOrderPay:
|
||||
utils.CallFuncAsync(func() {
|
||||
SaveJdsOrders(msg)
|
||||
})
|
||||
case jcqapi.TopicOrderCancel:
|
||||
utils.CallFuncAsync(func() {
|
||||
order := getRealOrderID(msg.OrderID)
|
||||
if order != nil {
|
||||
if order.Status != model.OrderStatusCanceled {
|
||||
CurPurchaseHandler.CancelOrder(jxcontext.AdminCtx, order, "系统取消")
|
||||
}
|
||||
}
|
||||
})
|
||||
case jcqapi.TopicOrderOut:
|
||||
utils.CallFuncAsync(func() {
|
||||
globals.SugarLogger.Debugf("jdsOrderOut", utils.Format4Output(msg, false))
|
||||
orders := getAllRealOrderID(msg.OrderID)
|
||||
if len(orders) > 0 {
|
||||
for _, order := range orders {
|
||||
if order.ActualPayPrice == 0 {
|
||||
if jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)) == 0 {
|
||||
order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderTotalPrice) + utils.Str2Float64(msg.FreightPrice) - utils.Str2Float64(msg.SellerDiscount))
|
||||
} else {
|
||||
order.ActualPayPrice = jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment))
|
||||
}
|
||||
order.TotalShopMoney = utils.Float64TwoInt64(float64(order.ActualPayPrice) * jdshopapi.JdsPayPercentage)
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"ActualPayPrice", "TotalShopMoney"})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
default:
|
||||
return fmt.Errorf("暂不支持的topic类型!topic: %v", msgType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SaveJdsOrders(msg *jdshopapi.CallBackResult) (err error) {
|
||||
order, err := result2Orders(msg)
|
||||
if err != nil || order == nil {
|
||||
return err
|
||||
}
|
||||
partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
|
||||
noticeMsg := fmt.Sprintf("京东商城新订单,订单号:[%v] ,将要发到的门店id:[%v] , 门店名:[%v]", order.VendorOrderID, order.StoreID, order.StoreName)
|
||||
if order.OrderType == model.OrderTypeAddressErr {
|
||||
noticeMsg += " 此订单地址有问题,需要矫正坐标!"
|
||||
}
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "DDC5657B43EE11E9A9FF525400E86DC0", "京东商城来新订单了!", noticeMsg)
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "1439B3E07D3911EA881A525400E86DC0", "京东商城来新订单了!", noticeMsg)
|
||||
return err
|
||||
}
|
||||
|
||||
func result2Orders(msg *jdshopapi.CallBackResult) (order *model.GoodsOrder, err error) {
|
||||
//有可能是库里已经有这个订单了
|
||||
orderE, err := partner.CurOrderManager.LoadOrder(msg.OrderID+"000001", model.VendorIDJDShop)
|
||||
if orderE != nil {
|
||||
return order, fmt.Errorf("已经存在此订单!")
|
||||
}
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID2: msg.OrderID,
|
||||
VendorOrderID: msg.OrderID + "000001",
|
||||
VendorID: model.VendorIDJDShop,
|
||||
BaseFreightMoney: jxutils.StandardPrice2Int(utils.Str2Float64(msg.FreightPrice)),
|
||||
VendorStatus: msg.OrderState,
|
||||
VendorUserID: msg.Pin,
|
||||
BuyerComment: msg.OrderRemark,
|
||||
PickDeadline: utils.DefaultTimeValue,
|
||||
OriginalData: string(utils.MustMarshal(msg)),
|
||||
OrderCreatedAt: utils.Str2Time(msg.OrderStartTime),
|
||||
ConsigneeAddress: Decrypt(msg.ConsigneeInfo.FullAddress),
|
||||
ConsigneeName: Decrypt(msg.ConsigneeInfo.Fullname),
|
||||
ConsigneeMobile: Decrypt(msg.ConsigneeInfo.Mobile),
|
||||
ConsigneeMobile2: Decrypt(msg.ConsigneeInfo.Telephone),
|
||||
ActualPayPrice: jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment)),
|
||||
Status: model.OrderStatusNew,
|
||||
TotalShopMoney: utils.Float64TwoInt64(math.Round(float64(jxutils.StandardPrice2Int(utils.Str2Float64(msg.OrderPayment))) * jdshopapi.JdsPayPercentage)),
|
||||
DeliveryType: model.OrderDeliveryTypeStoreSelf,
|
||||
StatusTime: utils.Str2Time(msg.OrderStartTime),
|
||||
OrderSeq: 0,
|
||||
}
|
||||
if order.TotalShopMoney < 100 {
|
||||
order.TotalShopMoney = 100
|
||||
}
|
||||
if order.ConsigneeAddress != "" {
|
||||
lng, lat, err2 := api.AutonaviAPI.GetCoordinateFromAddressByPage(order.ConsigneeAddress)
|
||||
if err = err2; err != nil {
|
||||
globals.SugarLogger.Infof("高德page err: %v", err)
|
||||
}
|
||||
lng2, lat2, _ := api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "")
|
||||
distance := jxutils.EarthDistance(lng, lat, lng2, lat2)
|
||||
if distance > 1 {
|
||||
order.OrderType = model.OrderTypeAddressErr
|
||||
}
|
||||
if err == nil && lng != 0 && lat != 0 {
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng)
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat)
|
||||
} else {
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng2)
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat2)
|
||||
}
|
||||
order.CoordinateType = model.CoordinateTypeMars
|
||||
}
|
||||
for _, v := range msg.ItemInfoList {
|
||||
sku := &model.OrderSku{
|
||||
VendorID: model.VendorIDJDShop,
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
Count: utils.Str2Int(v.ItemTotal),
|
||||
VendorSkuID: v.SkuID,
|
||||
SkuName: v.SkuName,
|
||||
VendorPrice: jxutils.StandardPrice2Int(utils.Str2Float64(v.JdPrice)),
|
||||
SalePrice: jxutils.StandardPrice2Int(utils.Str2Float64(v.JdPrice)),
|
||||
// SkuID: utils.Str2Int(v.OuterSkuID),
|
||||
}
|
||||
if v.OuterSkuID != "" {
|
||||
sku.SkuID = utils.Str2Int(v.OuterSkuID)
|
||||
}
|
||||
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.SkuName)
|
||||
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit)
|
||||
order.Skus = append(order.Skus, sku)
|
||||
}
|
||||
storeList, err := common.GetStoreListByLocation(jxcontext.AdminCtx, jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat), 3000, false, true)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("jds GetStoreListByLocation error: %v", err.Error())
|
||||
return order, err
|
||||
}
|
||||
if len(storeList) > 0 {
|
||||
for _, store := range storeList {
|
||||
order.StoreID = store.ID
|
||||
order.JxStoreID = store.ID
|
||||
order.StoreName = store.Name
|
||||
globals.SugarLogger.Debugf("jds GetStoreListByLocation, orderID: %v storeID :%v", order.VendorOrderID, order.StoreID)
|
||||
//结算类型
|
||||
storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), order.StoreID, model.VendorIDJDShop)
|
||||
if storeDetail != nil {
|
||||
if storeDetail.PayPercentage < 50 {
|
||||
order.EarningType = model.EarningTypePoints
|
||||
} else {
|
||||
order.EarningType = model.EarningTypeQuote
|
||||
}
|
||||
}
|
||||
var (
|
||||
shopPriceSum int
|
||||
saleNormalSum int
|
||||
)
|
||||
for _, sku := range order.Skus {
|
||||
storeSkuList, _ := dao.GetStoresSkusInfo(dao.GetDB(), []int{order.StoreID}, []int{sku.SkuID})
|
||||
if len(storeSkuList) > 0 {
|
||||
if storeSkuList[0].Status == model.StoreSkuBindStatusNormal {
|
||||
saleNormalSum += 1
|
||||
}
|
||||
shopPriceSum += storeSkuList[0].Price * sku.Count
|
||||
}
|
||||
}
|
||||
//可售数小于一半就不行
|
||||
if math.Mod(float64(len(order.Skus)), float64(2)) == 0 {
|
||||
if saleNormalSum < len(order.Skus)/2 {
|
||||
buildOrderTo102919(order)
|
||||
continue
|
||||
} else {
|
||||
if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) {
|
||||
buildOrderTo102919(order)
|
||||
continue
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if saleNormalSum <= len(order.Skus)/2 {
|
||||
buildOrderTo102919(order)
|
||||
continue
|
||||
} else {
|
||||
if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) {
|
||||
buildOrderTo102919(order)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
} else {
|
||||
buildOrderTo102919(order)
|
||||
}
|
||||
storeMaps, _ := dao.GetStoresMapList(dao.GetDB(), []int{model.VendorIDJDShop}, []int{order.StoreID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "")
|
||||
if len(storeMaps) > 0 {
|
||||
order.VendorStoreID = storeMaps[0].VendorStoreID
|
||||
}
|
||||
// 如果是暂停,表示是预订单g
|
||||
if msg.OrderState == jdshopapi.OrderStatusPause || msg.OrderState == jdshopapi.OrderStatusPopPause {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
if time2, err := api.JdShopAPI.GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil {
|
||||
if time2 == "" {
|
||||
order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour)
|
||||
} else {
|
||||
order.ExpectedDeliveredTime = utils.Str2Time(time2).Add(-time.Minute * 30)
|
||||
}
|
||||
}
|
||||
order.PickDeadline = order.ExpectedDeliveredTime.Add(-time.Hour)
|
||||
} else if msg.OrderState == jdshopapi.OrderStatusWait {
|
||||
order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour)
|
||||
order.BusinessType = model.BusinessTypeImmediate
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("暂不支持的京东商城订单类型!type: %v", msg.OrderState)
|
||||
return nil, err
|
||||
}
|
||||
if msg.IDSopShipmenttype == jdshopapi.IdSopShipmenttypeTC {
|
||||
if time2, err := api.JdShopAPI.GetOrderExtInfoByOrderId(order.VendorOrderID2); err == nil {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
order.ExpectedDeliveredTime = utils.Str2Time(time2).Add(-time.Minute * 30)
|
||||
}
|
||||
}
|
||||
setJdsOrderSeq(order)
|
||||
if order.OrderType == model.OrderTypeAddressErr {
|
||||
buildOrderTo102919(order)
|
||||
}
|
||||
return order, err
|
||||
}
|
||||
|
||||
func buildOrderTo102919(order *model.GoodsOrder) {
|
||||
order.StoreID = 102919
|
||||
order.JxStoreID = 102919
|
||||
order.StoreName = "商城模板(成都发货)"
|
||||
order.VendorStoreID = model.JdShopMainVendorStoreID
|
||||
order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
}
|
||||
|
||||
func setJdsOrderSeq(order *model.GoodsOrder) (err error) {
|
||||
type tCount struct {
|
||||
Count int `json:"count"`
|
||||
}
|
||||
var count = &tCount{}
|
||||
sql := `
|
||||
SELECT count(*) count FROM goods_order WHERE store_id = ? AND order_create_at >= ? AND order_create_at <= ? AND vendor_id = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
order.StoreID, utils.Time2Date(time.Now()), utils.Time2Date(time.Now().AddDate(0, 0, 1)), order.VendorID,
|
||||
}
|
||||
err = dao.GetRow(dao.GetDB(), &count, sql, sqlParams)
|
||||
order.OrderSeq = count.Count + 1
|
||||
return err
|
||||
}
|
||||
|
||||
func Decrypt(p string) (result string) {
|
||||
if p == "" {
|
||||
return ""
|
||||
}
|
||||
data, _ := base64.StdEncoding.DecodeString(strings.ReplaceAll(p, " ", "+"))
|
||||
key := GetKey(hex.EncodeToString(data)[4:36])
|
||||
globals.SugarLogger.Debugf("Decrypt keys : %v", key)
|
||||
data2, _ := base64.StdEncoding.DecodeString(key)
|
||||
b := bytes.NewBuffer(data)
|
||||
b.Next(18)
|
||||
iv := make([]byte, 16)
|
||||
b.Read(iv)
|
||||
main := make([]byte, len(data)-18-16)
|
||||
b.Read(main)
|
||||
decryptedData, _ := utils.AESCBCDecpryt(main, data2[:16], iv)
|
||||
return string(decryptedData)
|
||||
}
|
||||
|
||||
func getRealOrderID(orderID string) (order *model.GoodsOrder) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
sql := `
|
||||
SELECT * FROM goods_order WHERE vendor_order_id2 = ? ORDER BY vendor_order_id DESC LIMIT 1
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
orderID,
|
||||
}
|
||||
dao.GetRow(db, &order, sql, sqlParams)
|
||||
return order
|
||||
}
|
||||
|
||||
func getAllRealOrderID(orderID string) (orders []*model.GoodsOrder) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
sql := `
|
||||
SELECT * FROM goods_order WHERE vendor_order_id2 = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
orderID,
|
||||
}
|
||||
dao.GetRows(db, &orders, sql, sqlParams)
|
||||
return orders
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"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/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
CurPurchaseHandler *PurchaseHandler
|
||||
)
|
||||
|
||||
type PurchaseHandler struct {
|
||||
partner.BasePurchasePlatform
|
||||
putils.DefSingleStorePlatform
|
||||
}
|
||||
|
||||
func init() {
|
||||
if api.JdShopAPI != nil {
|
||||
CurPurchaseHandler = New()
|
||||
partner.RegisterPurchasePlatform(CurPurchaseHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func New() (obj *PurchaseHandler) {
|
||||
obj = new(PurchaseHandler)
|
||||
obj.ISingleStoreStoreSkuHandler = obj
|
||||
return obj
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetVendorID() int {
|
||||
return model.VendorIDJDShop
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
|
||||
if globals.EnableJdShopWrite {
|
||||
if imgType > model.ImgTypeLocal {
|
||||
result, err := api.JdShopAPI.UploadPicture(imgData, 0, imgName)
|
||||
if err == nil {
|
||||
imgHint = result.PictureURL
|
||||
}
|
||||
}
|
||||
} else {
|
||||
imgHint = utils.GetUpperUUID()
|
||||
}
|
||||
return imgHint, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetVendorCategories(ctx *jxcontext.Context) (vendorCats []*model.SkuVendorCategory, err error) {
|
||||
result, err := api.JdShopAPI.FindVendorCategories()
|
||||
for _, v := range result {
|
||||
cat := &model.SkuVendorCategory{
|
||||
VendorID: model.VendorIDJDShop,
|
||||
Name: v.Name,
|
||||
Level: v.Lev,
|
||||
VendorCategoryID: utils.Int2Str(v.ID),
|
||||
}
|
||||
if v.Lev > 1 {
|
||||
cat.ParentID = utils.Int2Str(v.Fid)
|
||||
cat.IsLeaf = 1
|
||||
}
|
||||
vendorCats = append(vendorCats, cat)
|
||||
}
|
||||
return vendorCats, err
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
var (
|
||||
KeyList []*Key
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
ID string `json:"id"`
|
||||
KeyExp int64 `json:"key_exp"`
|
||||
KeyStatus int `json:"key_status"`
|
||||
KeyDigest string `json:"key_digest"`
|
||||
KeyType string `json:"key_type"`
|
||||
KeyString string `json:"key_string"`
|
||||
KeyEffective int64 `json:"key_effective"`
|
||||
Version int `json:"version"`
|
||||
}
|
||||
|
||||
func InitKey() {
|
||||
keyResult, err := api.JdShopAPI.KeyGet()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range keyResult.Response.ServiceKeyList[0].Keys {
|
||||
data, _ := json.Marshal(v)
|
||||
vv := &Key{}
|
||||
err = json.Unmarshal(data, &vv)
|
||||
KeyList = append(KeyList, vv)
|
||||
}
|
||||
globals.SugarLogger.Debugf("jdshop key refreshed..")
|
||||
}
|
||||
|
||||
func GetKey(keySign string) (key string) {
|
||||
for _, v := range KeyList {
|
||||
data, _ := base64.StdEncoding.DecodeString(v.ID)
|
||||
if keySign == hex.EncodeToString(data) {
|
||||
return v.KeyString
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Debugf("no key can equal..")
|
||||
return key
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
"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/api"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
result := &jdshopapi.AllOrdersResult{}
|
||||
utils.Map2StructByJson(orderData, &result, false)
|
||||
jdsOrder := result.OrderList[0]
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: utils.Int64ToStr(jdsOrder.OrderID),
|
||||
VendorID: model.VendorIDJDShop,
|
||||
BaseFreightMoney: jxutils.StandardPrice2Int(jdsOrder.Freight),
|
||||
VendorStatus: utils.Int2Str(jdsOrder.OrderStatus),
|
||||
VendorUserID: jdsOrder.UserPin,
|
||||
BuyerComment: jdsOrder.UserRemark,
|
||||
PickDeadline: utils.DefaultTimeValue,
|
||||
OriginalData: string(utils.MustMarshal(jdsOrder)),
|
||||
}
|
||||
return order
|
||||
}
|
||||
func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID string) (order *model.GoodsOrder, err error) {
|
||||
resultOrders, err := api.JdShopAPI.AllOrders(&jdshopapi.AllOrdersParam{
|
||||
OrderID: vendorOrderID,
|
||||
Current: 1,
|
||||
PageSize: 1,
|
||||
})
|
||||
return p.Map2Order(utils.Struct2FlatMap(resultOrders)), err
|
||||
}
|
||||
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
|
||||
jdsOrder, err := GetJdsOrder(vendorOrderID)
|
||||
return status2Jxstatus(jdsOrder.OrderState), err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
var status int
|
||||
if isAcceptIt {
|
||||
status = model.OrderStatusAccepted
|
||||
} else {
|
||||
status = model.OrderStatusCanceled
|
||||
}
|
||||
return ChangeOrderStatus(order.VendorOrderID, status, "")
|
||||
}
|
||||
func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
status, err := p.GetOrderStatus("", order.VendorOrderID2)
|
||||
//说明此时该订单在平台上已经取消了
|
||||
if status == model.OrderStatusCanceled {
|
||||
err = ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, "订单在京东商城已被取消!")
|
||||
} else {
|
||||
err = ChangeOrderStatus(order.VendorOrderID, model.OrderStatusFinishedPickup, "自动拣货完成")
|
||||
err = p.OrderExport(jxcontext.AdminCtx, order.VendorOrderID, order.VendorOrderID, true)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
return err
|
||||
} // 取货失败后再次招唤平台配送
|
||||
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
return err
|
||||
} // 投递失败后确认收到退货
|
||||
func (p *PurchaseHandler) CanSwitch2SelfDeliver(order *model.GoodsOrder) (isCan bool, err error) {
|
||||
return isCan, err
|
||||
}
|
||||
func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
ChangeOrderStatus(order.VendorOrderID, model.OrderStatusDelivering, "")
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
ChangeOrderStatus(order.VendorOrderID, model.OrderStatusFinished, "")
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
|
||||
return mobile, err
|
||||
}
|
||||
func (p *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, reason)
|
||||
if order.EclpOutID != "" {
|
||||
_, err = api.JdEclpAPI.CancelOrder(order.EclpOutID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
func (p *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
diffShopPrice int64
|
||||
diffSalePrice int64
|
||||
)
|
||||
if order.Status >= model.OrderStatusDelivering {
|
||||
return fmt.Errorf("配送中以后的订单无法进行售前退款!")
|
||||
}
|
||||
//1、删除原order_sku 中售前调整的商品
|
||||
for _, sku := range removedSkuList {
|
||||
sql := `DELETE FROM order_sku WHERE vendor_order_id = ? AND vendor_id = ? AND sku_id = ?`
|
||||
sqlParams := []interface{}{order.VendorOrderID, order.VendorID, sku.SkuID}
|
||||
dao.ExecuteSQL(db, sql, sqlParams)
|
||||
|
||||
diffShopPrice += sku.ShopPrice
|
||||
diffSalePrice += sku.SalePrice
|
||||
}
|
||||
//2、修改goods_order 中的shopprice,若是扣点的订单,还要改new_earning_price和total_shop_money
|
||||
order.AdjustCount += 1
|
||||
order.ShopPrice = order.ShopPrice - diffShopPrice
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
order.TotalShopMoney = utils.Float64TwoInt64(float64(float64(order.TotalShopMoney)/jdshopapi.JdsPayPercentage-float64(diffSalePrice)) * jdshopapi.JdsPayPercentage)
|
||||
jxutils.RefreshOrderEarningPrice2(order, order.OrderPayPercentage)
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"TotalShopMoney", "NewEarningPrice"})
|
||||
}
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"AdjustCount", "ShopPrice"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetJdsOrders(ctx *jxcontext.Context, orderCreatedStart, orderCreatedEnd string, current, pageSize int) (orderResult *jdshopapi.AllOrdersResult, err error) {
|
||||
orderResult, err = api.JdShopAPI.AllOrders(&jdshopapi.AllOrdersParam{
|
||||
Current: current,
|
||||
PageSize: pageSize,
|
||||
OrderCreateDateRange: []string{orderCreatedStart, orderCreatedEnd},
|
||||
})
|
||||
return orderResult, err
|
||||
}
|
||||
|
||||
func ChangeOrderStatus(vendorOrderID string, status int, remark string) (err error) {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: vendorOrderID,
|
||||
VendorID: model.VendorIDJDShop,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: model.VendorIDJDShop,
|
||||
VendorStatus: utils.Int2Str(status),
|
||||
Status: status,
|
||||
StatusTime: time.Now(),
|
||||
Remark: remark,
|
||||
}
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, model.VendorIDJDShop))
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) OrderExport(ctx *jxcontext.Context, vendorOrderID, vendorWaybillID string, isAuto bool) (err error) {
|
||||
companyID := jdshopapi.JdsDeliveryCompany3rd
|
||||
//表示是门店手动发京东
|
||||
if !isAuto {
|
||||
companyID = jdshopapi.JdsDeliveryCompanyJD
|
||||
}
|
||||
err = api.JdShopAPI.OrderShipment(utils.Str2Int64(vendorOrderID[:12]), companyID, vendorWaybillID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) OrderTransfer(ctx *jxcontext.Context, vendorOrderID, vendorWaybillID string, isAuto bool) (err error) {
|
||||
companyID := jdshopapi.JdsDeliveryCompany3rd
|
||||
//表示是门店手动发京东
|
||||
if !isAuto {
|
||||
companyID = jdshopapi.JdsDeliveryCompanyJD
|
||||
}
|
||||
err = api.JdShopAPI.UpdateWaybill(vendorOrderID[:12], companyID, vendorOrderID)
|
||||
return err
|
||||
}
|
||||
|
||||
func status2Jxstatus(status string) (statusJx int) {
|
||||
if status == jdshopapi.OrderStatusPopPause || status == jdshopapi.OrderStatusPause {
|
||||
statusJx = model.OrderStatusNew
|
||||
} else if status == jdshopapi.OrderStatusWait {
|
||||
statusJx = model.OrderStatusAccepted
|
||||
} else if status == jdshopapi.OrderStatusCancel {
|
||||
statusJx = model.OrderStatusCanceled
|
||||
}
|
||||
return statusJx
|
||||
}
|
||||
|
||||
const (
|
||||
ProdURL = "http://116.196.82.188:8080/v2/"
|
||||
)
|
||||
|
||||
func apiToYd(url string, params map[string]interface{}) (retVal map[string]interface{}, err error) {
|
||||
cl := &http.Client{}
|
||||
err = platformapi.AccessPlatformAPIWithRetry(cl,
|
||||
func() *http.Request {
|
||||
request, _ := http.NewRequest(http.MethodPost, ProdURL+url, strings.NewReader(utils.Map2URLValues(params).Encode()))
|
||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
return request
|
||||
},
|
||||
nil,
|
||||
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
|
||||
if jsonResult1 == nil {
|
||||
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
|
||||
}
|
||||
if err == nil {
|
||||
if jsonResult1["code"] != nil {
|
||||
if utils.Interface2Int64WithDefault(jsonResult1["code"], 0) != 0 {
|
||||
errLevel = platformapi.ErrLevelGeneralFail
|
||||
err = utils.NewErrorCode(jsonResult1["desc"].(string), jsonResult1["code"].(string))
|
||||
baseapi.SugarLogger.Debugf("yd AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
|
||||
}
|
||||
}
|
||||
retVal = jsonResult1
|
||||
}
|
||||
return errLevel, err
|
||||
})
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func GetJdsOrder(vendorOrderID string) (jdsOrder *jdshopapi.GetOrderResult, err error) {
|
||||
params := make(map[string]interface{})
|
||||
params["orderID"] = vendorOrderID
|
||||
params["token"] = jdshopapi.JdsYdToken
|
||||
result, err := apiToYd("order/GetJdsOrder", params)
|
||||
jdsOrder2 := &jdshopapi.GetOrderResult{}
|
||||
err = utils.UnmarshalUseNumber([]byte(strings.ReplaceAll(result["data"].(string), "\\", "")), &jdsOrder2)
|
||||
return jdsOrder2, err
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"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"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrder *model.AfsOrder, approveType int, reason string) (err error) {
|
||||
var status int
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
status = model.AfsOrderStatusFailed
|
||||
} else {
|
||||
status = model.AfsOrderStatusFinished
|
||||
|
||||
}
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: afsOrder.AfsOrderID, // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: afsOrder.VendorID,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: afsOrder.VendorOrderID,
|
||||
RefVendorID: afsOrder.VendorID,
|
||||
VendorStatus: utils.Int2Str(status),
|
||||
Status: status,
|
||||
StatusTime: time.Now(),
|
||||
Remark: reason,
|
||||
}
|
||||
partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
|
||||
return err
|
||||
}
|
||||
|
||||
// 确认收到退货
|
||||
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
|
||||
err = fmt.Errorf("京东商城当前不支持ConfirmReceivedReturnGoods")
|
||||
return err
|
||||
}
|
||||
|
||||
// 发起全款退款
|
||||
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
err = c.PartRefundOrder(ctx, order, order.Skus, reason)
|
||||
return err
|
||||
}
|
||||
|
||||
// 发起部分退款
|
||||
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
globals.SugarLogger.Debugf("PartRefundOrder jdshop, orderID :%v", order.VendorOrderID)
|
||||
var (
|
||||
skuMap = make(map[int]*model.OrderSku)
|
||||
salePrice int64
|
||||
db = dao.GetDB()
|
||||
)
|
||||
for _, sku := range order.Skus {
|
||||
skuMap[sku.SkuID] = sku
|
||||
}
|
||||
orderStatus := buildOrderStatus(ctx, order, reason)
|
||||
afsOrder := &model.AfsOrder{
|
||||
VendorID: order.VendorID,
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorOrderID: orderStatus.RefVendorOrderID,
|
||||
// VendorStoreID: order.VendorStoreID,
|
||||
// StoreID: jxutils.GetSaleStoreIDFromOrder(order),
|
||||
AfsCreatedAt: time.Now(),
|
||||
VendorAppealType: "",
|
||||
AppealType: model.AfsAppealTypeRefund,
|
||||
VendorReasonType: utils.Int2Str(model.AfsReasonNotOthers),
|
||||
ReasonType: model.AfsReasonNotOthers,
|
||||
ReasonDesc: utils.LimitUTF8StringLen(reason, 1024),
|
||||
ReasonImgList: "",
|
||||
RefundType: model.AfsTypePartRefund,
|
||||
|
||||
VendorOrgCode: "",
|
||||
}
|
||||
for _, sku := range refundSkuList {
|
||||
orderSku := &model.OrderSkuFinancial{
|
||||
Count: sku.Count,
|
||||
VendorSkuID: utils.Int2Str(sku.SkuID),
|
||||
SkuID: sku.SkuID,
|
||||
}
|
||||
storeSkus, _ := dao.GetStoresSkusInfo(db, []int{model.JdShopMainStoreID}, []int{sku.SkuID})
|
||||
if len(storeSkus) > 0 {
|
||||
orderSku.VendorSkuID = utils.Int64ToStr(storeSkus[0].JdsID)
|
||||
}
|
||||
if skuMap[sku.SkuID] != nil {
|
||||
orderSku.Name = skuMap[sku.SkuID].SkuName
|
||||
orderSku.UserMoney = skuMap[sku.SkuID].SalePrice * int64(sku.Count)
|
||||
salePrice += skuMap[sku.SkuID].SalePrice * int64(sku.Count)
|
||||
}
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||||
}
|
||||
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
|
||||
return err
|
||||
}
|
||||
|
||||
func buildOrderStatus(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (orderStatus *model.OrderStatus) {
|
||||
orderStatus = &model.OrderStatus{
|
||||
VendorOrderID: utils.Int64ToStr(GenAfsOrderNo(ctx)), // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: order.VendorID,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
RefVendorID: order.VendorID,
|
||||
VendorStatus: utils.Int2Str(model.AfsOrderStatusWait4Approve),
|
||||
Status: model.AfsOrderStatusWait4Approve,
|
||||
StatusTime: time.Now(),
|
||||
Remark: reason,
|
||||
}
|
||||
orderStatus.Status = model.AfsOrderStatusWait4Approve
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func GenAfsOrderNo(ctx *jxcontext.Context) (orderNo int64) {
|
||||
const prefix = 70
|
||||
const randPartNum = 100
|
||||
orderNoBeginTimestamp := utils.Str2Time("2010-01-01 00:00:00").Unix()
|
||||
orderNo = time.Now().Unix() - orderNoBeginTimestamp
|
||||
orderNo = orderNo * randPartNum
|
||||
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
|
||||
randPart := 0
|
||||
for k, v := range md5Bytes {
|
||||
randPart += int(v) << ((k % 3) * 8)
|
||||
}
|
||||
orderNo += int64(randPart % randPartNum)
|
||||
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
|
||||
return orderNo
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
func (c *PurchaseHandler) StartRefreshComment() {
|
||||
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
"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/globals/api"
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) ReadStore(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string) (storeDetail *dao.StoreDetail, err error) {
|
||||
// result, err := api.JdShopAPI.NewInfoList(utils.Str2Int64(vendorStoreID))
|
||||
// storeDetail.VendorStoreID = vendorStoreID
|
||||
// storeDetail.Status = JdsStatus2jxStatus(result.StoreStatus)
|
||||
result2, err := api.JdShopAPI.QueryEntityStore(utils.Str2Int64(vendorStoreID))
|
||||
if result2 == nil {
|
||||
return storeDetail, fmt.Errorf("未查询到该平台门店,平台门店ID:[%v]", vendorStoreID)
|
||||
}
|
||||
storeDetail = &dao.StoreDetail{}
|
||||
storeDetail.ID = utils.Str2Int(result2.ExStoreID)
|
||||
storeDetail.Name = result2.StoreName
|
||||
storeDetail.Address = result2.Address
|
||||
storeDetail.Tel1 = result2.Phone
|
||||
storeDetail.DistrictCode = result2.AddrCode
|
||||
zbs := strings.Split(result2.Coordinate, ",")
|
||||
storeDetail.Lat = jxutils.StandardCoordinate2Int(utils.Str2Float64(zbs[0]))
|
||||
storeDetail.Lng = jxutils.StandardCoordinate2Int(utils.Str2Float64(zbs[1]))
|
||||
return storeDetail, err
|
||||
}
|
||||
|
||||
// stoerIDs为nil表示所有
|
||||
func (p *PurchaseHandler) UpdateStore(db *dao.DaoDB, storeID int, userName string) (err error) {
|
||||
store, err := dao.GetStoreDetail(db, storeID, model.VendorIDJDShop)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, _, err := jxutils.DownloadFileByURL(jdshopapi.JdsStoreImg)
|
||||
timeMap := map[string]string{
|
||||
"businessBeginTime": int2TimeStr(int(store.OpenTime1)),
|
||||
"businessEndTime": int2TimeStr(int(store.CloseTime1)),
|
||||
}
|
||||
timeJSON, _ := json.Marshal(timeMap)
|
||||
updateEntityStoreParam := &jdshopapi.UpdateEntityStoreParam{
|
||||
StoreID: utils.Str2Int(store.VendorStoreID),
|
||||
Name: store.Name,
|
||||
AddCode: store.JdsCode,
|
||||
AddCodeName: store.DistrictName,
|
||||
AddName: store.ProvinceName + store.CityName + store.DistrictName + "@!" + store.Address,
|
||||
Coordinate: utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lat)) + "," + utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lng)),
|
||||
Phone: store.Tel1,
|
||||
ExtendJSON: string(timeJSON),
|
||||
ImageFile: base64.StdEncoding.EncodeToString(data),
|
||||
CustomerID: utils.Int2Str(store.ID),
|
||||
}
|
||||
if store.JdsStreetCode != 0 {
|
||||
updateEntityStoreParam.AddCode = store.JdsStreetCode
|
||||
}
|
||||
if updateEntityStoreParam.AddCode == 0 {
|
||||
updateEntityStoreParam.AddCode = store.JdCode
|
||||
}
|
||||
err = api.JdShopAPI.UpdateEntityStore(updateEntityStoreParam)
|
||||
if err == nil {
|
||||
// if store.SyncStatus&(model.SyncFlagNewMask|model.SyncFlagStoreStatus) != 0 {
|
||||
// mergeStatus := jxutils.MergeStoreStatus(store.Status, store.VendorStatus)
|
||||
// err = api.JdShopAPI.UpdateStoreStatus(utils.Str2Int(store.VendorStoreID), jxStatus2JdsStatus(mergeStatus))
|
||||
// }
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStore2(db *dao.DaoDB, storeID int, userName string) (vendorStoreID string, err error) {
|
||||
store, err := dao.GetStoreDetail(db, storeID, model.VendorIDJDShop)
|
||||
if err != nil {
|
||||
return vendorStoreID, err
|
||||
}
|
||||
data, _, err := jxutils.DownloadFileByURL(jdshopapi.JdsStoreImg)
|
||||
timeMap := map[string]string{
|
||||
"businessBeginTime": int2TimeStr(int(store.OpenTime1)),
|
||||
"businessEndTime": int2TimeStr(int(store.CloseTime1)),
|
||||
}
|
||||
timeJSON, _ := json.Marshal(timeMap)
|
||||
createEntityStoreParam := &jdshopapi.CreateEntityStoreParam{
|
||||
Name: store.Name,
|
||||
AddCode: store.JdsCode,
|
||||
AddCodeName: store.DistrictName,
|
||||
AddName: store.ProvinceName + store.CityName + store.DistrictName + "@!" + store.Address,
|
||||
Coordinate: utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lat)) + "," + utils.Float64ToStr(jxutils.IntCoordinate2Standard(store.Lng)),
|
||||
Phone: store.Tel1,
|
||||
ExtendJSON: string(timeJSON),
|
||||
ImageFile: base64.StdEncoding.EncodeToString(data),
|
||||
CategoryName: jdshopapi.JdsStoreCategoryName,
|
||||
CustomerID: utils.Int2Str(store.ID),
|
||||
}
|
||||
if store.JdsStreetCode != 0 {
|
||||
createEntityStoreParam.AddCode = store.JdsStreetCode
|
||||
}
|
||||
if createEntityStoreParam.AddCode == 0 {
|
||||
createEntityStoreParam.AddCode = store.JdCode
|
||||
}
|
||||
//证明这个店可能隶属直辖市或者东莞
|
||||
if model.ZXCityCodeMap[store.CityCode] != "" {
|
||||
result, _ := api.AutonaviAPI.GetCoordinateAreaInfo(jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat))
|
||||
if result["regeocode"] != nil {
|
||||
street := result["regeocode"].(map[string]interface{})["addressComponent"].(map[string]interface{})["township"].(string)
|
||||
if street != "" {
|
||||
result1, _ := api.JdShopAPI.GetProvince()
|
||||
for _, v := range result1 {
|
||||
if strings.Contains(store.CityName, v.AreaName) {
|
||||
result2, _ := api.JdShopAPI.GetCity(v.AreaID)
|
||||
for _, vv := range result2 {
|
||||
if strings.Contains(store.DistrictName, vv.AreaName) {
|
||||
result3, _ := api.JdShopAPI.GetCounty(vv.AreaID)
|
||||
for _, vvv := range result3 {
|
||||
if street == vvv.AreaName {
|
||||
createEntityStoreParam.AddCode = vvv.AreaID
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vendorStoreID, err = api.JdShopAPI.CreateEntityStore(createEntityStoreParam)
|
||||
return vendorStoreID, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStore(db *dao.DaoDB, storeID int, userName string) (err error) {
|
||||
// store, err := dao.GetStoreDetail(db, storeID, model.VendorIDJDShop)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = api.JdShopAPI.DeleteStoresByID(utils.Str2Int64(store.VendorStoreID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) RefreshAllStoresID(ctx *jxcontext.Context, parentTask tasksch.ITask, isAsync bool) (hint string, err error) {
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string) (storeStatus int, err error) {
|
||||
return storeStatus, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) EnableAutoAcceptOrder(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, isSetEnable bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, status int) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreOpTime(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, opTimeList []int16) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetAllStoresVendorID(ctx *jxcontext.Context, vendorOrgCode string) (vendorStoreIDs []string, err error) {
|
||||
return vendorStoreIDs, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) UpdateStoreCustomID(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID string, storeID int64) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func int2TimeStr(time int) (str string) {
|
||||
str += utils.Int2Str(time / 1000)
|
||||
str += utils.Int2Str(time % 1000 / 100)
|
||||
str += ":"
|
||||
str += utils.Int2Str(time % 100 / 10)
|
||||
str += utils.Int2Str(time % 10)
|
||||
return str
|
||||
}
|
||||
|
||||
func jxStatus2JdsStatus(status int) (result int) {
|
||||
if status == model.StoreStatusOpened {
|
||||
result = jdshopapi.JdsStoreStatusOnline
|
||||
} else if status == model.StoreStatusHaveRest || status == model.StoreStatusClosed {
|
||||
result = jdshopapi.JdsStoreStatusRest
|
||||
} else {
|
||||
result = jdshopapi.JdsStoreStatusDisable
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func JdsStatus2jxStatus(status int) (result int) {
|
||||
if status == jdshopapi.JdsStoreStatusOnline {
|
||||
result = model.StoreStatusOpened
|
||||
} else if status == jdshopapi.JdsStoreStatusRest {
|
||||
result = model.StoreStatusClosed
|
||||
} else {
|
||||
result = model.StoreStatusDisabled
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,896 +0,0 @@
|
||||
package jdshop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/yinbaoapi"
|
||||
"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/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
deleteErr1 = "已经删除的不能直接下架"
|
||||
deleteErr2 = "SKU"
|
||||
deleteErr3 = "已删除"
|
||||
)
|
||||
|
||||
var (
|
||||
sensitiveWordRegexp = regexp.MustCompile(`商品名称中含有敏感词(\[.*\])`)
|
||||
)
|
||||
|
||||
func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
for _, v := range storeSkuList {
|
||||
//判断京东商城上是否有这个商品了,如果有就是添加规格而不是创建商品
|
||||
name := filterSensitiveWord(v.Name)
|
||||
flag := false
|
||||
result, err := api.JdShopAPI.SearchWare4Valid(name, 1, 100)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
|
||||
return failedList, err
|
||||
}
|
||||
for _, v := range result.Data {
|
||||
if v.Title == name {
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if result.TotalItem > 0 && len(result.Data) > 0 && flag {
|
||||
for _, vv := range v.StoreSkuSyncInfoJds {
|
||||
v.JdsWareID = result.Data[0].WareID
|
||||
vv.JdsWareID = result.Data[0].WareID
|
||||
updateSkusParam, err := buildUpdateSkusParam(v, vv, true)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
|
||||
return failedList, err
|
||||
}
|
||||
vendorSkuID, err := api.JdShopAPI.UpdateSkus(updateSkusParam)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
|
||||
return failedList, err
|
||||
}
|
||||
vv.VendorSkuID = vendorSkuID
|
||||
}
|
||||
} else {
|
||||
createSkuParamWare, createSkuParamSkus, err := buildCreateWareParam(v)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
|
||||
return failedList, err
|
||||
}
|
||||
createSkuResult, err := api.JdShopAPI.CreateWare(createSkuParamWare, createSkuParamSkus)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "创建商品")
|
||||
return failedList, err
|
||||
} else {
|
||||
//追加商品透图
|
||||
imageURL := ""
|
||||
img := v.Img
|
||||
if img != "" {
|
||||
suffix := img[strings.LastIndex(img, "."):]
|
||||
if suffix != ".png" {
|
||||
if resBinary, _, _ := jxutils.DownloadFileByURL(img + model.SkuNameImgToPng); err == nil {
|
||||
downloadURL, _ := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix()))
|
||||
imageURL, _ = uploadImg(downloadURL, name, "tou")
|
||||
}
|
||||
} else {
|
||||
imageURL, _ = uploadImg(img, name, "tou")
|
||||
}
|
||||
}
|
||||
api.JdShopAPI.TransparentImageAdd(createSkuResult.WareID, imageURL)
|
||||
}
|
||||
var paramAttrs = make(map[string]*jdshopapi.CreateSkuParamSkus)
|
||||
var resultAttrs = make(map[string]int64)
|
||||
for _, vv := range createSkuParamSkus {
|
||||
for _, vvv := range vv.SaleAttrs {
|
||||
paramAttrs[vvv.AttrValues[0]] = vv
|
||||
}
|
||||
}
|
||||
for _, vv1 := range createSkuResult.Skus {
|
||||
for _, vvv1 := range vv1.SaleAttrs {
|
||||
if paramAttrs[vvv1.AttrValues[0]] != nil {
|
||||
resultAttrs[paramAttrs[vvv1.AttrValues[0]].OuterID] = vv1.SkuID
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, vv2 := range v.StoreSkuSyncInfoJds {
|
||||
vv2.JdsWareID = createSkuResult.WareID
|
||||
if resultAttrs[utils.Int2Str(vv2.SkuID)] != 0 {
|
||||
vv2.VendorSkuID = utils.Int64ToStr(resultAttrs[utils.Int2Str(vv2.SkuID)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
for _, v := range storeSkuList {
|
||||
name := filterSensitiveWord(v.Name)
|
||||
updateWareParam := &jdshopapi.UpdateWareParam{
|
||||
WareID: v.JdsWareID,
|
||||
Title: name,
|
||||
VenderID: jdshopapi.VenderID,
|
||||
// PromiseID: jdshopapi.JdsPromiseID,
|
||||
ShopCategorys: []int{utils.Str2Int(v.VendorCatID)},
|
||||
JdPrice: jxutils.IntPrice2Standard(v.UnitPrice),
|
||||
}
|
||||
if v.VendorVendorCatID != jdshopapi.JdsOtherMeatCatID {
|
||||
updateWareParam.PromiseID = jdshopapi.JdsPromiseID
|
||||
}
|
||||
var desc string
|
||||
if v.DescImg != "" {
|
||||
pic3, err2 := uploadImg2(v.DescImg, name, "desc")
|
||||
err = err2
|
||||
desc = `<p><img src="` + jdshopapi.JdsImgURL + pic3 + `" style="width: auto; height: auto; max-width: 100%;"><br></p><p><br></p>`
|
||||
} else {
|
||||
desc = `<p><br></p><p><br></p>`
|
||||
}
|
||||
updateWareParam.Introduction = desc
|
||||
updateWareParam.MobileDesc = desc
|
||||
img := ""
|
||||
if v.ImgMix != "" {
|
||||
img = v.ImgMix
|
||||
} else {
|
||||
img = v.Img
|
||||
}
|
||||
if img != "" {
|
||||
pic1, err2 := uploadImg2(img, name, "1")
|
||||
err = err2
|
||||
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 1, pic1)
|
||||
if v.Img2 != "" {
|
||||
pic2, err2 := uploadImg2(v.Img2, name, "2")
|
||||
err = err2
|
||||
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 2, pic2)
|
||||
} else {
|
||||
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 2, pic1)
|
||||
}
|
||||
err = api.JdShopAPI.ImageUpdate(v.JdsWareID, 3, pic1)
|
||||
}
|
||||
var features = []*jdshopapi.CreateSkuParamFeatures{
|
||||
&jdshopapi.CreateSkuParamFeatures{
|
||||
Key: "is7ToReturn", //不支持7天无理由退货
|
||||
Value: "0",
|
||||
},
|
||||
&jdshopapi.CreateSkuParamFeatures{
|
||||
Key: "tssp", //支持自提
|
||||
Value: "",
|
||||
},
|
||||
// &jdshopapi.CreateSkuParamFeatures{
|
||||
// Key: "fdms", //分单?
|
||||
// Value: "1",
|
||||
// },
|
||||
}
|
||||
updateWareParam.Features = features
|
||||
err = api.JdShopAPI.UpdateWare(updateWareParam)
|
||||
if err == nil {
|
||||
//追加商品透图
|
||||
imageURL := ""
|
||||
img := v.Img
|
||||
if img != "" {
|
||||
suffix := img[strings.LastIndex(img, "."):]
|
||||
if suffix != ".png" {
|
||||
if resBinary, _, err := jxutils.DownloadFileByURL(img + model.SkuNameImgToPng); err == nil {
|
||||
downloadURL, err2 := jxutils.UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix()))
|
||||
err = err2
|
||||
imageURL, err = uploadImg(downloadURL, name, "tou")
|
||||
}
|
||||
} else {
|
||||
imageURL, err = uploadImg(img, name, "tou")
|
||||
}
|
||||
}
|
||||
api.JdShopAPI.TransparentImageAdd(v.JdsWareID, imageURL)
|
||||
}
|
||||
for _, vv := range v.StoreSkuSyncInfoJds {
|
||||
updateSkusParam, err := buildUpdateSkusParam(v, vv, false)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "更新商品基础信息")
|
||||
return failedList, err
|
||||
}
|
||||
_, err = api.JdShopAPI.UpdateSkus(updateSkusParam)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "更新商品基础信息")
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
for _, v := range storeSkuList {
|
||||
if v.IsDeletedBySku {
|
||||
err = api.JdShopAPI.DeleteSku(utils.Str2Int64(v.VendorSkuID))
|
||||
} else {
|
||||
err = api.JdShopAPI.UpOrDown(utils.Str2Int64(v.VendorSkuID2), 2)
|
||||
if err == nil {
|
||||
err = api.JdShopAPI.DeleteWare(utils.Str2Int(v.VendorSkuID2))
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "删除商品")...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
|
||||
var (
|
||||
pageNo = 1
|
||||
pageSize = 20
|
||||
)
|
||||
_, totalCount, err := api.JdShopAPI.SearchSkuList(pageNo, pageSize)
|
||||
for ; pageNo <= totalCount/pageSize+1; pageNo++ {
|
||||
result, _, err := api.JdShopAPI.SearchSkuList(pageNo, pageSize)
|
||||
if err == nil {
|
||||
for _, v := range result {
|
||||
if skuName := vendorSku2Jx(v); skuName != nil {
|
||||
skuNameList = append(skuNameList, skuName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return skuNameList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableJdShopWrite {
|
||||
var stock = 0
|
||||
for _, v := range storeSkuList {
|
||||
if storeID == model.JdShopMainStoreID {
|
||||
if status == model.SkuStatusNormal {
|
||||
stock = 9999
|
||||
}
|
||||
if v.JdsStockSwitch == model.NO {
|
||||
stock = 0
|
||||
}
|
||||
err = api.JdShopAPI.UpdateSkuStock(utils.Str2Int(v.VendorSkuID), stock)
|
||||
} else {
|
||||
storeSkus, err2 := dao.GetStoresSkusInfo(dao.GetDB(), []int{model.JdShopMainStoreID}, []int{v.SkuID})
|
||||
err = err2
|
||||
if len(storeSkus) > 0 {
|
||||
if storeSkus[0].JdsID != 0 && vendorStoreID != "" {
|
||||
if storeSkus[0].Status == model.SkuStatusNormal {
|
||||
stock = 9999
|
||||
}
|
||||
err = api.JdShopAPI.UpdateSkuSiteStock(storeSkus[0].JdsID, stock, utils.Str2Int(vendorStoreID))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "修改商品库存")
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
for _, v := range storeSkuList {
|
||||
err = api.JdShopAPI.UpdateSkuJdPrice(utils.Str2Int(v.VendorSkuID), jxutils.IntPrice2Standard(v.VendorPrice))
|
||||
if err != nil {
|
||||
failedList = append(failedList, putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDJDShop], "修改商品价格")...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
|
||||
if globals.EnableJdShopWrite {
|
||||
|
||||
}
|
||||
return failedList, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
|
||||
result, err := api.JdShopAPI.FindShopCategories()
|
||||
for _, v := range result {
|
||||
var cat = &partner.BareCategoryInfo{
|
||||
VendorCatID: utils.Int64ToStr(v.CID),
|
||||
Name: v.Name,
|
||||
}
|
||||
if v.ParentCID == 0 {
|
||||
cat.Level = 1
|
||||
} else {
|
||||
cat.Level = 2
|
||||
}
|
||||
cats = append(cats, cat)
|
||||
}
|
||||
return cats, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
status, err2 := updateOrCreateCategories(storeCat, true)
|
||||
err = err2
|
||||
if status == -1 {
|
||||
return fmt.Errorf("京东商城店内分类创建失败!")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
// flag := false
|
||||
// for {
|
||||
result, err := api.JdShopAPI.FindShopCategories()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range result {
|
||||
if v.Name == storeCat.Name {
|
||||
storeCat.VendorCatID = utils.Int64ToStr(v.CID)
|
||||
// flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if storeCat.VendorCatID == "" {
|
||||
return fmt.Errorf("京东商城店内分类创建可能失败了!storeID: %v", storeID)
|
||||
}
|
||||
// if flag {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
status, err2 := updateOrCreateCategories(storeCat, false)
|
||||
err = err2
|
||||
if status == -1 {
|
||||
return fmt.Errorf("京东商城店内分类更新失败!")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
|
||||
if globals.EnableJdShopWrite && vendorStoreID == model.JdShopMainVendorStoreID {
|
||||
_, err = api.JdShopAPI.DeleteShopCategory(utils.Str2Int64(vendorCatID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
|
||||
return sensitiveWordRegexp
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
|
||||
if strings.Contains(err.Error(), deleteErr1) || (strings.Contains(err.Error(), deleteErr2) && strings.Contains(err.Error(), deleteErr3)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ybSkuStatus2Jx(ybStatus int) (jxSkuStatus int) {
|
||||
if ybStatus == yinbaoapi.SkuStatusEnable {
|
||||
jxSkuStatus = model.SkuStatusNormal
|
||||
} else if ybStatus == yinbaoapi.SkuStatusDisabled {
|
||||
jxSkuStatus = model.SkuStatusDontSale
|
||||
} else if ybStatus == yinbaoapi.SkuStatusDeleted {
|
||||
jxSkuStatus = model.SkuStatusDeleted
|
||||
}
|
||||
return jxSkuStatus
|
||||
}
|
||||
|
||||
func vendorSku2Jx(result *jdshopapi.SearchSkuListResult) (skuName *partner.SkuNameInfo) {
|
||||
if result == nil {
|
||||
globals.SugarLogger.Warnf("vendorSku2Jx, strange result:%s", utils.Format4Output(result, true))
|
||||
return nil
|
||||
}
|
||||
skuName = &partner.SkuNameInfo{
|
||||
VendorNameID: utils.Int64ToStr(result.WareID),
|
||||
SkuList: []*partner.SkuInfo{
|
||||
&partner.SkuInfo{
|
||||
StoreSkuInfo: partner.StoreSkuInfo{
|
||||
SkuID: utils.Str2Int(result.OuterID),
|
||||
VendorSkuID: utils.Int64ToStr(result.SkuID),
|
||||
VendorNameID: utils.Int64ToStr(result.WareID),
|
||||
Stock: result.StockNum,
|
||||
VendorPrice: utils.Float64TwoInt64(result.JdPrice * 100),
|
||||
},
|
||||
Comment: result.SaleAttrs[0].AttrValueAlias[0],
|
||||
},
|
||||
},
|
||||
}
|
||||
return skuName
|
||||
}
|
||||
|
||||
func updateOrCreateCategories(storeCat *dao.SkuStoreCatInfo, isCreate bool) (status int64, err error) {
|
||||
var createShopCategoryParams []*jdshopapi.CreateShopCategoryParam
|
||||
result, err := api.JdShopAPI.FindShopCategories()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
for _, v := range result {
|
||||
createShopCategoryParam := &jdshopapi.CreateShopCategoryParam{
|
||||
HomeShow: "0",
|
||||
ID: utils.Int64ToStr(v.CID),
|
||||
Open: "",
|
||||
OrderNo: utils.Int2Str(v.OrderNo),
|
||||
ParentID: utils.Int64ToStr(v.ParentCID),
|
||||
Title: v.Name,
|
||||
Type: jdshopapi.UpdateCatType,
|
||||
}
|
||||
createShopCategoryParams = append(createShopCategoryParams, createShopCategoryParam)
|
||||
}
|
||||
createShopCategoryParam2 := &jdshopapi.CreateShopCategoryParam{
|
||||
HomeShow: "0",
|
||||
Open: "",
|
||||
OrderNo: utils.Int2Str(storeCat.Seq),
|
||||
ParentID: storeCat.ParentVendorCatID,
|
||||
Title: storeCat.Name,
|
||||
}
|
||||
if isCreate {
|
||||
createShopCategoryParam2.Type = jdshopapi.CreateCatType
|
||||
createShopCategoryParam2.ID = "1"
|
||||
createShopCategoryParams = append(createShopCategoryParams, createShopCategoryParam2)
|
||||
} else {
|
||||
for _, v := range createShopCategoryParams {
|
||||
if v.ID == storeCat.VendorCatID {
|
||||
v.Title = createShopCategoryParam2.Title
|
||||
v.OrderNo = createShopCategoryParam2.OrderNo
|
||||
}
|
||||
}
|
||||
}
|
||||
status, err = api.JdShopAPI.CreateShopCategory(createShopCategoryParams)
|
||||
return status, err
|
||||
}
|
||||
|
||||
func buildCreateWareParam(storeSku *dao.StoreSkuSyncInfo) (createSkuParamWare *jdshopapi.CreateSkuParamWare, createSkuParamSkus []*jdshopapi.CreateSkuParamSkus, err error) {
|
||||
var (
|
||||
images []*jdshopapi.CreateSkuParamImages
|
||||
vendorCatID int
|
||||
)
|
||||
if storeSku.VendorCatID == "0" {
|
||||
resultCat, _ := api.JdShopAPI.FindShopCategories()
|
||||
for _, v := range resultCat {
|
||||
if v.Name == storeSku.CategoryName {
|
||||
vendorCatID = int(v.CID)
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vendorCatID = utils.Str2Int(storeSku.VendorCatID)
|
||||
}
|
||||
name := filterSensitiveWord(storeSku.Name)
|
||||
createSkuParamWare = &jdshopapi.CreateSkuParamWare{
|
||||
Title: name,
|
||||
ShopCategorys: []int{vendorCatID},
|
||||
CategoryID: int(storeSku.VendorVendorCatID),
|
||||
BrandID: jdshopapi.JxBrandId,
|
||||
// TransportID: jdshopapi.TransportID,
|
||||
WareStatus: 8, //上架待审核
|
||||
OuterID: utils.Int2Str(storeSku.NameID),
|
||||
VenderID: jdshopapi.VenderID,
|
||||
Length: 100,
|
||||
Width: 100,
|
||||
Height: 100,
|
||||
Weight: 0.5,
|
||||
JdPrice: jxutils.IntPrice2Standard(storeSku.UnitPrice),
|
||||
// MarketPrice: jxutils.IntPrice2Standard(storeSku.UnitPrice),
|
||||
// PromiseID: jdshopapi.JdsPromiseID,
|
||||
}
|
||||
|
||||
if storeSku.VendorVendorCatID != jdshopapi.JdsOtherMeatCatID {
|
||||
createSkuParamWare.PromiseID = jdshopapi.JdsPromiseID
|
||||
}
|
||||
|
||||
if storeSku.VendorVendorCatID == jdshopapi.JdsBeefCatID {
|
||||
createSkuParamWare.MultiCategoryID = jdshopapi.JdsBeefLastCatID
|
||||
}
|
||||
|
||||
//上传京东图片
|
||||
//规则,有两张就传两张,没有就重复传一张
|
||||
pic1, err := uploadImg(storeSku.Img, name, "1")
|
||||
img1 := &jdshopapi.CreateSkuParamImages{
|
||||
ColorID: "0000000000",
|
||||
ImgIndex: 1,
|
||||
ImgURL: pic1,
|
||||
}
|
||||
img2 := &jdshopapi.CreateSkuParamImages{
|
||||
ColorID: "0000000000",
|
||||
ImgIndex: 2,
|
||||
}
|
||||
if storeSku.Img2 == "" {
|
||||
img2.ImgURL = pic1
|
||||
} else {
|
||||
pic2, err2 := uploadImg(storeSku.Img, name, "2")
|
||||
err = err2
|
||||
img2.ImgURL = pic2
|
||||
}
|
||||
img3 := &jdshopapi.CreateSkuParamImages{
|
||||
ColorID: "0000000000",
|
||||
ImgIndex: 3,
|
||||
ImgURL: pic1,
|
||||
}
|
||||
images = append(images, img1)
|
||||
images = append(images, img2)
|
||||
images = append(images, img3)
|
||||
createSkuParamWare.Images = images
|
||||
//商品详情拼接
|
||||
var desc string
|
||||
if storeSku.DescImg != "" {
|
||||
pic3, err2 := uploadImg(storeSku.DescImg, name, "desc")
|
||||
err = err2
|
||||
desc = `<p><img src="` + jdshopapi.JdsImgURL + pic3 + `" style="width: auto; height: auto; max-width: 100%;"><br></p><p><br></p>`
|
||||
} else {
|
||||
desc = `<p><br></p><p><br></p>`
|
||||
}
|
||||
createSkuParamWare.MobileDesc = desc
|
||||
createSkuParamWare.Introduction = desc
|
||||
|
||||
//设置商品属性值
|
||||
var (
|
||||
attrIDs = make(map[string]int) //贮存方式,净含量,保质期IDs
|
||||
zctjValueID int64 //贮存条件冷藏0-4的id
|
||||
gcjkValueID int64 //国产,进口的id
|
||||
lbValueID int64 //类别的ID
|
||||
bcztValueID int64 //保存状态ID
|
||||
rmsjValueID int64 //热卖时间ID
|
||||
attrsProp []*jdshopapi.CreateSkuParamAttrs
|
||||
)
|
||||
attrs, err := api.JdShopAPI.FindAttrs(int(storeSku.VendorVendorCatID))
|
||||
for _, v := range attrs {
|
||||
if v.Name == "保质期" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "贮存条件" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "净含量" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "规格" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "国产/进口" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "类别" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "保存状态" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "热卖时间" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
}
|
||||
}
|
||||
values, _, err := api.JdShopAPI.FindValuesByAttrId(attrIDs["贮存条件"])
|
||||
for _, v := range values {
|
||||
if v.Name == "冷藏 0-4℃" {
|
||||
zctjValueID = v.ID
|
||||
}
|
||||
}
|
||||
if attrIDs["国产/进口"] != 0 {
|
||||
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["国产/进口"])
|
||||
err = err2
|
||||
for _, v := range values2 {
|
||||
if v.Name == "国产" {
|
||||
gcjkValueID = v.ID
|
||||
}
|
||||
}
|
||||
attrgcjk := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["国产/进口"]),
|
||||
AttrValues: []string{utils.Int64ToStr(gcjkValueID)},
|
||||
}
|
||||
attrsProp = append(attrsProp, attrgcjk)
|
||||
}
|
||||
if attrIDs["保存状态"] != 0 {
|
||||
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["保存状态"])
|
||||
err = err2
|
||||
for _, v := range values2 {
|
||||
if v.Name == "冷藏" || v.Name == "活鲜" {
|
||||
bcztValueID = v.ID
|
||||
}
|
||||
}
|
||||
attrbczt := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["保存状态"]),
|
||||
AttrValues: []string{utils.Int64ToStr(bcztValueID)},
|
||||
}
|
||||
attrsProp = append(attrsProp, attrbczt)
|
||||
}
|
||||
if attrIDs["热卖时间"] != 0 {
|
||||
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["热卖时间"])
|
||||
err = err2
|
||||
for _, v := range values2 {
|
||||
if v.Name == "12月" {
|
||||
rmsjValueID = v.ID
|
||||
}
|
||||
}
|
||||
attrrmsj := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["热卖时间"]),
|
||||
AttrValues: []string{utils.Int64ToStr(rmsjValueID)},
|
||||
}
|
||||
attrsProp = append(attrsProp, attrrmsj)
|
||||
}
|
||||
if storeSku.VendorVendorCatID == jdshopapi.JdsBeefCatID {
|
||||
var exValueID int64
|
||||
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(150390)
|
||||
err = err2
|
||||
for _, v := range values2 {
|
||||
if v.Name == "其它" {
|
||||
exValueID = v.ID
|
||||
}
|
||||
}
|
||||
attrex := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(150390),
|
||||
AttrValues: []string{utils.Int64ToStr(exValueID)},
|
||||
}
|
||||
attrsProp = append(attrsProp, attrex)
|
||||
}
|
||||
attrZctj := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["贮存条件"]),
|
||||
AttrValues: []string{utils.Int64ToStr(zctjValueID)},
|
||||
}
|
||||
attrJhl := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["净含量"]),
|
||||
AttrValues: []string{"0.5"},
|
||||
}
|
||||
attrBzq := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["保质期"]),
|
||||
AttrValues: []string{"5"},
|
||||
}
|
||||
attrsProp = append(attrsProp, attrZctj)
|
||||
attrsProp = append(attrsProp, attrJhl)
|
||||
attrsProp = append(attrsProp, attrBzq)
|
||||
createSkuParamWare.MultiCateProps = attrsProp
|
||||
var features = []*jdshopapi.CreateSkuParamFeatures{
|
||||
&jdshopapi.CreateSkuParamFeatures{
|
||||
Key: "is7ToReturn", //不支持7天无理由退货
|
||||
Value: "0",
|
||||
},
|
||||
&jdshopapi.CreateSkuParamFeatures{
|
||||
Key: "tssp", //支持自提
|
||||
Value: "",
|
||||
},
|
||||
// &jdshopapi.CreateSkuParamFeatures{
|
||||
// Key: "fdms", //分单?
|
||||
// Value: "1",
|
||||
// },
|
||||
}
|
||||
createSkuParamWare.Features = features
|
||||
//组合sku
|
||||
var vendorPrice int64 = 0
|
||||
for _, v := range storeSku.StoreSkuSyncInfoJds {
|
||||
var (
|
||||
ggValueID int64 //规格的属性id
|
||||
attrsPropSku []*jdshopapi.CreateSkuParamAttrs
|
||||
multiPropSku []*jdshopapi.CreateSkuParamAttrs
|
||||
specQuality string
|
||||
)
|
||||
valuesSku, maxNo, _ := api.JdShopAPI.FindValuesByAttrId(attrIDs["规格"])
|
||||
if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] {
|
||||
specQuality = strings.TrimRight(fmt.Sprintf("%.2f", float64(v.SpecQuality)), "0.") + v.SpecUnit
|
||||
} else {
|
||||
specQuality = utils.Float64ToStr(float64(v.SpecQuality)) + v.SpecUnit
|
||||
}
|
||||
if v.Comment != "" {
|
||||
specQuality = v.Comment
|
||||
}
|
||||
for _, v := range valuesSku {
|
||||
if v.Name == specQuality {
|
||||
ggValueID = v.ID
|
||||
}
|
||||
}
|
||||
if ggValueID == 0 { //说明没有建这个规格,要建上
|
||||
catID, _ := api.JdShopAPI.SaveVenderAttrValue(specQuality, attrIDs["规格"], int(storeSku.VendorVendorCatID), maxNo+1)
|
||||
ggValueID = catID
|
||||
}
|
||||
attrSku := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["规格"]),
|
||||
AttrValues: []string{utils.Int64ToStr(ggValueID)},
|
||||
}
|
||||
attrsPropSku = append(attrsPropSku, attrSku)
|
||||
sku := &jdshopapi.CreateSkuParamSkus{
|
||||
JdPrice: jxutils.IntPrice2Standard(v.VendorPrice),
|
||||
// StockNum: 9999,
|
||||
Type: "com.jd.pop.ware.ic.api.domain.sku",
|
||||
Type2: "com.jd.pop.ware.ic.api.domain.Sku",
|
||||
OuterID: utils.Int2Str(v.SkuID),
|
||||
}
|
||||
sku.SaleAttrs = attrsPropSku
|
||||
if attrIDs["类别"] != 0 {
|
||||
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["类别"])
|
||||
err = err2
|
||||
lbValueID = values2[len(values2)-1].ID
|
||||
attrlb := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["类别"]),
|
||||
AttrValues: []string{utils.Int64ToStr(lbValueID)},
|
||||
}
|
||||
multiPropSku = append(multiPropSku, attrlb)
|
||||
}
|
||||
sku.MultiCateProps = multiPropSku
|
||||
createSkuParamSkus = append(createSkuParamSkus, sku)
|
||||
|
||||
if v.VendorPrice > vendorPrice {
|
||||
vendorPrice = v.VendorPrice
|
||||
}
|
||||
if v.Status == model.SkuStatusNormal {
|
||||
sku.StockNum = 9999
|
||||
} else {
|
||||
sku.StockNum = 0
|
||||
}
|
||||
}
|
||||
//市场价固定500
|
||||
createSkuParamWare.MarketPrice = 500
|
||||
return createSkuParamWare, createSkuParamSkus, err
|
||||
}
|
||||
|
||||
//京东商城上传图片,若平台上已经有了这个图就直接拿来用了
|
||||
func uploadImg(img, name, index string) (imgURL string, err error) {
|
||||
result, err := api.JdShopAPI.QueryPicture(name + index)
|
||||
if len(result) > 0 {
|
||||
imgURL = result[0].PictureURL
|
||||
} else {
|
||||
data, _, err := jxutils.DownloadFileByURL(img)
|
||||
if err != nil {
|
||||
return imgURL, err
|
||||
}
|
||||
uploadResult, err := api.JdShopAPI.UploadPicture(data, 0, name+index)
|
||||
if err != nil {
|
||||
return imgURL, err
|
||||
}
|
||||
imgURL = uploadResult.PictureURL
|
||||
}
|
||||
return imgURL, err
|
||||
}
|
||||
|
||||
func uploadImg2(img, name, index string) (imgURL string, err error) {
|
||||
data, _, err := jxutils.DownloadFileByURL(img)
|
||||
if err != nil {
|
||||
return imgURL, err
|
||||
}
|
||||
uploadResult, err := api.JdShopAPI.UploadPicture(data, 0, name+index)
|
||||
if err != nil {
|
||||
return imgURL, err
|
||||
}
|
||||
imgURL = uploadResult.PictureURL
|
||||
return imgURL, err
|
||||
}
|
||||
|
||||
func filterSensitiveWord(name string) (result string) {
|
||||
for _, v := range jdshopapi.SensitiveWordMap {
|
||||
if strings.Contains(name, v) {
|
||||
return strings.ReplaceAll(name, v, "")
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func buildUpdateSkusParam(storeSku *dao.StoreSkuSyncInfo, v *dao.StoreSkuSyncInfo, isCreate bool) (updateSkusParam *jdshopapi.UpdateSkusParam, err error) {
|
||||
var (
|
||||
ggValueID int64 //规格的属性id
|
||||
attrsPropSku []*jdshopapi.CreateSkuParamAttrs
|
||||
skus []*jdshopapi.UpdateSkusParamSkus
|
||||
multiPropSku []*jdshopapi.CreateSkuParamAttrs
|
||||
specQuality string
|
||||
)
|
||||
updateSkusParam = &jdshopapi.UpdateSkusParam{
|
||||
WareID: storeSku.JdsWareID,
|
||||
}
|
||||
sku := &jdshopapi.UpdateSkusParamSkus{
|
||||
WareID: storeSku.JdsWareID,
|
||||
JdPrice: jxutils.IntPrice2Standard(v.VendorPrice),
|
||||
Type: "com.jd.pop.ware.ic.api.domain.sku",
|
||||
Type2: "com.jd.pop.ware.ic.api.domain.Sku",
|
||||
OuterID: utils.Int2Str(v.SkuID),
|
||||
}
|
||||
//库存设置
|
||||
if v.StoreSkuStatus == model.SkuStatusNormal {
|
||||
sku.StockNum = "9999"
|
||||
} else {
|
||||
sku.StockNum = "0"
|
||||
}
|
||||
//规格类别设置
|
||||
attrIDs := make(map[string]int)
|
||||
attrs, err := api.JdShopAPI.FindAttrs(int(storeSku.VendorVendorCatID))
|
||||
for _, v := range attrs {
|
||||
if v.Name == "规格" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
} else if v.Name == "类别" {
|
||||
attrIDs[v.Name] = v.ID
|
||||
}
|
||||
}
|
||||
if attrIDs["类别"] != 0 {
|
||||
values2, _, err2 := api.JdShopAPI.FindValuesByAttrId(attrIDs["类别"])
|
||||
err = err2
|
||||
lbValueID := values2[len(values2)-1].ID
|
||||
attrlb := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["类别"]),
|
||||
AttrValues: []string{utils.Int64ToStr(lbValueID)},
|
||||
}
|
||||
multiPropSku = append(multiPropSku, attrlb)
|
||||
}
|
||||
sku.MultiCateProps = multiPropSku
|
||||
if v.SpecUnit == model.SpecUnitNames[1] || v.SpecUnit == model.SpecUnitNames[2] {
|
||||
if math.Mod(float64(v.SpecQuality), 10) != 0 {
|
||||
specQuality = strings.TrimRight(fmt.Sprintf("%.2f", float64(v.SpecQuality)), "0.") + v.SpecUnit
|
||||
} else {
|
||||
specQuality = utils.Float64ToStr(float64(v.SpecQuality)) + v.SpecUnit
|
||||
}
|
||||
} else {
|
||||
specQuality = utils.Float64ToStr(float64(v.SpecQuality)) + v.SpecUnit
|
||||
}
|
||||
valuesSku, maxNo, _ := api.JdShopAPI.FindValuesByAttrId(attrIDs["规格"])
|
||||
if isCreate {
|
||||
for _, vv := range valuesSku {
|
||||
if vv.Name == specQuality {
|
||||
ggValueID = vv.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
if ggValueID == 0 { //说明没有建这个规格,要建上
|
||||
catID, _ := api.JdShopAPI.SaveVenderAttrValue(specQuality, attrIDs["规格"], int(storeSku.VendorVendorCatID), maxNo+1)
|
||||
ggValueID = catID
|
||||
}
|
||||
attrSku := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: utils.Int2Str(attrIDs["规格"]),
|
||||
AttrValues: []string{utils.Int64ToStr(ggValueID)},
|
||||
}
|
||||
attrsPropSku = append(attrsPropSku, attrSku)
|
||||
sku.SaleAttrs = attrsPropSku
|
||||
} else {
|
||||
vendorSku, err2 := api.JdShopAPI.FindSkuById(utils.Str2Int64(v.VendorSkuID))
|
||||
err = err2
|
||||
vendorAttrValue := vendorSku.SaleAttrs[0].AttrValueAlias[0]
|
||||
if v.Comment != "" {
|
||||
specQuality = v.Comment
|
||||
}
|
||||
if v.Comment != vendorAttrValue {
|
||||
err = api.JdShopAPI.UpdateWareSaleAttrvalueAlias(&jdshopapi.UpdateWareSaleAttrvalueAliasParam{
|
||||
WareID: v.JdsWareID,
|
||||
Props: []*jdshopapi.CreateSkuParamAttrs2{
|
||||
&jdshopapi.CreateSkuParamAttrs2{
|
||||
AttrID: vendorSku.SaleAttrs[0].AttrID,
|
||||
AttrValues: []string{vendorSku.SaleAttrs[0].AttrValues[0]},
|
||||
AttrValueAlias: []string{specQuality},
|
||||
Type: "com.jd.pop.ware.ic.api.domain.prop",
|
||||
Type2: "com.jd.pop.ware.ic.api.domain.Prop",
|
||||
},
|
||||
},
|
||||
})
|
||||
sku.SkuID = utils.Str2Int64(v.VendorSkuID)
|
||||
}
|
||||
attrSku := &jdshopapi.CreateSkuParamAttrs{
|
||||
AttrID: vendorSku.SaleAttrs[0].AttrID,
|
||||
AttrValues: []string{vendorSku.SaleAttrs[0].AttrValues[0]},
|
||||
}
|
||||
attrsPropSku = append(attrsPropSku, attrSku)
|
||||
sku.SaleAttrs = attrsPropSku
|
||||
}
|
||||
skus = append(skus, sku)
|
||||
updateSkusParam.Skus = skus
|
||||
return updateSkusParam, err
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package jx
|
||||
|
||||
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) SyncAct(ctx *jxcontext.Context, parentTask tasksch.ITask, act *model.Act2, actOrderRules []*model.ActOrderRule, actStoreSkuList []*model.ActStoreSku2) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package jx
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
type PurchaseHandler struct {
|
||||
partner.BasePurchasePlatform
|
||||
}
|
||||
|
||||
var (
|
||||
CurPurchaseHandler *PurchaseHandler
|
||||
)
|
||||
|
||||
func init() {
|
||||
globals.SugarLogger.Debug("init jx")
|
||||
if true {
|
||||
CurPurchaseHandler = new(PurchaseHandler)
|
||||
// 不能注册京西
|
||||
// partner.RegisterPurchasePlatform(CurPurchaseHandler)
|
||||
partner.RegisterPurchaseOrderHandler(CurPurchaseHandler.GetVendorID(), CurPurchaseHandler)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetVendorID() int {
|
||||
return model.VendorIDJX
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) UploadImg(ctx *jxcontext.Context, vendorOrgCode, imgURL string, imgData []byte, imgName string, imgType int) (imgHint string, err error) {
|
||||
return imgHint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +0,0 @@
|
||||
package localjx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestGenOrderNo(t *testing.T) {
|
||||
orderNo := GenOrderNo(jxcontext.AdminCtx)
|
||||
t.Log(orderNo)
|
||||
}
|
||||
|
||||
func TestGetAvailableDeliverTime(t *testing.T) {
|
||||
timeInfo, err := GetAvailableDeliverTime(jxcontext.AdminCtx, 100118)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(timeInfo, false))
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
package localjx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func pay4OrderByTL(ctx *jxcontext.Context, order *model.GoodsOrder, payType int, vendorPayType string) (orderPay *model.OrderPay, err error) {
|
||||
// if order.FromStoreID != 0 {
|
||||
// result, _ := orderman.GetMatterStoreOrderCount(nil, order.FromStoreID)
|
||||
// if !result.Flag {
|
||||
// return nil, fmt.Errorf("该门店[%v]已在一周内申请过物料,请勿重复申请!", order.FromStoreID)
|
||||
// }
|
||||
// }
|
||||
payCreatedAt := time.Now()
|
||||
param := &tonglianpayapi.CreateUnitorderOrderParam{
|
||||
Trxamt: int(order.ActualPayPrice),
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Reqsn: order.VendorOrderID,
|
||||
PayType: vendorPayType,
|
||||
}
|
||||
//暂时做兼容处理
|
||||
if vendorPayType == "JSAPI" {
|
||||
param.PayType = tonglianpayapi.PayTypeWxXcx
|
||||
}
|
||||
if vendorPayType == tonglianpayapi.PayTypeWxXcx {
|
||||
if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini {
|
||||
param.Acct = authInfo.GetAuthID()
|
||||
}
|
||||
}
|
||||
if vendorPayType == tonglianpayapi.PayTypeH5 {
|
||||
param2 := &tonglianpayapi.CreateH5UnitorderOrderParam{
|
||||
Trxamt: int(order.ActualPayPrice),
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Body: "京西菜市",
|
||||
Charset: "UTF-8",
|
||||
}
|
||||
err = api.TLpayAPI.CreateH5UnitorderOrder(param2)
|
||||
} else {
|
||||
result, err := api.TLpayAPI.CreateUnitorderOrder(param)
|
||||
if err == nil {
|
||||
var result2 tonglianpayapi.PayInfo
|
||||
json.Unmarshal([]byte(result.PayInfo), &result2)
|
||||
prePayID := result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)]
|
||||
orderPay = &model.OrderPay{
|
||||
PayOrderID: param.Reqsn,
|
||||
PayType: payType,
|
||||
VendorPayType: vendorPayType,
|
||||
TransactionID: result.TrxID,
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: order.VendorID,
|
||||
Status: 0,
|
||||
PayCreatedAt: payCreatedAt,
|
||||
PrepayID: prePayID,
|
||||
CodeURL: utils.LimitUTF8StringLen(result.PayInfo, 3200),
|
||||
TotalFee: int(order.ActualPayPrice),
|
||||
}
|
||||
}
|
||||
}
|
||||
return orderPay, err
|
||||
}
|
||||
|
||||
func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true))
|
||||
switch call.TrxCode {
|
||||
case tonglianpayapi.MsgTypePay:
|
||||
err = onTLpayFinished(call)
|
||||
case tonglianpayapi.MsgTypeRefund:
|
||||
err = onTLpayRefund(call)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
orderPay := &model.OrderPay{
|
||||
PayOrderID: call.CusorderID,
|
||||
// PayType: model.PayTypeTL,
|
||||
}
|
||||
orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPay, "PayOrderID", "DeletedAt"); err == nil {
|
||||
if orderPay.Status != 0 {
|
||||
globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
return err
|
||||
}
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
|
||||
orderPay.PayFinishedAt = utils.Time2Pointer(t1)
|
||||
// orderPay.TransactionID = call.ChnlTrxID
|
||||
orderPay.OriginalData = utils.Format4Output(call, true)
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPay.Status = model.PayStatusYes
|
||||
} else {
|
||||
orderPay.Status = model.PayStatusFailed
|
||||
}
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
err = OnPayFinished(orderPay)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
orderPayRefund := &model.OrderPayRefund{
|
||||
RefundID: call.CusorderID,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(call, true)
|
||||
dao.UpdateEntity(db, orderPayRefund)
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true))
|
||||
}
|
||||
|
||||
orderPay := &model.OrderPay{
|
||||
VendorOrderID: orderPayRefund.VendorOrderID,
|
||||
VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
|
||||
PayType: model.PayTypeWX,
|
||||
Status: model.PayStatusYes,
|
||||
}
|
||||
orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
|
||||
orderPay.Status = model.PayStatusRefund
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func RefundOrderByTL(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) {
|
||||
result, err := api.TLpayAPI.PayRefund(&tonglianpayapi.PayRefundParam{
|
||||
Trxamt: refundFee,
|
||||
Reqsn: utils.GetUUID(),
|
||||
Remark: refundDesc,
|
||||
OldTrxID: orderPay.TransactionID,
|
||||
})
|
||||
if err == nil {
|
||||
orderPayRefund = &model.OrderPayRefund{
|
||||
RefundID: refundID,
|
||||
VendorRefundID: result.TrxID,
|
||||
VendorOrderID: orderPay.VendorOrderID,
|
||||
VendorID: orderPay.VendorID,
|
||||
Status: model.RefundStatusNo,
|
||||
TransactionID: orderPay.TransactionID,
|
||||
RefundFee: refundFee,
|
||||
RefundCreatedAt: time.Now(),
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName())
|
||||
db := dao.GetDB()
|
||||
if result.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(result, true)
|
||||
dao.CreateEntity(db, orderPayRefund)
|
||||
|
||||
orderPay.Status = model.PayStatusRefund
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
}
|
||||
return orderPayRefund, err
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package localjx
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
type GetJxShopUsersResult struct {
|
||||
model.User
|
||||
BuyCount int `json:"buyCount"`
|
||||
ActualPayPrice int `json:"actualPayPrice"`
|
||||
GoodCommentCount int `json:"goodCommentCount"`
|
||||
BadCommentCount int `json:"badCommentCount"`
|
||||
UserMembers []*model.UserMember `json:"userMembers"`
|
||||
}
|
||||
|
||||
func GetJxShopUsers(ctx *jxcontext.Context, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
var (
|
||||
requestList []*GetJxShopUsersResult
|
||||
db = dao.GetDB()
|
||||
)
|
||||
sql := `
|
||||
SELECT SQL_CALC_FOUND_ROWS DISTINCT a.*, b.buy_count, b.actual_pay_price
|
||||
FROM user a,
|
||||
(SELECT a.user_id, COUNT(*) buy_count, SUM(c.actual_pay_price) actual_pay_price
|
||||
FROM user a
|
||||
JOIN auth_bind b ON b.user_id = a.user_id AND b.deleted_at = ? AND b.type_id = ?
|
||||
JOIN goods_order c ON c.user_id = a.user_id AND c.status <> ? AND c.store_id <> ?
|
||||
WHERE a.deleted_at = ?
|
||||
GROUP BY 1) b
|
||||
WHERE a.user_id = b.user_id
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue, api.WeixinMiniAppID2,
|
||||
model.OrderStatusCanceled, model.MatterStoreID,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
if keyword != "" {
|
||||
sql += " AND (a.user_id LIKE ? OR a.name LIKE ? OR a.mobile LIKE ? OR a.user_id2 LIKE ?)"
|
||||
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
|
||||
}
|
||||
sql += "LIMIT ? OFFSET ?"
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
dao.Begin(db)
|
||||
defer dao.Commit(db)
|
||||
if err = dao.GetRows(db, &requestList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
// Data: requestList,
|
||||
}
|
||||
for _, v := range requestList {
|
||||
userMembers, _ := dao.GetUserMember(db, v.UserID, "", model.MemberTypeDiscountCard, model.YES)
|
||||
v.UserMembers = userMembers
|
||||
}
|
||||
pagedInfo.Data = requestList
|
||||
}
|
||||
return pagedInfo, err
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package localjx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func vendorPayType2WxpayType(vendorPayType string) string {
|
||||
return vendorPayType
|
||||
}
|
||||
|
||||
func getOrderBrief(order *model.GoodsOrder) string {
|
||||
return fmt.Sprintf("%s等共%d件商品", order.Skus[0].SkuName, order.GoodsCount)
|
||||
}
|
||||
|
||||
func pay4OrderByWX(ctx *jxcontext.Context, order *model.GoodsOrder, vendorPayType string) (orderPay *model.OrderPay, err error) {
|
||||
payCreatedAt := time.Now()
|
||||
param := &wxpayapi.CreateOrderParam{
|
||||
OutTradeNo: utils.Int64ToStr(GenPayOrderID(order)),
|
||||
Body: getOrderBrief(order),
|
||||
NotifyURL: globals.WxpayNotifyURL,
|
||||
SpbillCreateIP: ctx.GetRealRemoteIP(),
|
||||
TradeType: vendorPayType2WxpayType(vendorPayType),
|
||||
TotalFee: int(order.ActualPayPrice),
|
||||
|
||||
TimeStart: wxpayapi.Time2PayTime(payCreatedAt),
|
||||
// TimeExpire: wxpayapi.Time2PayTime(payCreatedAt.Add(PayWaitingTime)),
|
||||
ProfitSharing: wxpayapi.OptYes,
|
||||
}
|
||||
if authInfo, err := ctx.GetV2AuthInfo(); err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini {
|
||||
param.OpenID = authInfo.GetAuthID()
|
||||
}
|
||||
result, err := api.WxpayAPI.CreateUnifiedOrder(param)
|
||||
if err == nil {
|
||||
orderPay = &model.OrderPay{
|
||||
PayOrderID: param.OutTradeNo,
|
||||
PayType: model.PayTypeWX,
|
||||
VendorPayType: vendorPayType,
|
||||
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: order.VendorID,
|
||||
Status: 0,
|
||||
PayCreatedAt: payCreatedAt,
|
||||
PrepayID: result.PrepayID,
|
||||
CodeURL: result.CodeURL,
|
||||
TotalFee: int(order.ActualPayPrice),
|
||||
}
|
||||
}
|
||||
return orderPay, err
|
||||
}
|
||||
|
||||
func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) {
|
||||
globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true))
|
||||
switch msg.MsgType {
|
||||
case wxpayapi.MsgTypePay:
|
||||
err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg))
|
||||
case wxpayapi.MsgTypeRefund:
|
||||
err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) {
|
||||
orderPay := &model.OrderPay{
|
||||
PayOrderID: msg.OutTradeNo,
|
||||
PayType: model.PayTypeWX,
|
||||
}
|
||||
orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPay, "PayOrderID", "PayType", "DeletedAt"); err == nil {
|
||||
orderPay.PayFinishedAt = utils.Time2Pointer(wxpayapi.PayTime2Time(msg.TimeEnd))
|
||||
orderPay.TransactionID = msg.TransactionID
|
||||
orderPay.OriginalData = utils.Format4Output(msg, true)
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
orderPay.Status = model.PayStatusYes
|
||||
} else {
|
||||
orderPay.Status = model.PayStatusFailed
|
||||
}
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
err = OnPayFinished(orderPay)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onWxpayFinished msg:%s, err:%v", utils.Format4Output(msg, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) {
|
||||
orderPayRefund := &model.OrderPayRefund{
|
||||
RefundID: msg.ReqInfoObj.OutRefundNo,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(msg, true)
|
||||
dao.UpdateEntity(db, orderPayRefund)
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
globals.SugarLogger.Warnf("收到异常的退款事件, msg:%s", utils.Format4Output(msg, true))
|
||||
}
|
||||
|
||||
orderPay := &model.OrderPay{
|
||||
VendorOrderID: orderPayRefund.VendorOrderID,
|
||||
VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
|
||||
PayType: model.PayTypeWX,
|
||||
Status: model.PayStatusYes,
|
||||
}
|
||||
orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
|
||||
orderPay.Status = model.PayStatusRefund
|
||||
dao.UpdateEntity(db, orderPay)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func refundOrderByWX(ctx *jxcontext.Context, orderPay *model.OrderPay, refundID string, refundFee int, refundDesc string) (orderPayRefund *model.OrderPayRefund, err error) {
|
||||
result, err := api.WxpayAPI.PayRefund(&wxpayapi.PayRefundParam{
|
||||
OutTradeNo: orderPay.VendorOrderID,
|
||||
NotifyURL: globals.WxpayNotifyURL,
|
||||
OutRefundNo: refundID,
|
||||
TotalFee: orderPay.TotalFee,
|
||||
RefundFee: refundFee,
|
||||
RefundDesc: wxpayapi.CData(refundDesc),
|
||||
})
|
||||
if err == nil {
|
||||
orderPayRefund = &model.OrderPayRefund{
|
||||
RefundID: refundID,
|
||||
VendorRefundID: result.RefundID,
|
||||
VendorOrderID: orderPay.VendorOrderID,
|
||||
VendorID: orderPay.VendorID,
|
||||
Status: model.RefundStatusNo,
|
||||
TransactionID: orderPay.TransactionID,
|
||||
RefundFee: orderPay.TotalFee,
|
||||
RefundCreatedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
return orderPayRefund, err
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
package jx
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"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/business/partner/purchase/jx/localjx"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/phpjx"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) {
|
||||
return order
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrder(vendorOrgCode, orderID string) (order *model.GoodsOrder, err error) {
|
||||
order, err = partner.CurOrderManager.LoadOrder(orderID, model.VendorIDJX)
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX)
|
||||
if err == nil {
|
||||
status = order.Status
|
||||
}
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
var status int
|
||||
if isAcceptIt {
|
||||
status = model.OrderStatusAccepted
|
||||
} else {
|
||||
status = model.OrderStatusCanceled
|
||||
}
|
||||
if model.IsOrderJXTemp(order) {
|
||||
err = phpjx.NotifyOrderStatusChanged(order, status)
|
||||
} else {
|
||||
err = localjx.AcceptOrRefuseOrder(order, isAcceptIt, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusFinishedPickup)
|
||||
} else {
|
||||
err = localjx.PickupGoods(order, isSelfDelivery, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusDelivering)
|
||||
} else {
|
||||
err = localjx.SelfDeliverDelivering(order, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusFinished)
|
||||
} else {
|
||||
err = localjx.SelfDeliverDelivered(order, userName)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) {
|
||||
return mobile, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
} else {
|
||||
err = localjx.AgreeOrRefuseCancel(ctx, order, isAgree, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusCanceled)
|
||||
} else {
|
||||
err = localjx.CancelOrder(ctx, order, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
} else {
|
||||
err = localjx.AdjustOrder(ctx, order, removedSkuList, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) {
|
||||
return vendorOrderIDs, err
|
||||
}
|
||||
|
||||
func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID, selfTakeCode string) (err error) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX)
|
||||
if err == nil {
|
||||
if model.IsOrderJXTemp(order) {
|
||||
err = phpjx.NotifyOrderStatusChanged(order, model.OrderStatusFinished)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
package jx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"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"
|
||||
)
|
||||
|
||||
// 审核售后单申请
|
||||
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
|
||||
var status int
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
status = model.AfsOrderStatusFailed
|
||||
} else {
|
||||
status = model.AfsOrderStatusFinished
|
||||
}
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: order.AfsOrderID, // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: order.VendorID,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
RefVendorID: order.VendorID,
|
||||
VendorStatus: utils.Int2Str(status),
|
||||
Status: status,
|
||||
StatusTime: time.Now(),
|
||||
Remark: reason,
|
||||
}
|
||||
if status == model.AfsOrderStatusFinished {
|
||||
orderPays, err := dao.GetOrderPayList(dao.GetDB(), order.VendorOrderID, order.VendorID)
|
||||
if err == nil {
|
||||
_, err = localjx.RefundOrderByTL(ctx, orderPays[0], order.VendorOrderID, int(order.SkuUserMoney), reason)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 确认收到退货
|
||||
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
|
||||
err = fmt.Errorf("京西商城当前不支持ConfirmReceivedReturnGoods")
|
||||
return err
|
||||
}
|
||||
|
||||
// 发起全款退款
|
||||
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
err = c.PartRefundOrder(ctx, order, order.Skus, reason)
|
||||
return err
|
||||
}
|
||||
|
||||
// 发起部分退款
|
||||
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
globals.SugarLogger.Debugf("PartRefundOrder jx, orderID :%v", order.VendorOrderID)
|
||||
var (
|
||||
skuMap = make(map[int]*model.OrderSku)
|
||||
appID = ""
|
||||
salePrice int64
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if time.Now().Sub(order.OrderCreatedAt) > 24*time.Hour {
|
||||
return fmt.Errorf("已超过售后申请时间,如有疑问请联系门店!")
|
||||
}
|
||||
referer := ctx.GetRequest().Referer()
|
||||
index := strings.Index(referer, "//")
|
||||
if index > 0 {
|
||||
list := strings.Split(referer[index+2:], "/")
|
||||
if len(list) >= 2 {
|
||||
appID = list[1]
|
||||
}
|
||||
}
|
||||
for _, sku := range order.Skus {
|
||||
skuMap[sku.SkuID] = sku
|
||||
}
|
||||
orderStatus := buildOrderStatus(ctx, order, reason, isJxShop(appID))
|
||||
afsOrder := &model.AfsOrder{
|
||||
VendorID: order.VendorID,
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorOrderID: orderStatus.RefVendorOrderID,
|
||||
VendorStoreID: order.VendorStoreID,
|
||||
StoreID: order.StoreID,
|
||||
AfsCreatedAt: time.Now(),
|
||||
VendorAppealType: "",
|
||||
AppealType: model.AfsAppealTypeRefund,
|
||||
VendorReasonType: utils.Int2Str(model.AfsReasonNotOthers),
|
||||
ReasonType: model.AfsReasonNotOthers,
|
||||
ReasonDesc: utils.LimitUTF8StringLen(reason, 1024),
|
||||
ReasonImgList: "",
|
||||
RefundType: model.AfsTypePartRefund,
|
||||
|
||||
VendorOrgCode: "",
|
||||
}
|
||||
for _, sku := range refundSkuList {
|
||||
orderSku := &model.OrderSkuFinancial{
|
||||
Count: sku.Count,
|
||||
VendorSkuID: utils.Int2Str(sku.SkuID),
|
||||
SkuID: sku.SkuID,
|
||||
}
|
||||
if skuMap[sku.SkuID] != nil {
|
||||
orderSku.Name = skuMap[sku.SkuID].SkuName
|
||||
orderSku.UserMoney = skuMap[sku.SkuID].SalePrice * int64(sku.Count)
|
||||
salePrice += skuMap[sku.SkuID].SalePrice * int64(sku.Count)
|
||||
}
|
||||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||||
}
|
||||
|
||||
if !isJxShop(appID) {
|
||||
orderPays, err := dao.GetOrderPayList(db, order.VendorOrderID, order.VendorID)
|
||||
if err == nil {
|
||||
_, err = localjx.RefundOrderByTL(ctx, orderPays[0], order.VendorOrderID, int(salePrice), reason)
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
if afsOrder != nil {
|
||||
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func buildOrderStatus(ctx *jxcontext.Context, order *model.GoodsOrder, reason string, isJxShop bool) (orderStatus *model.OrderStatus) {
|
||||
orderStatus = &model.OrderStatus{
|
||||
VendorOrderID: utils.Int64ToStr(jxutils.GenAfsOrderNo()), // 是售后单ID,不是订单ID,订单ID在RefVendorOrderID中
|
||||
VendorID: order.VendorID,
|
||||
OrderType: model.OrderTypeAfsOrder,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
RefVendorID: order.VendorID,
|
||||
VendorStatus: utils.Int2Str(model.AfsOrderStatusWait4Approve),
|
||||
// Status: model.AfsOrderStatusWait4Approve,
|
||||
StatusTime: time.Now(),
|
||||
Remark: reason,
|
||||
}
|
||||
if isJxShop {
|
||||
orderStatus.Status = model.AfsOrderStatusWait4Approve
|
||||
} else {
|
||||
orderStatus.Status = model.AfsOrderStatusFinished
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func isJxShop(appID string) bool {
|
||||
if appID == api.WeixinMiniAppID2 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package jx
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func (c *PurchaseHandler) ReplyOrderComment(ctx *jxcontext.Context, vendorOrgCode string, orderComment *model.OrderComment, replyComment string) (err error) {
|
||||
return err
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package phpjx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
appKey = "4A86853D-E4B6-454E-940A-B68ECDA2B73E"
|
||||
|
||||
MsgTypeOrder = "order"
|
||||
MsgTypeAfsOrder = "afsOrder"
|
||||
)
|
||||
|
||||
type CallbackResponse struct {
|
||||
Code int `json:"code"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
type CallbackMsg struct {
|
||||
AppKey string `json:"appKey"`
|
||||
MsgType string `json:"msgType"`
|
||||
SubMsgType string `json:"subMsgType"`
|
||||
ThingID string `json:"thingID"`
|
||||
ThingID2 string `json:"thingID2"`
|
||||
Data string `json:"data"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func OnCallbackMsg(msg *CallbackMsg) (retVal, errCode string, err error) {
|
||||
if msg.AppKey != appKey {
|
||||
return retVal, errCode, fmt.Errorf("无效的AppKey:%s", msg.AppKey)
|
||||
}
|
||||
if msg.MsgType == MsgTypeOrder {
|
||||
retVal, errCode, err = OnOrderMsg(msg)
|
||||
} else if msg.MsgType == MsgTypeAfsOrder {
|
||||
err = OnAfsOrderMsg(msg)
|
||||
}
|
||||
return retVal, errCode, err
|
||||
}
|
||||
|
||||
func postFakeMsg(orderNo string, status int) {
|
||||
msg := &CallbackMsg{
|
||||
AppKey: appKey,
|
||||
MsgType: MsgTypeOrder,
|
||||
SubMsgType: utils.Int2Str(status),
|
||||
ThingID: orderNo,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
utils.CallFuncAsync(func() {
|
||||
OnCallbackMsg(msg)
|
||||
})
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package phpjx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestBuildNewJxOrder(t *testing.T) {
|
||||
order, err := partner.CurOrderManager.LoadOrder("920931913000041", model.VendorIDJD)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
order.VendorID = model.VendorIDJX
|
||||
order.VendorStoreID = utils.Int2Str(order.StoreID)
|
||||
for _, sku := range order.Skus {
|
||||
sku.VendorID = model.VendorIDJX
|
||||
sku.VendorSkuID = utils.Int2Str(sku.SkuID)
|
||||
}
|
||||
order2 := &Data4Neworder{
|
||||
GoodsOrder: *order,
|
||||
Skus: order.Skus,
|
||||
}
|
||||
msg := &CallbackMsg{
|
||||
AppKey: appKey,
|
||||
MsgType: MsgTypeOrder,
|
||||
SubMsgType: utils.Int2Str(model.OrderStatusNew),
|
||||
ThingID: order.VendorOrderID,
|
||||
Data: utils.Format4Output(order2, true),
|
||||
}
|
||||
t.Logf("\n%s", msg.AppKey)
|
||||
t.Logf("\n%s", msg.MsgType)
|
||||
t.Logf("\n%s", msg.SubMsgType)
|
||||
t.Logf("\n%s", msg.ThingID)
|
||||
t.Logf("\n%s", msg.Data)
|
||||
|
||||
var order3 *model.GoodsOrder
|
||||
err = utils.UnmarshalUseNumber([]byte(msg.Data), &order3)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(order3.OrderCreatedAt)
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package phpjx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
)
|
||||
|
||||
type API struct {
|
||||
token string
|
||||
appKey string
|
||||
appSecret string
|
||||
client *http.Client
|
||||
config *platformapi.APIConfig
|
||||
}
|
||||
|
||||
const (
|
||||
ResponseCodeSuccess = 200
|
||||
)
|
||||
|
||||
const (
|
||||
prodURL = "https://www.jingxicaishi.com/index.php/Weimendian/index"
|
||||
)
|
||||
|
||||
var (
|
||||
exceedLimitCodes = map[int]int{}
|
||||
canRetryCodes = map[int]int{}
|
||||
)
|
||||
|
||||
var (
|
||||
jxAPI *API
|
||||
)
|
||||
|
||||
func NewAPI(token, appKey, appSecret string, config ...*platformapi.APIConfig) *API {
|
||||
curConfig := platformapi.DefAPIConfig
|
||||
if len(config) > 0 {
|
||||
curConfig = *config[0]
|
||||
}
|
||||
return &API{
|
||||
token: token,
|
||||
appKey: appKey,
|
||||
appSecret: appSecret,
|
||||
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
||||
config: &curConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
jxAPI = NewAPI("", "", "")
|
||||
}
|
||||
|
||||
func (a *API) AccessAPI(apiStr string, jxParams map[string]interface{}, traceInfo string) (retVal map[string]interface{}, err error) {
|
||||
err = platformapi.AccessPlatformAPIWithRetry(a.client,
|
||||
func() *http.Request {
|
||||
params := utils.MergeMaps(jxParams, map[string]interface{}{
|
||||
"timestamp": utils.GetCurTimeStr(),
|
||||
})
|
||||
var request *http.Request
|
||||
if false {
|
||||
|
||||
} else {
|
||||
fullURL := prodURL + "/" + apiStr
|
||||
// baseapi.SugarLogger.Debug(utils.Map2URLValues(params).Encode())
|
||||
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(params).Encode()))
|
||||
request.Header.Set("charset", "UTF-8")
|
||||
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
if traceInfo != "" {
|
||||
request.Header.Set(platformapi.KeyTrackInfo, traceInfo)
|
||||
}
|
||||
// request.Close = true //todo 为了性能考虑还是不要关闭
|
||||
return request
|
||||
},
|
||||
a.config,
|
||||
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
|
||||
if jsonResult1 == nil {
|
||||
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
|
||||
}
|
||||
code := int(utils.Interface2Int64WithDefault(jsonResult1["code"], 0))
|
||||
if code == ResponseCodeSuccess {
|
||||
retVal = jsonResult1
|
||||
return platformapi.ErrLevelSuccess, nil
|
||||
}
|
||||
newErr := utils.NewErrorIntCode(jsonResult1["msg"].(string), code)
|
||||
if _, ok := exceedLimitCodes[code]; ok {
|
||||
return platformapi.ErrLevelExceedLimit, newErr
|
||||
} else if _, ok := canRetryCodes[code]; ok {
|
||||
return platformapi.ErrLevelRecoverableErr, newErr
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("jx AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true))
|
||||
return platformapi.ErrLevelCodeIsNotOK, newErr
|
||||
}
|
||||
})
|
||||
return retVal, err
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package phpjx
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
var (
|
||||
orderStatusMap = map[int]int{
|
||||
model.OrderStatusFinishedPickup: 7,
|
||||
model.OrderStatusDelivering: 8,
|
||||
// 4,
|
||||
model.OrderStatusFinished: 3,
|
||||
model.OrderStatusCanceled: 3,
|
||||
}
|
||||
)
|
||||
|
||||
func translateOrderStatus(status int) (outStatus int) {
|
||||
return status //orderStatusMap[status]
|
||||
}
|
||||
|
||||
func (a *API) NotifyOrderStatusChanged(order *model.GoodsOrder) (err error) {
|
||||
status := translateOrderStatus(order.Status)
|
||||
if status > 0 {
|
||||
_, err = a.AccessAPI("orderChangeStatus", map[string]interface{}{
|
||||
"orderid": order.VendorOrderID,
|
||||
"status": status,
|
||||
"data": "", //string(utils.MustMarshal(order)),
|
||||
}, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *API) NotifyAfsOrderStatusChanged(afsOrder *model.AfsOrder) (err error) {
|
||||
status := translateOrderStatus(afsOrder.Status)
|
||||
if status > 0 {
|
||||
_, err = a.AccessAPI("afsOrderChangeStatus", map[string]interface{}{
|
||||
"orderid": afsOrder.VendorOrderID,
|
||||
"afsOrderID": afsOrder.AfsOrderID,
|
||||
"status": status,
|
||||
"data": "", //string(utils.MustMarshal(order)),
|
||||
}, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user