Files
jx-callback/business/jxcallback/orderman/order.go
邹宗楠 982c7568b3 1
2023-05-31 13:57:37 +08:00

2694 lines
103 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package orderman
import (
"crypto/md5"
"errors"
"fmt"
"math"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/partner/purchase/tiktok_store"
"git.rosy.net.cn/jx-callback/globals/api2"
beego "github.com/astaxie/beego/server/web"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/jdeclpapi"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"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"
"github.com/astaxie/beego/client/orm"
)
var (
orderNoBeginTimestamp int64
)
func init() {
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
}
type tSkuCountPrice struct {
Count int `json:"count"`
SalePrice int64 `json:"salePrice"`
}
// msgVendorStatus的意思是事件本身的类型类似有时收到NewOrder事件去取订单状态不一定就是New的
// OnOrderAdjust也类似而OrderStatus要记录的是消息所以添加这个
func (c *OrderManager) OnOrderNew(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) {
if order.ConsigneeMobile2 == "" && jxutils.IsStringLikeMobile(order.ConsigneeMobile) {
order.ConsigneeMobile2 = order.ConsigneeMobile
}
db := dao.GetDB()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if order.Status == model.OrderStatusUnknown {
order.Status = model.OrderStatusNew
}
var isDuplicated bool
if order.Status == model.OrderStatusNew && order.VendorID == model.VendorIDJX && !model.IsOrderJXTemp(order) {
isDuplicated, _, err = c.addOrderStatus(orderStatus, db)
} else {
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated {
isDuplicated, err = c.SaveOrder(order, false, db)
}
}
if err == nil {
dao.Commit(db, txDB)
if !isDuplicated {
err = scheduler.CurrentScheduler.OnOrderNew(order, false, false)
}
} else {
dao.Rollback(db, txDB)
}
return err
}
// todo 调整单的处理可能还需要再细化一点,当前只是简单的删除重建
func (c *OrderManager) OnOrderAdjust(order *model.GoodsOrder, orderStatus *model.OrderStatus) (err error) {
if order.ConsigneeMobile2 == "" && jxutils.IsStringLikeMobile(order.ConsigneeMobile) {
order.ConsigneeMobile2 = order.ConsigneeMobile
}
db := dao.GetDB()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
// 出现过调整单后状态回到新订单状态比如911350836000622
// 不完全确定,加一个处理
if order.Status < model.OrderStatusAccepted {
order.Status = model.OrderStatusAccepted
}
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated {
err = utils.CallFuncLogError(func() error {
_, err = db.Db.Raw("DELETE FROM order_sku WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec()
return err
}, "OnAdjustOrder delete order, orderID:%s", order.VendorOrderID)
if err != nil {
return err
}
adjustCount := int8(0)
previousOrder := &model.GoodsOrder{
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
}
if err = dao.GetEntity(db, previousOrder, model.FieldVendorOrderID, model.FieldVendorID); err != nil && !dao.IsNoRowsError(err) {
return err
}
if err == nil {
adjustCount = previousOrder.AdjustCount
if _, err = dao.DeleteEntity(db, previousOrder); err != nil {
return err
}
order.VendorWaybillID = previousOrder.VendorWaybillID
order.WaybillVendorID = previousOrder.WaybillVendorID
} else {
globals.SugarLogger.Warnf("OnOrderAdjust, but previous order:%s doesn't exist", order.VendorOrderID)
}
// err = utils.CallFuncLogError(func() error {
// _, err = db.Db.Raw("DELETE FROM goods_order WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID).Exec()
// return err
// }, "OnAdjustOrder delete order_sku, orderID:%s", order.VendorOrderID)
order.AdjustCount = adjustCount + 1
//扣点的订单需要修改订单的totalshopmoney
if err == nil && order.OrderPayPercentage < 50 && order.OrderPayPercentage > 0 {
order2, _ := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID)
order.TotalShopMoney = order2.TotalShopMoney
}
isDuplicated, err = c.SaveOrder(order, true, db)
}
if err == nil {
dao.Commit(db, txDB)
if !isDuplicated {
// 因为订单调度器需要的是真实状态所以用order的状态
_ = scheduler.CurrentScheduler.OnOrderNew(order, false, false)
_ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false)
}
} else {
dao.Rollback(db, txDB)
}
return err
}
func (c *OrderManager) OnOrderStatusChanged(vendorOrgCode string, orderStatus *model.OrderStatus) (err error) {
// 有些平台(比如美团外卖),在新订单事件没有成功返回,但在重发订单消息前,订单状态转换,则不会再重发新订单事件,特殊处理一下
if orderStatus != nil {
if orderStatus.Status == model.OrderStatusAccepted {
if _, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == ErrCanNotFindOrder {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderStatus.VendorID); handler != nil {
if order, err2 := handler.GetOrder(vendorOrgCode, orderStatus.VendorOrderID, ""); err2 == nil && order != nil {
c.OnOrderNew(order, orderStatus)
}
}
}
}
}
db := dao.GetDB()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
isDuplicated, order, err := c.addOrderStatus(orderStatus, db)
if err == nil {
dao.Commit(db, txDB)
if orderStatus.Status == model.OrderStatusWaybillTipChanged {
if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil {
if handler := partner.GetWaybillTipUpdater(orderStatus.RefVendorID); handler != nil {
tipFee, err2 := handler.GetWaybillTip(jxcontext.AdminCtx, vendorOrgCode, order.VendorStoreID, orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, "")
if err2 == nil {
order.WaybillTipMoney = tipFee
c.UpdateOrderFields(order, []string{"WaybillTipMoney"})
}
}
}
} else if orderStatus.Status == model.OrderStatusFinished {
if order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID); err2 == nil {
// 当前只针对三方运单更新配送费信息
if order.WaybillVendorID >= 0 && order.VendorWaybillID != "" && order.WaybillVendorID != order.VendorID {
if waybill, err2 := c.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID); err2 == nil {
if handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID); handler != nil {
tipFee, err2 := handler.GetWaybillTip(jxcontext.AdminCtx, waybill.VendorOrgCode, "", order.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2)
if err2 == nil && waybill.TipFee != tipFee {
waybill.ActualFee += tipFee - waybill.TipFee
waybill.TipFee = tipFee
dao.UpdateEntity(db, waybill, "TipFee", "ActualFee")
}
}
}
}
// 目前存在当订单为平台自配送时,本地储存新订单的结算信息是包含了配送费的!所以结算信息不对!
// 修改为订单完成时更新订单的结算信息
settlementAmount, err3 := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).GetOrderSettleAccounts(order)
if err3 == nil && settlementAmount != model.NO {
order.TotalShopMoney = settlementAmount
dao.UpdateEntity(db, order, "TotalShopMoney")
}
//更新订单new_earning_price
if order.EarningType == model.EarningTypePoints {
waybill, _ := c.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
// store, _ := c.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
if waybill == nil {
if (order.NewEarningPrice == 0 || order.NewEarningPrice != order.TotalShopMoney*int64(100-order.OrderPayPercentage/2)/int64(100)) && order.OrderPayPercentage <= 50 {
order.NewEarningPrice = order.TotalShopMoney * int64(100-order.OrderPayPercentage/2) / int64(100)
}
} else {
if (order.NewEarningPrice == 0 || order.NewEarningPrice != (order.TotalShopMoney-waybill.DesiredFee)*int64(100-order.OrderPayPercentage/2)/int64(100)) && order.OrderPayPercentage <= 50 {
order.NewEarningPrice = order.TotalShopMoney*int64(100-order.OrderPayPercentage/2)/int64(100) - waybill.DesiredFee
}
}
dao.UpdateEntity(db, order, "NewEarningPrice")
}
//美团订单如果有售后的话,订单完成后才能查到售后结算
if order.VendorID == model.VendorIDMTWM {
if afsOrders, _ := dao.GetAfsOrders(db, order.VendorID, order.VendorOrderID, ""); len(afsOrders) > 0 {
for _, v := range afsOrders {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(v.VendorID); handler != nil {
if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, v.VendorOrderID, v.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
v.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
}
dao.UpdateEntity(db, v, "AfsTotalShopMoney")
}
}
}
}
}
// 刷新订单结束时间
order.OrderFinishedAt = time.Now()
dao.UpdateEntity(db, order, "OrderFinishedAt")
} else if orderStatus.Status == model.OrderStatusCanceled {
order, err2 := c.LoadOrder(orderStatus.VendorOrderID, orderStatus.VendorID) // 订单被取消,则取消三方运单
waybill, _ := dao.GetWaybills(db, order.VendorOrderID, []int64{model.VendorIDMTPS, model.VendorIDDada, model.VendorIDFengNiao, model.VendorIDUUPT, model.VendorIDSFPS})
for _, v := range waybill {
if err := partner.GetDeliveryPlatformFromVendorID(v.WaybillVendorID).Handler.CancelWaybill(v, 0, "订单被取消了"); err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s]被取消了,运单[%s]取消失败Err: %s", order.VendorOrderID, v.VendorWaybillID, err.Error()), "")
} else {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s]被取消了,运单[%s]取消成功", order.VendorOrderID, v.VendorWaybillID), "")
}
}
//如果取消订单则要把库存加回去
if err2 == nil {
// 判断是否需要打印取消订单
storeDetail, err := c.LoadStoreDetail(order.StoreID, order.VendorID)
if err == nil && storeDetail.IsPrintCancelOrder == model.YES { // 取消申请
_, err = netprinter.PrintRefundOrCancelOrder(jxcontext.AdminCtx, model.YES, order, order.StoreID)
}
if err != nil {
globals.SugarLogger.Debug("Get store Detail Err: ", err)
}
}
}
if !isDuplicated {
if order != nil {
order.Skus = c.loadOrderSku(db, order.VendorOrderID, order.VendorID)
_ = scheduler.CurrentScheduler.OnOrderStatusChanged(order, orderStatus, false)
}
}
} else {
dao.Rollback(db, txDB)
}
return err
}
func (c *OrderManager) ChangeOrderInfo(order *model.GoodsOrder) (err error) {
db := dao.GetDB()
_, err = dao.UpdateEntity(db, order, "ConsigneeAddress", "ConsigneeName", "ConsigneeMobile", "ConsigneeLat", "ConsigneeLng", "BuyerComment")
return err
}
func (c *OrderManager) OnOrderMsg(order *model.GoodsOrder, vendorStatus, remark string) (err error) {
_, _, err = c.addOrderStatus(&model.OrderStatus{
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: order.VendorOrderID,
RefVendorID: order.VendorID,
VendorStatus: vendorStatus,
Status: model.OrderStatusMsg,
StatusTime: time.Now(),
Remark: utils.LimitUTF8StringLen(remark, 255),
}, nil)
return err
}
func setFakeOrderFlag(db *dao.DaoDB, order *model.GoodsOrder) {
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
if realMobile := jxutils.GetRealMobile4Order(order); realMobile != "" {
if configList, err := dao.QueryConfigs(db, model.ConfigSysFakeOrderMobiles, model.ConfigTypeSys, ""); err == nil && len(configList) > 0 {
isMatch := false
mobileList := strings.Split(configList[0].Value, ",")
for _, v := range mobileList {
if jxutils.TrimDecorationChar(v) == realMobile {
isMatch = true
break
}
}
if isMatch {
order.Flag |= model.OrderFlagMaskFake
}
}
}
}
}
func (c *OrderManager) SaveOrder(order *model.GoodsOrder, isAdjust bool, db *dao.DaoDB) (isDuplicated bool, err error) {
// 忽略美团超市的订单
if order.VendorID == model.VendorIDMTWM {
if order.VendorStoreID == "2391979" || order.VendorStoreID == "7379027" {
return
}
}
// 忽略查找JX信息错误
c.updateOrderOtherInfo(order, db)
order.ID = 0
order.WaybillVendorID = model.VendorIDUnknown
order.OrderFinishedAt = utils.DefaultTimeValue
setFakeOrderFlag(db, order)
// cms.HandleOrder4Consignee(order)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
// todo hardcode 兼容京东消息错序问题
if true { //order.VendorID == model.VendorIDJD {
orderStatus := &model.OrderStatus{}
if dao.GetRow(db, orderStatus, `
SELECT *
FROM order_status
WHERE order_type = ? AND vendor_order_id = ? AND vendor_id = ? AND status > 0
ORDER BY status_time DESC
LIMIT 1
`, model.OrderTypeOrder, order.VendorOrderID, order.VendorID) == nil {
if orderStatus.Status > order.Status {
order.Status = orderStatus.Status
order.VendorStatus = orderStatus.VendorStatus
order.StatusTime = orderStatus.StatusTime
// jxutils.RefreshOrderSkuRelated(order)
}
}
}
filterOrderInfo(order)
created, _, err2 := db.Db.ReadOrCreate(order, "VendorOrderID", "VendorID")
if err = err2; err == nil {
originalOrder := &model.GoodsOrderOriginal{
VendorOrderID: order.VendorOrderID,
VendorID: order.VendorID,
OrderCreatedAt: order.OrderCreatedAt,
OriginalData: order.OriginalData,
}
_, _, err = db.Db.ReadOrCreate(originalOrder, "VendorOrderID", "VendorID")
if created {
if err = dao.CreateMultiEntities(db, order.Skus); err != nil {
baseapi.SugarLogger.Warnf("saveOrder orderID:%s, save order_sku failed with error:%v", order.VendorOrderID, err)
}
} else {
isDuplicated = true
order.DuplicatedCount++
db.Db.Update(order, "DuplicatedCount")
baseapi.SugarLogger.Infof("saveOrder duplicated orderid:%s msg received", order.VendorOrderID)
}
//} else {
// baseapi.SugarLogger.Warnf("saveOrder orderID:%s, save order OriginalData failed2 with error:%v", order.VendorOrderID, err)
//}
} else {
//globals.SugarLogger.Warnf("saveOrder create order:%v, error:%v", order, err)
}
//修改商品库存
//if err == nil {
// err = ModifyOrderSkusStock(db, order, false)
//}
if err == nil {
dao.Commit(db, txDB)
}
return isDuplicated, err
}
func ModifyOrderSkusStock(db *dao.DaoDB, order *model.GoodsOrder, isAdd bool) (err error) {
skus := order.Skus
for _, sku := range skus {
storeSkus, _ := dao.GetStoresSkusInfo(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, []int{sku.SkuID})
if len(storeSkus) == 0 {
// if !isAdd {
// globals.SugarLogger.Warnf("此订单商品没得storsku%v,%v", order.VendorOrderID, sku.SkuID)
// }
continue
}
storeSku, stock := storeSkus[0], 0
if storeSku.Stock == 0 {
if !isAdd {
// globals.SugarLogger.Warnf("此订单商品库存为0%v,%v", order.VendorOrderID, sku.SkuID)
}
continue
}
if isAdd {
stock = storeSku.Stock + sku.Count
} else {
stock = storeSku.Stock - sku.Count
//如果是进货的订单,进货方门店对应商品要加上这么多库存
if order.OrderType == model.OrderTypeSupplyGoods {
storeSkus2, _ := dao.GetStoresSkusInfo(db, []int{order.FromStoreID}, []int{sku.SkuID})
if len(storeSkus2) > 0 {
storeSku3 := storeSkus2[0]
storeSku3.Stock = storeSku3.Stock + sku.Count
db.Db.Update(storeSku3, "Stock")
}
}
realStock := checkPriceDefendOrderByStock(db, jxutils.GetSaleStoreIDFromOrder(order), sku.SkuID, stock, storeSku.JxPrice)
if realStock != -1 {
stock = realStock
}
}
storeSku.Stock = stock
db.Db.Update(storeSku, "Stock")
if order.VendorID != model.VendorIDJX {
// dao.SetStoreSkuSyncStatus(db, order.VendorID, []int{jxutils.GetSaleStoreIDFromOrder(order)}, []int{sku.SkuID}, model.SyncFlagStockMask)
}
}
return err
}
func filterOrderInfo(order *model.GoodsOrder) {
order.ConsigneeName = utils.LimitUTF8StringLen2(order.ConsigneeName, 32)
order.ConsigneeAddress = utils.LimitUTF8StringLen2(order.ConsigneeAddress, 255)
order.ConsigneeAddress = strings.ReplaceAll(order.ConsigneeAddress, "·", "")
}
// FinisOrderWaybillFee 订单完成时,计算结算信息
func FinisOrderWaybillFee(db *dao.DaoDB, order *model.GoodsOrder, bill *model.Waybill) (err error) {
if db == nil {
db = dao.GetDB()
}
if bill.WaybillVendorID != model.VendorIDMTPS && bill.WaybillVendorID != model.VendorIDDada && bill.WaybillVendorID != model.VendorIDFengNiao && bill.WaybillVendorID != model.VendorIDUUPT {
return nil
}
// 查询所有运单
bills, err := dao.GetWaybills(db, order.VendorOrderID, nil)
if err != nil {
return err
}
store, _ := dao.GetStoreDetail(db, order.JxStoreID, order.VendorID, order.VendorOrgCode)
// 正常来说只会出现一个完成运单,之前有bug会出现多个完成订单,这不做考虑.默认一个运单完成,其他运单取消状态
// 1.完成当前运单的金额核算,正常完成的订单金额不需要核算
// 2.取消运单的金额核算
cancelWaybill := make(map[string]*model.Waybill, 0)
for _, v := range bills {
if v.Status != model.WaybillStatusCanceled {
continue
}
if v.VendorWaybillID == bill.VendorWaybillID {
continue
}
cancelWaybill[v.VendorWaybillID] = v
}
// 已经全部运单取消,退款结算
for _, v := range bills {
if v.VendorWaybillID == bill.VendorWaybillID {
continue
}
// 已经取消订单的违约金计算
if err = countWaybillSettleInfo(db, order, v, store); err != nil {
return err
}
}
// 3.总的收支核算
if err = orderFeeSettle(db, order, bill, bills, store); err != nil {
return err
}
return nil
}
// ResetCreateWaybillFee 取消所有运单时计算结算信息
func ResetCreateWaybillFee(db *dao.DaoDB, order *model.GoodsOrder, bill *model.Waybill) (err error) {
if db == nil {
db = dao.GetDB()
}
if bill.WaybillVendorID != model.VendorIDMTPS && bill.WaybillVendorID != model.VendorIDDada && bill.WaybillVendorID != model.VendorIDFengNiao && bill.WaybillVendorID != model.VendorIDUUPT {
return nil
}
// 获取订单运单详情列表
store, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode)
// 订单被取消了,所有运单应该也被取消了,检查是否退还配送费
// 1.查询订单创建的所有运单,三方配送运单(达达,蜂鸟,uu,美团配送),平台自配送订单不参与
if err := countWaybillSettleInfo(db, order, bill, store); err != nil {
return err
}
// 所有运单停止调度之后才开始退还余额
bills, err := dao.GetWaybills(db, order.VendorOrderID, nil)
if err != nil {
return err
}
// 所有取消的运单
cancelWaybill := make(map[string]*model.Waybill, 0)
for _, v := range bills {
if v.Status == model.WaybillStatusCanceled && v.VendorWaybillID != bill.VendorWaybillID {
cancelWaybill[v.VendorWaybillID] = v
}
}
cancelWaybill[bill.VendorWaybillID] = bill
// 已经全部运单取消,退款结算
if len(bills) == len(cancelWaybill) {
// 最终的金额核算,多退少补
if err = orderFeeSettle(db, order, bill, bills, store); err != nil {
return err
}
}
return err
}
// countWaybillSettleInfo 计算订单的结算信息
func countWaybillSettleInfo(db *dao.DaoDB, order *model.GoodsOrder, bill *model.Waybill, store *dao.StoreDetail) error {
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID); handlerInfo != nil {
// 这一步必须要做,可能不是最后取消订单,需要更新违约金和取消状态
deductFee, err := handlerInfo.Handler.GetDeliverLiquidatedDamages(bill.VendorOrderID, bill.VendorWaybillID)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,获取违约金异常:%v", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err), "")
return err
}
if err = dao.UpdateWaybillActualFee(db, bill.VendorWaybillID, bill.VendorOrderID, deductFee, deductFee); err != nil {
return err
}
// 门店发单,支付运单违约金
if store != nil && store.CreateDeliveryType == model.YES && deductFee != model.NO {
err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(jxcontext.AdminCtx, store.ID, int(deductFee), partner.StoreAcctTypeExpendCreateWaybillDeductFee, bill.VendorOrderID, bill.VendorWaybillID, 0)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,获取违约金门店扣除失败:%v,金额[%d]", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err, deductFee), "")
return err
}
}
if store != nil && store.CreateDeliveryType == model.NO && deductFee != model.NO {
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, store.BrandID, int(deductFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDeductFee, order.VendorOrderID, order.VendorWaybillID)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,获取违约金品牌扣除失败:%v,金额[%d]", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err, deductFee), "")
return err
}
}
if err == nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,违约金扣除成功:%d", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, deductFee), "")
return err
}
}
return nil
}
// 订单金额核算
func orderFeeSettle(db *dao.DaoDB, order *model.GoodsOrder, bill *model.Waybill, bills []*model.Waybill, store *dao.StoreDetail) (err error) {
billExpend := 0
billIncome := 0
allFee := 0
// 门店结算,全部支出
if store.CreateDeliveryType == model.YES {
// 此订单支出的费用
expendType := []int{partner.StoreAcctTypeExpendCreateWaybillEx, partner.StoreAcctTypeExpendCreateWaybillTip, partner.StoreAcctTypeExpendCreateWaybill2ndMore, partner.StoreAcctTypeExpendCreateWaybillDeductFee, partner.StoreAcctTypeRealFeeExpend}
billExpend, err = dao.GetStoreAcctExpendTotal(db, store.ID, expendType, bill.VendorOrderID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if err != nil {
globals.SugarLogger.Errorf("GetStoreAcctExpendTotal 545 err :%v", err)
return err
}
// 此订单退还的费用
incomeType := []int{partner.StoreAcctTypeRealFeeIncome, partner.StoreAcctTypeIncomeCancelTemp, partner.StoreAcctTypeIncomeCancelReal}
billIncome, err = dao.GetStoreAcctIncomeTotal(db, store.ID, incomeType, bill.VendorOrderID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if err != nil {
globals.SugarLogger.Errorf("GetStoreAcctIncomeTotal 551 err :%v", err)
return err
}
} else {
billExpend, err = dao.GetBrandBillOrderExpend(db, store.BrandID, bill.VendorOrderID)
if err != nil {
return err
}
billIncome, err = dao.GetBrandBillOrderIncome(db, store.BrandID, bill.VendorOrderID)
if err != nil {
return err
}
}
for _, v := range bills {
allFee += int(v.DesiredFee)
//allFee += int(v.TipFee)
}
// 运单支出费用统计,应该等于 支出费用- 退还费用
globals.SugarLogger.Errorf("计算错误:订单支出费用应该=退还费用+运单支出费用,支出费用:%d,已经退还费用:%d,运单计算费用:%d", billExpend, billIncome, allFee)
if allFee != billExpend-billIncome {
globals.SugarLogger.Errorf("计算错误:订单支出费用应该=退还费用+运单支出费用,支出费用:%d,已经退还费用:%d,剩余退还费用:%d", billExpend, billIncome, billExpend-billIncome)
}
if billExpend-billIncome == allFee {
globals.SugarLogger.Debugf("计算正确,运单消耗[%d],账户支出[%d],账户退回[%d]", allFee, billExpend, billIncome)
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("计算正确,运单消耗[%d],账户支出[%d],账户退回[%d]", allFee, billExpend, billIncome), "")
return nil
}
abnormalAmount := billExpend - billIncome - allFee
switch store.CreateDeliveryType {
case model.NO: // 品牌结算
if abnormalAmount > 0 { // 多退
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, store.BrandID, abnormalAmount, model.BrandBillTypeIncome, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,品牌支出大于消耗,多退:%v,金额[%d]", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err, abnormalAmount), "")
globals.SugarLogger.Errorf("InsertBrandBill 489 : %v", err)
return err
}
}
if abnormalAmount < 0 {
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, store.BrandID, abnormalAmount*-1, model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,品牌支出小于消耗,少补:%v,金额[%d]", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err, abnormalAmount), "")
globals.SugarLogger.Errorf("InsertBrandBill 489 : %v", err)
return err
}
}
case model.YES: // 门店结算
if abnormalAmount > 0 { // 多退
err = partner.CurStoreAcctManager.InsertStoreAcctIncomeAndUpdateStoreAcctBalance(jxcontext.AdminCtx, store.ID, int(billExpend-billIncome-allFee), partner.StoreAcctTypeIncomeCancelReal, bill.VendorOrderID, bill.VendorWaybillID, 0)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,支出大于消耗,多退:%v,金额[%d]", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err, abnormalAmount), "")
globals.SugarLogger.Errorf("InsertStoreAcctIncomeAndUpdateStoreAcctBalance 483 : %v", err)
}
}
if abnormalAmount < 0 {
err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(jxcontext.AdminCtx, store.ID, int(abnormalAmount)*-1, partner.StoreAcctTypeExpendCreateWaybill2ndMore, bill.VendorOrderID, bill.VendorWaybillID, 0)
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单[%s],运单平台[%d],运单[%s]取消,支出小于消耗,少补:%v,金额[%d]", order.VendorOrderID, bill.WaybillVendorID, bill.VendorWaybillID, err, abnormalAmount), "")
globals.SugarLogger.Errorf("InsertStoreAcctIncomeAndUpdateStoreAcctBalance 483 : %v", err)
}
}
}
return err
}
func checkPriceDefendOrderByStock(db *dao.DaoDB, storeID, skuID, stock, jxPrice int) (realStock int) {
var (
sumStock = 0
)
priceDefends, _ := dao.GetPriceDefendOrder(db, "", []int{storeID}, []int{skuID}, []int{jxutils.GetDefendPriceIssue()}, 0, 1, 0, 1, "", utils.ZeroTimeValue, utils.ZeroTimeValue, false)
if len(priceDefends) == 0 {
return -1
}
for _, v := range priceDefends {
sumStock += v.Count
}
//如果现库存小于等于用户守价的库存,就要开始了
//如果小于,要按照守价时间的先后来决定
//如果等于就刚好全部成功然后库存清0
if stock < sumStock {
tStock := stock
for _, v := range priceDefends {
if tStock <= v.Count {
tStock -= v.Count
v.IsSuccess = model.YES
v.RealPrice = int64(jxPrice)
dao.UpdateEntity(db, v, "IsSuccess", "RealPrice")
} else {
continue
}
}
realStock = tStock
} else if stock == sumStock {
for _, v := range priceDefends {
v.IsSuccess = model.YES
v.RealPrice = int64(jxPrice)
dao.UpdateEntity(db, v, "IsSuccess", "RealPrice")
}
realStock = 0 //库存清0
} else {
realStock = -1
}
return realStock
}
func (c *OrderManager) updateOrderSkuOtherInfo(order *model.GoodsOrder, db *dao.DaoDB, storePayPercentage, changePriceType int) (err error) {
jxStoreID := jxutils.GetShowStoreIDFromOrder(order)
var opNumStr string
if time.Now().Sub(order.OrderCreatedAt) < 1*time.Hour && order.VendorID != model.VendorIDJD {
opNumStr = "2"
} else {
opNumStr = "2"
}
if jxStoreID == 0 {
return nil
}
orderSkus := order.Skus
var vendorSkuIDs []string
for _, v := range orderSkus {
if v.VendorSkuID != "" {
vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID)
}
}
if len(vendorSkuIDs) > 0 {
var vendorStoreID string
if order.VendorID == model.VendorIDJDShop && order.VendorOrgCode == "1" {
vendorStoreID = model.JdShopMainVendorStoreID
} else {
vendorStoreID = order.VendorStoreID
}
l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs)
if err != nil {
return err
}
skumapper := storeSkuPriceAndWeight2Map(l)
for _, v := range orderSkus {
v.VendorOrderID = order.VendorOrderID
v.VendorID = order.VendorID
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
skuBindInfo := skumapper[v.VendorSkuID]
if skuBindInfo == nil {
if v.ShopPrice == 0 {
v.ShopPrice = v.SalePrice * 70 / 100
}
} else {
// TODO 客户端当前逻辑认为SkuID为0为赠品
if v.SkuID == 0 {
v.SkuID = v.JxSkuID
}
v.JxSkuID = skuBindInfo.SkuID
//京东商城的话,门店里可能取不到对应商品
if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDDD {
if v.SkuID == 0 && v.JxSkuID != 0 {
v.SkuID = v.JxSkuID
}
// v.JxSkuID = v.SkuID
storeSkus, _ := dao.GetStoresSkusInfo(db, []int{order.StoreID}, []int{v.SkuID})
if len(storeSkus) > 0 {
v.ShopPrice = int64(storeSkus[0].Price)
} else {
v.ShopPrice = v.SalePrice * 70 / 100
}
} else {
v.ShopPrice = int64(skuBindInfo.Price)
if v.ShopPrice == 0 {
v.ShopPrice = v.SalePrice * 70 / 100
}
}
v.SkuName = jxutils.ComposeSkuNameOriginal(skuBindInfo.Prefix, skuBindInfo.Name, skuBindInfo.Comment, skuBindInfo.Unit, skuBindInfo.SpecQuality, skuBindInfo.SpecUnit, 0)
v.Weight = skuBindInfo.Weight // 以本地信息中的WEIGHT为准
if v.Upc == "" {
v.Upc = skuBindInfo.Upc
}
//饿鲜达的订单做一下处理
if strings.Contains(order.StoreName, model.ExdStoreName) {
if v.SkuID == 0 && !strings.Contains(v.SkuName, "免费") {
v.SkuID = v.JxSkuID
}
}
if skuBindInfo.Price == 0 {
globals.SugarLogger.Infof("updateOrderSkuOtherInfo [运营%s]%s订单sku门店价格为零一般原因为没有门店价格信息orderID:%s, StoreID:%d, SkuID:%d, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.JxSkuID, v)
}
}
}
// 直营店始终按比例结算,不考虑活动与结算表
salePrice := v.SalePrice
if changePriceType == model.StoreChangePriceTypeManagedStore && v.ShopPrice != 0 {
salePrice = 0
}
v.EarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, salePrice, storePayPercentage)
}
// 直营店始终按比例结算,不考虑活动与结算表
if changePriceType != model.StoreChangePriceTypeManagedStore {
updateSingleOrderEarningPrice(order, db)
}
//TODO 重复购买有活动且结算价大于0的商品需要拆分第一个商品按结算价后面的商品按shopprice 或者 saleprice, 2020-05-06
//TODO 京东美团的订单,做活动的商品之前就会拆分出来,所以只做更新,饿百暂时不管, 2020-05-07
//TODO 不根据商品是否拆分直接根据该商品做了活动并且他的vendorPrice 和 salePrice 相等,就按新规则结算, 2020-05-11
//TODO 现在不判断商品做没做活动只要vendorPrice和salePrice不等就默认为做了活动不做活动的商品就按新规则结算2020-05-18
// if order.VendorID == model.VendorIDJD || order.VendorID == model.VendorIDMTWM {
// for _, v := range orderSkus {
// if v.EarningPrice > 0 {
// if v.VendorPrice == v.SalePrice {
// var earningPrice = 0
// if v.ShopPrice < v.SalePrice {
// if v.ShopPrice == 0 {
// earningPrice = int(utils.Float64TwoInt64(math.Round(utils.Int2Float64(int(v.SalePrice)) * utils.Int2Float64(storePayPercentage) / 100)))
// } else {
// earningPrice = int(utils.Float64TwoInt64(math.Round(utils.Int2Float64(int(v.ShopPrice)) * utils.Int2Float64(storePayPercentage) / 100)))
// }
// } else {
// earningPrice = int(utils.Float64TwoInt64(math.Round(utils.Int2Float64(int(v.SalePrice)) * utils.Int2Float64(storePayPercentage) / 100)))
// }
// v.EarningPrice = int64(earningPrice)
// }
// }
// }
// }
}
return nil
}
func storeSkuPriceAndWeight2Map(l []*dao.StoreSkuPriceAndWeight) (skuMapper map[string]*dao.StoreSkuPriceAndWeight) {
skuMapper = make(map[string]*dao.StoreSkuPriceAndWeight)
for _, v := range l {
skuMapper[v.VendorSkuID] = v
}
return skuMapper
}
func updateSingleOrderEarningPrice(order *model.GoodsOrder, db *dao.DaoDB) {
jxStoreID := jxutils.GetShowStoreIDFromOrder(order)
skuIDMap := make(map[int]int)
for _, v := range order.Skus {
if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 {
skuIDMap[skuID] = 1
}
}
if len(skuIDMap) > 0 {
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order.OrderCreatedAt, order.OrderCreatedAt)
if err != nil {
globals.SugarLogger.Errorf("updateOrderSkuOtherInfo can not get sku promotion info for error:%v", err)
}
if actStoreSkuMap := jxutils.NewActStoreSkuMap(actStoreSkuList, false); actStoreSkuMap != nil {
for _, v := range order.Skus {
if skuID := jxutils.GetSkuIDFromOrderSku(v); skuID > 0 {
if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
v.EarningPrice = actStoreSku.EarningPrice
if true { //v.StoreSubName != "" { // 之前这里为什么要加判断?
v.StoreSubID = actStoreSku.ActID
}
}
}
}
}
}
}
func (c *OrderManager) updateOrderOtherInfo(order *model.GoodsOrder, db *dao.DaoDB) (err error) {
payPercentage := 0
changePriceType := model.StoreChangePriceTypeDirect
var storeDetail *dao.StoreDetail
if order.VendorID == model.VendorIDJDShop {
storeDetail, err = dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, order.VendorID, order.VendorOrgCode)
} else {
storeDetail, err = dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, order.VendorID, "")
}
if err != nil {
if !dao.IsNoRowsError(err) {
return err
}
if time.Now().Sub(order.OrderCreatedAt) < 1*time.Hour {
globals.SugarLogger.Infof("updateOrderOtherInfo [运营]订单在京西与平台都找不到京西门店信息,订单:%s,平台门店ID:%s,平台:%s", order.VendorOrderID, order.VendorStoreID, model.VendorChineseNames[order.VendorID])
}
err = nil
} else {
order.JxStoreID = storeDetail.Store.ID
changePriceType = int(storeDetail.ChangePriceType)
//判断订单结算比例
if storeDetail.VendorPayPercentage != 0 {
payPercentage = storeDetail.VendorPayPercentage
} else {
payPercentage = storeDetail.PayPercentage
}
if payPercentage < 50 {
order.EarningType = model.EarningTypePoints
} else {
order.EarningType = model.EarningTypeQuote
}
order.OrderPayPercentage = payPercentage
order.CreateDeliveryType = storeDetail.CreateDeliveryType
}
if err = c.updateOrderSkuOtherInfo(order, db, payPercentage, changePriceType); err == nil {
jxutils.RefreshOrderSkuRelated(order)
//EarningPrice2, 新规则门店结算比例在50以下的做新规则计算
jxutils.RefreshOrderEarningPrice2(order, payPercentage)
// caculateOrderEarningPrice(order, payPercentage)
}
return err
}
// 计算结算给门店的金额
// func caculateOrderEarningPrice(order *model.GoodsOrder, storePayPercentage int) {
// order.EarningPrice = 0
// for _, v := range order.Skus {
// skuEarningPrice := v.EarningPrice
// if skuEarningPrice == 0 {
// skuEarningPrice = jxutils.CaculateSkuEarningPrice(v.ShopPrice, v.SalePrice, storePayPercentage)
// }
// order.EarningPrice += skuEarningPrice * int64(v.Count)
// }
// }
func (c *OrderManager) addOrderStatus(orderStatus *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, order *model.GoodsOrder, err error) {
if db == nil {
db = dao.GetDB()
}
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
order = &model.GoodsOrder{
VendorOrderID: orderStatus.VendorOrderID,
VendorID: orderStatus.VendorID,
}
if err = db.Db.ReadForUpdate(order, "VendorOrderID", "VendorID"); err == nil {
// todo 美团在订单完成后还可能收到订单取消应该当成售后单处理才合适强制忽略这种情况比如订单80662201436073600
// 后来又发现有订单81710104014426376在完成后直接再被取消的情况不能生成售后单还是再允许完成后取消。。。
// if orderStatus.VendorID == model.VendorIDMTWM && model.IsOrderFinalStatus(order.Status) {
// return false, order, nil
// }
if (model.IsOrderLockStatus(orderStatus.Status) || model.IsOrderUnlockStatus(orderStatus.Status)) ||
(model.IsOrderMainStatus(orderStatus.Status) && orderStatus.Status >= order.Status) { // todo 要求status不能回绕
order.VendorStatus = orderStatus.VendorStatus
updateFields := []string{
"VendorStatus",
"UpdatedAt",
}
if model.IsOrderMainStatus(orderStatus.Status) {
order.Status = orderStatus.Status
order.StatusTime = orderStatus.StatusTime
updateFields = append(updateFields, "Status", "StatusTime")
if model.IsOrderFinalStatus(orderStatus.Status) {
order.OrderFinishedAt = orderStatus.StatusTime
updateFields = append(updateFields, "OrderFinishedAt")
if order.LockStatus != model.OrderStatusUnknown {
order.LockStatus = model.OrderStatusUnknown
updateFields = append(updateFields, "LockStatus")
}
}
} else {
if model.IsOrderUnlockStatus(orderStatus.Status) {
order.LockStatus = model.OrderStatusUnknown
updateFields = append(updateFields, "LockStatus")
} else if model.IsOrderLockStatus(orderStatus.Status) {
if order.LockStatus != model.OrderStatusUnknown {
globals.SugarLogger.Warnf("addOrderStatus refOrderID:%s, orderID:%s, order.LockStatus:%d, status.LockStatus:%d", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID, order.LockStatus, orderStatus.Status)
}
order.Flag &= ^model.OrderFlagMaskUserApplyCancel
order.LockStatus = orderStatus.Status
order.LockStatusTime = orderStatus.StatusTime
updateFields = append(updateFields, "LockStatus", "LockStatusTime", "Flag")
}
}
utils.CallFuncLogError(func() error {
_, err = db.Db.Update(order, updateFields...)
return err
}, "addOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
} else {
isDuplicated = true
}
} else {
order = nil
if dao.IsNoRowsError(err) { // todo 消息错序
err = nil
} else {
globals.SugarLogger.Warnf("addOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
}
}
}
return isDuplicated, order, err
}
func (c *OrderManager) loadOrderSku(db *dao.DaoDB, vendorOrderID string, vendorID int) (orderSkus []*model.OrderSku) {
utils.CallFuncLogError(func() (err error) {
_, err = db.Db.QueryTable("order_sku").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).All(&orderSkus)
return err
}, "loadOrderSku orderID:%s", vendorOrderID)
return orderSkus
}
func (c *OrderManager) LoadStoreDetail(storeID, vendorID int) (storeDetail *dao.StoreDetail, err error) {
var (
db = dao.GetDB()
)
storeDetail, err = dao.GetStoreDetail(db, storeID, vendorID, "")
return storeDetail, err
}
func (c *OrderManager) loadOrder(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) {
db1 := dao.GetDB()
db := db1.Db
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorOrderID2: vendorOrderID2,
VendorID: vendorID,
}
keyFields := []string{
model.FieldVendorID,
}
if vendorOrderID != "" {
keyFields = append(keyFields, model.FieldVendorOrderID)
}
if vendorOrderID2 != "" {
keyFields = append(keyFields, model.FieldVendorOrderID2)
}
if err = db.Read(order, keyFields...); err == nil {
vendorOrderID = order.VendorOrderID
order.Skus = c.loadOrderSku(db1, vendorOrderID, vendorID)
}
if err != nil {
order = nil
if err == orm.ErrNoRows {
err = ErrCanNotFindOrder
}
}
return order, err
}
func (c *OrderManager) LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error) {
return c.loadOrder(vendorOrderID, "", vendorID)
}
func (c *OrderManager) LoadOrder2(vendorOrderID2 string, vendorID int) (order *model.GoodsOrder, err error) {
return c.loadOrder("", vendorOrderID2, vendorID)
}
func (c *OrderManager) LoadOrderFinancial(vendorOrderID string, vendorID int) (order *model.OrderFinancial, err error) {
return c.loadOrderFinancial(vendorOrderID, "", vendorID)
}
func (c *OrderManager) LoadOrderFinancial2(vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error) {
return c.loadOrderFinancial("", vendorOrderID2, vendorID)
}
func (c *OrderManager) loadOrderFinancial(vendorOrderID, vendorOrderID2 string, vendorID int) (order *model.OrderFinancial, err error) {
db := orm.NewOrm()
order = &model.OrderFinancial{
VendorOrderID: vendorOrderID,
VendorOrderID2: vendorOrderID2,
VendorID: vendorID,
}
keyFields := []string{
model.FieldVendorID,
}
if vendorOrderID != "" {
keyFields = append(keyFields, model.FieldVendorOrderID)
}
if vendorOrderID2 != "" {
keyFields = append(keyFields, model.FieldVendorOrderID2)
}
// 这块不知道怎么写了、、、标注一下
if err = db.Read(order, keyFields...); err == nil {
vendorOrderID = order.VendorOrderID
err = utils.CallFuncLogError(func() error {
_, err = db.QueryTable("order_sku_financial").Filter("vendor_order_id", vendorOrderID).Filter("vendor_id", vendorID).Filter("is_afs_order", 0).All(&order.Skus)
return err
}, "LoadOrder orderID:%s", vendorOrderID)
}
if err != nil {
order = nil
if err == orm.ErrNoRows {
err = ErrCanNotFindOrder
}
}
return order, err
}
func (c *OrderManager) UpdateOrderStatusAndDeliveryFlag(order *model.GoodsOrder) (err error) {
return c.UpdateOrderFields(order, []string{"Status", "DeliveryFlag"})
}
func (c *OrderManager) UpdateOrderFields(order *model.GoodsOrder, fieldList []string) (err error) {
db := dao.GetDB()
utils.CallFuncLogError(func() error {
if order.ID == 0 {
order2 := *order
if err = dao.GetEntity(db, &order2, model.FieldVendorOrderID, model.FieldVendorID); err == nil {
order.ID = order2.ID
} else if dao.IsNoRowsError(err) {
err = nil // 强制忽略订单不存在错误
}
}
if err == nil && order.ID != 0 {
_, err = db.Db.Update(order, fieldList...)
}
return err
}, "UpdateOrderFields orderID:%s failed with error:%v", order.VendorOrderID, err)
return err
}
func (c *OrderManager) RefreshHistoryOrdersEarningPrice(ctx *jxcontext.Context, vendorOrderID string, actID int, vendorIDs []int, storeID int, fromDate, toDate string, isAsync, isContinueWhenError bool) (hint string, errCode string, err error) {
var (
orderList []*model.GoodsOrder
fromDateParam time.Time
toDateParam time.Time
beginAt time.Time
endAt time.Time
)
db := dao.GetDB()
if actID > 0 {
if fromDate != "" && toDate != "" {
fromDateParam = utils.Str2Time(fromDate)
toDateParam = utils.Str2Time(toDate)
actList, _ := dao.QueryActs(db, actID, 0, math.MaxInt32, 0, "", -1, nil, nil, nil, 0, nil, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue)
if len(actList.Data) > 0 {
actBeginAt := actList.Data[0].BeginAt
actEndAt := actList.Data[0].EndAt
if fromDateParam.Sub(actBeginAt) > 0 && fromDateParam.Sub(actEndAt) > 0 {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 [%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam))
}
if actBeginAt.Sub(toDateParam) > 0 && actEndAt.Sub(toDateParam) > 0 {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("结算活动有效时间范围与订单创建时间范围不一致!,活动时间范围:[%v] 至 [%v] ,订单创建时间范围 [%v] 至 [%v]", actBeginAt, actEndAt, fromDateParam, toDateParam))
}
if fromDateParam.Sub(actBeginAt) > 0 {
beginAt = fromDateParam
if toDateParam.Sub(actEndAt) > 0 {
endAt = actEndAt
} else {
endAt = toDateParam
}
} else {
beginAt = actBeginAt
if toDateParam.Sub(actEndAt) > 0 {
endAt = actEndAt
} else {
endAt = toDateParam
}
}
orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, beginAt, endAt)
} else {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关结算活动活动ID[%d]", actID))
}
} else if fromDate == "" && toDate == "" {
actList, _ := dao.QueryActs(db, actID, 0, math.MaxInt32, 0, "", -1, nil, nil, nil, 0, nil, 0, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue)
if len(actList.Data) > 0 {
orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, actList.Data[0].BeginAt, actList.Data[0].EndAt)
if len(orderList) == 0 {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关订单!开始时间:[%v],结束时间:[%v]", actList.Data[0].BeginAt, actList.Data[0].EndAt))
}
} else {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("未查询到相关结算活动活动ID[%d]", actID))
}
} else {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate))
}
} else {
if fromDate != "" && toDate != "" {
fromDateParam = utils.Str2Time(fromDate)
toDateParam = utils.Str2Time(toDate)
//若未传入活动ID,且时间间隔大于10天则不允许查询
if math.Ceil(toDateParam.Sub(fromDateParam).Hours()/24) > 10 {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("查询间隔时间不允许大于10天时间范围[%v] 至 [%v]", fromDate, toDate))
}
orderList, _ = dao.QueryOrders(db, vendorOrderID, actID, vendorIDs, storeID, fromDateParam, toDateParam)
} else {
return "", model.ErrCodeGeneralFailed, errors.New(fmt.Sprintf("若不按活动查询则间隔时间必须完整!时间范围:[%v] 至 [%v]", fromDate, toDate))
}
}
if len(orderList) <= 0 {
return "", model.ErrCodePoint, errors.New(fmt.Sprintf("所选活动没有要更新结算价的订单!,vendorOrderID : %s, actID : %d, 时间范围:[%v] 至 [%v]", vendorOrderID, actID, fromDate, toDate))
}
task := tasksch.NewParallelTask("刷新历史订单结算价", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
order := batchItemList[0].(*model.GoodsOrder)
db := dao.GetDB()
updateSingleOrderEarningPrice(order, db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
for _, value := range order.Skus {
// storeID := 0
// if order.StoreID == 0 {
// storeID = order.JxStoreID
// } else {
// storeID = order.StoreID
// }
// result, _ := dao.GetEffectiveActStoreSkuInfo(db, 0, nil, 0, []int{storeID}, []int{value.SkuID}, order.OrderCreatedAt, order.OrderCreatedAt)
// if len(result) > 0 {
// if result[0].EarningPrice != 0 {
// var (
// storePayPercentage int
// )
// stores, _ := dao.GetStoreList(db, []int{order.StoreID}, nil, nil, nil, "")
// if len(stores) > 0 {
// storePayPercentage = stores[0].PayPercentage
// } else {
// storePayPercentage = 70
// }
// sku := value
// sku.Count = value.Count - 1
// value.Count = 1
// if value.ShopPrice < value.SalePrice {
// sku.EarningPrice = value.ShopPrice * int64(storePayPercentage)
// } else {
// sku.EarningPrice = value.SalePrice * int64(storePayPercentage)
// }
// order.Skus = append(order.Skus, sku)
// }
// }
if _, err = dao.UpdateEntity(db, value, "EarningPrice", "StoreSubID"); err != nil {
return nil, err
}
}
jxutils.RefreshOrderSkuRelated(order)
storeID := 0
if order.StoreID == 0 {
storeID = order.JxStoreID
} else {
storeID = order.StoreID
}
store, _ := dao.GetStoreDetail(db, storeID, order.VendorID, "")
payPercentage := store.PayPercentage
if payPercentage <= 50 {
order.NewEarningPrice = order.TotalShopMoney * utils.Float64TwoInt64(utils.Int2Float64(100)-utils.Int2Float64(payPercentage)/2) / 100
} else {
order.NewEarningPrice = order.EarningPrice
}
num, err := dao.UpdateEntity(db, order, "EarningPrice", "NewEarningPrice")
if err != nil {
return nil, err
}
dao.Commit(db, txDB)
retVal = []string{utils.Int64ToStr(num)}
return retVal, err
}, orderList)
tasksch.HandleTask(task, nil, true).Run()
if !isAsync {
resultNum, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = resultNum[0].(string)
}
} else {
hint = task.GetID()
}
return hint, model.ErrCodeSuccess, err
}
func RefreshOrdersWithoutJxStoreID(ctx *jxcontext.Context, fromDate, toDate string, isAsync, isContinueWhenError bool) (hint string, err error) {
var (
fromDateParam time.Time
toDateParam time.Time
)
if fromDate != "" {
fromDateParam = utils.Str2Time(fromDate)
}
if toDate != "" {
toDateParam = utils.Str2Time(toDate)
}
db := dao.GetDB()
task := tasksch.NewParallelTask("订单门店归属补漏", tasksch.NewParallelConfig().SetParallelCount(1), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
_, err = dao.UpdateOrdersWithoutJxStoreID(db, fromDateParam, toDateParam)
return retVal, err
}, []int{0})
tasksch.HandleTask(task, nil, true).Run()
if !isAsync {
_, err = task.GetResult(0)
hint = "1"
} else {
hint = task.GetID()
}
return hint, err
}
func GetOrdersSupplement(ctx *jxcontext.Context, storIDs, vendorIDs, statuss []int, vendorOrderID, fromTime, toTime string, stype, IsReverse, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
var (
db = dao.GetDB()
fromTimeP time.Time
toTimeP time.Time
)
if fromTime != "" {
fromTimeP = utils.Str2Time(fromTime)
}
if toTime != "" {
toTimeP = utils.Str2Time(toTime)
}
if fromTimeP.After(toTimeP) {
return nil, fmt.Errorf("时间范围不合法!开始时间:[%v],结束时间:[%v]", fromTimeP, toTimeP)
}
result, totalCount, err := dao.GetOrdersSupplement(db, storIDs, vendorIDs, statuss, vendorOrderID, fromTimeP, toTimeP, stype, IsReverse, offset, pageSize)
pageInfo = &model.PagedInfo{
Data: result,
TotalCount: totalCount,
}
return pageInfo, err
}
func AddUpdateOrdersSupplement(ctx *jxcontext.Context, ordersSupplement *model.OrderSupplementFee) (num int64, err error) {
var (
db = dao.GetDB()
id = ordersSupplement.ID
)
now := time.Now()
ordersSupplement.SupplementTime = &now
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
if id > 0 {
orderSupplementFee, _ := dao.GetOrdersSupplementNoPage(db, id, nil, nil, nil, "", utils.ZeroTimeValue, utils.ZeroTimeValue, 0, 0)
if len(orderSupplementFee) > 2 || len(orderSupplementFee) == 0 {
return 0, fmt.Errorf("查询扣款记录有误,请联系技术部!")
}
if orderSupplementFee[0].Status == 1 {
return 0, fmt.Errorf("已结账的扣款信息不允许修改门店ID:[%v],订单号:[%v]", ordersSupplement.StoreID, ordersSupplement.VendorOrderID)
}
ordersSupplement.UpdatedAt = time.Now()
ordersSupplement.LastOperator = ctx.GetUserName()
ordersSupplement.CreatedAt = orderSupplementFee[0].CreatedAt
if ordersSupplement.Status == -1 {
ordersSupplement.DeletedAt = time.Now()
} else {
ordersSupplement.DeletedAt = utils.DefaultTimeValue
}
num, err = dao.UpdateEntity(db, ordersSupplement)
} else {
dao.WrapAddIDCULDEntity(ordersSupplement, ctx.GetUserName())
err = dao.CreateEntity(db, ordersSupplement)
}
dao.Commit(db, txDB)
return num, err
}
func RefreshOrdersPriceInfo(ctx *jxcontext.Context, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
if utils.IsTimeZero(fromTime) {
return "", fmt.Errorf("必须指定起始时间")
}
if utils.IsTimeZero(toTime) {
toTime = fromTime
}
db := dao.GetDB()
orderList, err := dao.QueryOrders(db, "", 0, nil, 0, fromTime, toTime)
if err == nil && len(orderList) > 0 {
task := tasksch.NewParallelTask("RefreshOrdersPriceInfo", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
curOrder := batchItemList[0].(*model.GoodsOrder)
newOrder, err := FixedOrderManager.LoadOrder(curOrder.VendorOrderID, curOrder.VendorID)
if err == nil {
db := dao.GetDB()
if err = FixedOrderManager.updateOrderOtherInfo(newOrder, db); err == nil {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntity(db, newOrder); err != nil {
dao.Rollback(db, txDB)
return nil, err
}
for _, sku := range newOrder.Skus {
if _, err = dao.UpdateEntity(db, sku); err != nil {
dao.Rollback(db, txDB)
return nil, err
}
}
dao.Commit(db, txDB)
}
}
return retVal, err
}, orderList)
tasksch.HandleTask(task, nil, true).Run()
if isAsync {
hint = task.GetID()
} else {
_, err = task.GetResult(0)
hint = "1"
}
}
return hint, err
}
type GetOrderSimpleInfoResult struct {
VendorOrderID string `orm:"column(vendor_order_id)" json:"vendorOrderID"`
Status int `json:"status"`
WaybillVendorID int `orm:"column(waybill_vendor_id)" json:"waybillVendorID"`
CourierName string `json:"courierName"`
CourierMobile string `json:"courierMobile"`
Tel1 string `json:"tel1"`
MarketManPhone string `json:"marketManPhone"`
}
func GetOrderSimpleInfo(ctx *jxcontext.Context, vendorOrderID string) (getOrderSimpleInfoResult *GetOrderSimpleInfoResult, err error) {
db := dao.GetDB()
sql := `
SELECT a.vendor_order_id, a.status, a.waybill_vendor_id, c.courier_name, c.courier_mobile, b.tel1, b.market_man_phone
FROM goods_order a
JOIN store b ON IF(a.store_id <> '', a.store_id, a.jx_store_id) = b.id
LEFT JOIN waybill c ON c.vendor_order_id = a.vendor_order_id
WHERE (a.vendor_order_id LIKE ? OR a.consignee_mobile LIKE ?)
ORDER BY a.order_created_at DESC
LIMIT 1
`
sqlParams := []interface{}{
"%" + vendorOrderID + "%",
"%" + vendorOrderID + "%",
}
err = dao.GetRow(db, &getOrderSimpleInfoResult, sql, sqlParams)
if getOrderSimpleInfoResult == nil {
return getOrderSimpleInfoResult, fmt.Errorf("未查询到该订单的信息!")
}
return getOrderSimpleInfoResult, err
}
func setJdsOrderSeq(order *model.GoodsOrder) (err error) {
type tCount struct {
Count int `json:"count"`
}
var counts []*tCount
sql := `
SELECT count(*) count FROM goods_order WHERE store_id = ? AND order_created_at >= ? AND order_created_at <= ? AND vendor_id = ?
`
sqlParams := []interface{}{
order.StoreID, utils.Time2Date(time.Now()), utils.Time2Date(time.Now().AddDate(0, 0, 1)), order.VendorID,
}
err = dao.GetRows(dao.GetDB(), &counts, sql, sqlParams)
order.OrderSeq = counts[0].Count + 1
return err
}
func MergeJdsOrders(ctx *jxcontext.Context, vendorOrderIDs []string) (vendorOrderIDJds string, err error) {
var (
db = dao.GetDB()
orders []*model.GoodsOrder
orderSkus []*model.OrderSku
orderIDs []string
storeDuplicate = make(map[int]int)
storeID int
)
for _, vendorOrderID := range vendorOrderIDs {
order, _ := dao.GetSimpleOrder(db, vendorOrderID)
if err != nil || order == nil {
return "", fmt.Errorf("未查询到该订单!订单号:[%v]", vendorOrderID)
}
if order.Status >= model.OrderStatusDelivering && order.Status != model.OrderStatusCanceled {
return "", fmt.Errorf("暂不支持此状态的订单进行转移!订单号:[%v]", vendorOrderID)
}
if order.VendorID != model.VendorIDJDShop {
return "", fmt.Errorf("暂不支持非京狗的订单进行转移!订单号:[%v]", vendorOrderID)
}
storeDuplicate[jxutils.GetSaleStoreIDFromOrder(order)] = jxutils.GetSaleStoreIDFromOrder(order)
orders = append(orders, order)
//订单商品
skus, _ := dao.GetSimpleOrderSkus(db, order.VendorOrderID, nil)
orderSkus = append(orderSkus, skus...)
orderIDs = append(orderIDs, vendorOrderID)
}
if len(storeDuplicate) > 1 {
return "", fmt.Errorf("只能选择相同门店的订单进行合并!")
} else {
storeID = jxutils.GetSaleStoreIDFromOrder(orders[0])
}
for _, order := range orders {
var waybill *model.Waybill
//将订单和运单取消
waybills, err := dao.GetWaybills(db, order.VendorOrderID, nil)
if err != nil {
return "", err
}
if len(waybills) > 0 {
for _, v := range waybills {
if v.Status != model.WaybillStatusCanceled {
waybill = v
}
}
if waybill != nil {
if waybill.WaybillVendorID != model.VendorIDJDWL {
if handler := partner.GetDeliveryPlatformFromVendorID(waybill.WaybillVendorID); handler != nil {
err = handler.Handler.CancelWaybill(waybill, 0, "订单合并被取消")
}
}
}
}
if err = jdshop.ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, "订单合并被取消"); err != nil {
return "", err
}
}
//重新构建order的数据
storeMaps, err := dao.GetStoresMapList(db, []int{model.VendorIDJDShop}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
if err != nil || len(storeMaps) == 0 {
return "", fmt.Errorf("该门店未绑定京狗平台,请先绑定后再转移!门店:[%v]", storeID)
}
stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "")
var (
newEarningPrice int64
actualPrice int64
shopPrice int64
salePrice int64
totalShop int64
)
for _, v := range orders {
newEarningPrice += v.NewEarningPrice
actualPrice += v.ActualPayPrice
shopPrice += v.ShopPrice
salePrice += v.SalePrice
totalShop += v.TotalShopMoney
}
store := stores[0]
order := orders[0]
order.ID = 0
order.NewEarningPrice = newEarningPrice
order.ActualPayPrice = actualPrice
order.SalePrice = salePrice
order.ShopPrice = shopPrice
order.TotalShopMoney = totalShop
order.VendorOrderID = utils.Int64ToStr(utils.Str2Int64(orders[0].VendorOrderID2)*10000000) + utils.Int2Str(time.Now().Second())
if len(order.VendorOrderID) < 18 {
order.VendorOrderID = order.VendorOrderID + "0"
}
order.VendorOrderID2 = strings.Join(orderIDs, ",")
order.Status = model.OrderStatusNew
setJdsOrderSeq(order)
if order.BusinessType == model.BusinessTypeImmediate {
var (
opentime1 = jxutils.JxOperationTime2TimeByDate(store.OpenTime1, order.CreatedAt)
opentime2 = jxutils.JxOperationTime2TimeByDate(store.OpenTime2, order.CreatedAt)
closetime1 = jxutils.JxOperationTime2TimeByDate(store.CloseTime1, order.CreatedAt)
closetime2 = jxutils.JxOperationTime2TimeByDate(store.CloseTime2, order.CreatedAt)
orderCreatedAt = order.CreatedAt
)
if store.OpenTime1 == 0 || store.CloseTime1 == 0 {
return "", fmt.Errorf("该门店没有营业时间,不能接单!门店:[%v]", storeID)
}
if !(orderCreatedAt.Sub(opentime1) >= 0 && orderCreatedAt.Sub(closetime1) <= 0) {
if store.OpenTime2 != 0 && store.CloseTime2 != 0 {
if !(orderCreatedAt.Sub(opentime2) >= 0 && orderCreatedAt.Sub(closetime2) <= 0) {
if orderCreatedAt.Sub(opentime1) < 0 {
order.ExpectedDeliveredTime = opentime1
order.BusinessType = model.BusinessTypeDingshida
} else {
if orderCreatedAt.Sub(opentime2) < 0 {
order.ExpectedDeliveredTime = opentime2
} else {
order.ExpectedDeliveredTime = opentime1.AddDate(0, 0, 1)
}
order.BusinessType = model.BusinessTypeDingshida
}
}
} else {
if orderCreatedAt.Sub(opentime1) < 0 {
order.ExpectedDeliveredTime = opentime1
} else {
order.ExpectedDeliveredTime = opentime1.AddDate(0, 0, 1)
}
order.BusinessType = model.BusinessTypeDingshida
}
}
}
//结算类型
if store.PayPercentage < 50 {
order.EarningType = model.EarningTypePoints
} else {
order.EarningType = model.EarningTypeQuote
}
if storeID != model.JdShopMainStoreID {
order.DeliveryFlag = model.NO
}
//skus
for _, sku := range orderSkus {
sku.VendorOrderID = order.VendorOrderID
sku.ID = 0
}
order.Skus = orderSkus
err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
vendorOrderIDJds = order.VendorOrderID
return vendorOrderIDJds, err
}
func TransferJdsOrder(ctx *jxcontext.Context, vendorOrderID string, storeID int) (vendorOrderIDJds string, err error) {
var (
db = dao.GetDB()
waybill *model.Waybill
)
order, err := dao.GetSimpleOrder(db, vendorOrderID)
if err != nil || order == nil {
return "", fmt.Errorf("未查询到该订单!订单号:[%v]", vendorOrderID)
}
if order.Status >= model.OrderStatusDelivering && order.Status != model.OrderStatusCanceled {
return "", fmt.Errorf("暂不支持此状态的订单进行转移!")
}
if order.VendorID != model.VendorIDJDShop && order.VendorID != model.VendorIDJX {
return "", fmt.Errorf("暂不支持该平台的订单进行转移!")
}
skus, err := dao.GetSimpleOrderSkus(db, vendorOrderID, nil)
if err != nil || order == nil {
return "", fmt.Errorf("未查询到该订单商品!订单号:[%v]", vendorOrderID)
}
//将订单和运单取消
waybills, err := dao.GetWaybills(db, vendorOrderID, nil)
if err != nil {
return "", err
}
if len(waybills) > 0 {
for _, v := range waybills {
if v.Status != model.WaybillStatusCanceled {
waybill = v
}
}
if waybill != nil {
if handler := partner.GetDeliveryPlatformFromVendorID(waybill.WaybillVendorID); handler != nil {
err = handler.Handler.CancelWaybill(waybill, 0, "订单转移被取消")
}
}
}
//重新构建order的数据
storeMaps, err := dao.GetStoresMapList(db, []int{order.VendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", order.VendorOrgCode)
if err != nil || len(storeMaps) == 0 {
return "", fmt.Errorf("该门店未绑定平台,请先绑定后再转移!门店:[%v]", storeID)
}
stores, err := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "")
if len(storeMaps) > 0 && len(stores) > 0 {
if storeMaps[0].VendorStoreID == "" {
return "", fmt.Errorf("该门店未绑定平台,或绑定有误,请联系技术部!门店:[%v]", storeID)
}
order.StoreID = storeID
order.StoreName = stores[0].Name
order.VendorStoreID = storeMaps[0].VendorStoreID
//如果是立即达的订单,要判断一下下单时间是否在门店营业时间范围内
//若没有,则要把这个订单变成定时达,预计送达时间改为门店的营业时间
//如果门店没有营业时间,则直接报错
if order.BusinessType == model.BusinessTypeImmediate {
store := stores[0]
var (
opentime1 = jxutils.JxOperationTime2TimeByDate(store.OpenTime1, order.OrderCreatedAt)
opentime2 = jxutils.JxOperationTime2TimeByDate(store.OpenTime2, order.OrderCreatedAt)
closetime1 = jxutils.JxOperationTime2TimeByDate(store.CloseTime1, order.OrderCreatedAt)
closetime2 = jxutils.JxOperationTime2TimeByDate(store.CloseTime2, order.OrderCreatedAt)
orderCreatedAt = order.OrderCreatedAt
)
if store.OpenTime1 == 0 || store.CloseTime1 == 0 {
return "", fmt.Errorf("该门店没有营业时间,不能接单!门店:[%v]", storeID)
}
if closetime1.Sub(opentime1) <= time.Hour {
return "", fmt.Errorf("该门店营业时间间隔过小,请确认!门店:[%v]", storeID)
}
if !(orderCreatedAt.Sub(opentime1) >= 0 && orderCreatedAt.Sub(closetime1) <= 0) {
if store.OpenTime2 != 0 && store.CloseTime2 != 0 {
if !(orderCreatedAt.Sub(opentime2) >= 0 && orderCreatedAt.Sub(closetime2) <= 0) {
if orderCreatedAt.Sub(opentime1) < 0 {
order.ExpectedDeliveredTime = opentime1
order.BusinessType = model.BusinessTypeDingshida
} else {
if orderCreatedAt.Sub(opentime2) < 0 {
order.ExpectedDeliveredTime = opentime2
} else {
order.ExpectedDeliveredTime = opentime1.AddDate(0, 0, 1)
}
order.BusinessType = model.BusinessTypeDingshida
}
}
} else {
if orderCreatedAt.Sub(opentime1) < 0 {
order.ExpectedDeliveredTime = opentime1
} else {
order.ExpectedDeliveredTime = opentime1.AddDate(0, 0, 1)
}
order.BusinessType = model.BusinessTypeDingshida
}
}
}
//结算类型
if stores[0].PayPercentage < 50 {
order.EarningType = model.EarningTypePoints
} else {
order.EarningType = model.EarningTypeQuote
}
} else {
return "", fmt.Errorf("未查询到该门店对应的平台信息!门店:[%v]", order.StoreID)
}
if order.VendorID == model.VendorIDJDShop {
if len(order.VendorOrderID) > 12 {
var goodsOrders []*model.GoodsOrder
sql := `
SELECT * FROM goods_order WHERE vendor_order_id2 = ? ORDER BY vendor_order_id DESC
`
sqlParams := []interface{}{order.VendorOrderID2}
err = dao.GetRows(db, &goodsOrders, sql, sqlParams)
for _, order := range goodsOrders {
if order.Status != model.OrderStatusCanceled {
err = jdshop.ChangeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, "订单转移被取消")
}
}
// suffix := utils.Str2Int(goodsOrders[0].VendorOrderID[12:len(goodsOrders[0].VendorOrderID)])
// suffix++
if len(order.VendorOrderID2) > 18 {
order.VendorOrderID2 = order.VendorOrderID2[0:12]
}
order.VendorOrderID = utils.Int64ToStr(utils.Str2Int64(order.VendorOrderID2)*10000000) + utils.Int2Str(time.Now().Second())
if len(order.VendorOrderID) < 18 {
order.VendorOrderID = order.VendorOrderID + "0"
}
}
if storeID != model.JdShopMainStoreID {
order.DeliveryFlag = model.NO
}
err = jdshop.ChangeOrderStatus(vendorOrderID, model.OrderStatusCanceled, "订单转移被取消")
if err != nil {
return "", err
}
order.Status = model.OrderStatusNew
if order.ActualPayPrice == 0 {
msg, err := jdshop.GetJdsOrder(order.VendorOrderID2, order.VendorOrgCode)
if err == nil {
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)
}
}
} else {
order.VendorOrderID2 = order.VendorOrderID
order.VendorOrderID = utils.Int64ToStr(jxutils.GenOrderNo())
order.DeliveryFlag = model.NO
orderStatus := &model.OrderStatus{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDJX,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: vendorOrderID,
RefVendorID: model.VendorIDJX,
VendorStatus: utils.Int2Str(model.OrderStatusCanceled),
Status: model.OrderStatusCanceled,
StatusTime: time.Now(),
Remark: "订单转移被取消",
}
jxutils.CallMsgHandlerAsync(func() {
err = partner.CurOrderManager.OnOrderStatusChanged(order.VendorOrgCode, orderStatus)
}, jxutils.ComposeUniversalOrderID(vendorOrderID, model.VendorIDJX))
if err != nil {
return "", err
}
if order.VendorOrgCode == "1" {
order.Status = model.OrderStatusAccepted
} else {
order.Status = model.OrderStatusNew
}
}
for _, sku := range skus {
sku.VendorOrderID = order.VendorOrderID
sku.ID = 0
var storesSku *model.StoreSkuBind
sql := `
SELECT * FROM store_sku_bind WHERE deleted_at = ? AND store_id = ? AND jds_id = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, model.JdShopMainStoreID, sku.VendorSkuID}
if err = dao.GetRow(db, &storesSku, sql, sqlParams); err == nil && storesSku != nil {
if realStoresSkus, err := dao.GetStoresSkusInfo(db, []int{storeID}, []int{storesSku.SkuID}); err == nil && len(realStoresSkus) > 0 {
sku.ShopPrice = int64(realStoresSkus[0].Price)
}
}
order.Skus = append(order.Skus, sku)
}
setJdsOrderSeq(order)
err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
vendorOrderIDJds = order.VendorOrderID
return vendorOrderIDJds, err
}
func SendJdwlForJdsOrder(ctx *jxcontext.Context, vendorOrderID string) (err error) {
db := dao.GetDB()
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJDShop)
if order == nil || err != nil {
return fmt.Errorf("目前只支持京狗订单创建!")
}
if order.Status >= model.OrderStatusDelivering {
return fmt.Errorf("订单当前状态不支持创建!")
}
waybill := &model.Waybill{}
waybills, err := dao.GetWaybills(db, vendorOrderID, nil)
if err != nil {
return err
}
if len(waybills) > 0 {
for _, v := range waybills {
if v.Status != model.WaybillStatusCanceled {
waybill = v
}
}
if handler := partner.GetDeliveryPlatformFromVendorID(model.VendorIDJDWL); handler != nil {
err = handler.Handler.CancelWaybill(waybill, 0, "订单已发送其他物流")
}
if err != nil {
return err
}
}
var vendorWaybillID string
if order.StoreID == model.JdShopMainStoreID {
var (
goodsNos []string
prices []string
quantities []string
)
for _, v := range order.Skus {
skus, err := dao.GetSkus(db, []int{v.SkuID}, nil, nil, nil, nil)
if err != nil || len(skus) == 0 {
continue
}
goodsNos = append(goodsNos, skus[0].EclpID)
prices = append(prices, "0")
quantities = append(quantities, utils.Int2Str(v.Count))
}
eclpSoNo, err := api.JdEclpAPI.AddOrder(&jdeclpapi.AddOrderParam{
IsvUUID: order.VendorOrderID,
IsvSource: jdeclpapi.IsvSource,
ShopNo: jdeclpapi.ShopNo,
DepartmentNo: jdeclpapi.DepartmentNo,
WarehouseNo: jdeclpapi.WarehouseNo,
ShipperNo: jdeclpapi.ShipperNo,
SalesPlatformOrderNo: order.VendorOrderID,
SalePlatformSource: jdeclpapi.SalePlatformSource,
ConsigneeName: order.ConsigneeName,
ConsigneeMobile: order.ConsigneeMobile,
ConsigneeAddress: order.ConsigneeAddress,
OrderMark: jdeclpapi.OrderMark,
GoodsNo: strings.Join(goodsNos, ","),
Price: strings.Join(prices, ","),
Quantity: strings.Join(quantities, ","),
})
waybill := &model.Waybill{
VendorOrderID: order.VendorOrderID,
OrderVendorID: model.VendorIDJX,
VendorWaybillID: eclpSoNo,
WaybillVendorID: model.VendorIDJDWL,
Status: model.WaybillStatusDelivering,
WaybillCreatedAt: time.Now(),
StatusTime: time.Now(),
WaybillFinishedAt: utils.DefaultTimeValue,
DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled,
}
dao.CreateEntity(db, waybill)
if err != nil {
return err
}
order.EclpOutID = eclpSoNo
dao.UpdateEntity(db, order, "EclpOutID")
vendorWaybillID = eclpSoNo
} else {
// if handler := partner.GetDeliveryPlatformFromVendorID(model.VendorIDJDWL); handler != nil {
// waybill2, err := handler.Handler.CreateWaybill(order, 0)
// if err != nil {
// return err
// }
// vendorWaybillID = waybill2.VendorWaybillID
// }
}
jdshop.CurPurchaseHandler.OrderExport(ctx, vendorOrderID, vendorWaybillID, false)
return err
}
func AdjustJdsOrderSimple(ctx *jxcontext.Context, vendorOrderID string, skuID int) (err error) {
var (
db = dao.GetDB()
)
orderSkus, err := dao.GetSimpleOrderSkus(db, vendorOrderID, []int{skuID})
order, err := dao.GetSimpleOrder(db, vendorOrderID)
//如果不是商城模板店
if jxutils.GetSaleStoreIDFromOrder(order) != model.JdShopMainStoreID {
return fmt.Errorf("目前只支持商城模板店的简单售前删除!")
}
orderSkus2, err := dao.GetSimpleOrderSkus(db, vendorOrderID, nil)
if len(orderSkus2) == 1 {
return fmt.Errorf("这一单只剩这最后一个商品了,不允许删除!")
}
if len(orderSkus) == 0 {
return fmt.Errorf("未查询到该订单商品!")
}
if order.Status > model.OrderStatusAccepted {
return fmt.Errorf("目前只支持待拣货状态前的订单售前调整!")
}
orderSku := orderSkus[0]
if orderSku.Count > 1 {
orderSku.Count--
_, err = dao.UpdateEntity(db, orderSku, "Count")
} else {
_, err = dao.DeleteEntity(db, orderSku)
}
order.AdjustCount++
order.ActualPayPrice = order.ActualPayPrice - orderSku.SalePrice
order.TotalShopMoney = int64(float64(order.ActualPayPrice) * jdshopapi.JdsPayPercentage)
dao.UpdateEntity(db, order, "AdjustCount", "TotalShopMoney")
return err
}
func UpdateWaybillDesiredFee(ctx *jxcontext.Context, vendorOrderID string, desiredFee int) (err error) {
var (
db = dao.GetDB()
)
order, _ := dao.GetSimpleOrder(db, vendorOrderID)
if order == nil {
return fmt.Errorf("未找到该订单orderID: %v", vendorOrderID)
}
bill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
if bill == nil {
waybill := &model.Waybill{
VendorOrderID: order.VendorOrderID,
OrderVendorID: order.VendorID,
VendorWaybillID: utils.Int64ToStr(GenOrderNo(ctx)),
WaybillVendorID: -1,
Status: model.WaybillStatusDelivered,
WaybillCreatedAt: time.Now(),
StatusTime: time.Now(),
WaybillFinishedAt: utils.DefaultTimeValue,
DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled,
DesiredFee: int64(desiredFee),
}
dao.CreateEntity(db, waybill)
order.VendorWaybillID = waybill.VendorWaybillID
dao.UpdateEntity(db, order, "VendorWaybillID")
} else {
bill.DesiredFee = int64(desiredFee)
_, err = dao.UpdateEntity(db, bill, "DesiredFee")
if order.EarningType == model.EarningTypePoints {
order.NewEarningPrice = order.NewEarningPrice - int64(desiredFee)
_, err = dao.UpdateEntity(db, order, "NewEarningPrice")
}
}
return err
}
func AcceptOrRefuseOrder(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isAccept bool) (err error) {
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
handler := partner.GetPurchaseOrderHandlerFromVendorID(vendorID)
err = handler.AcceptOrRefuseOrder(order, isAccept, ctx.GetUserName())
if err == nil && isAccept && vendorID == model.VendorIDEBAI {
// netprinter.PrintOrderByOrder(jxcontext.AdminCtx, order)
// smsmsg.NotifyNewOrder(order)
// smsmsg.NotifyNewUserOrder(order)
// weixinmsg.NotifyNewOrder(order)
// msghub.OnNewOrder(order)
}
return err
}
func GenOrderNo(ctx *jxcontext.Context) (orderNo int64) {
const prefix = 88
const randPartNum = 1000
orderNo = time.Now().Unix() - orderNoBeginTimestamp
// fmt.Println(orderNo)
orderNo = orderNo * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
orderNo += int64(randPart % randPartNum)
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
return orderNo
}
func RefreshJdsOrderConsigneeInfo(ctx *jxcontext.Context, vendorOrderID string) (err error) {
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJDShop)
if order == nil {
return fmt.Errorf("未查询到此京东商城订单!")
}
waybill, err := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
if waybill != nil {
return fmt.Errorf("已经创建了三方运单不允许修改联系人信息!")
}
jdsOrder, err := jdshop.GetJdsOrder(order.VendorOrderID2, order.VendorOrgCode)
if err != nil {
return err
}
if jdsOrder == nil {
return fmt.Errorf("未查询到对应的京东商城订单!")
}
order.ConsigneeAddress = jdshop.Decrypt(jdsOrder.ConsigneeInfo.FullAddress, order.VendorOrgCode)
order.ConsigneeName = jdshop.Decrypt(jdsOrder.ConsigneeInfo.Fullname, order.VendorOrgCode)
order.ConsigneeMobile = jdshop.Decrypt(jdsOrder.ConsigneeInfo.Mobile, order.VendorOrgCode)
order.ConsigneeMobile2 = jdshop.Decrypt(jdsOrder.ConsigneeInfo.Telephone, order.VendorOrgCode)
order.BuyerComment = jdsOrder.OrderRemark
if order.ConsigneeAddress != "" {
lng, lat, _ := api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "")
order.ConsigneeLng = jxutils.StandardCoordinate2Int(lng)
order.ConsigneeLat = jxutils.StandardCoordinate2Int(lat)
}
partner.CurOrderManager.UpdateOrderFields(order, []string{"ConsigneeAddress", "ConsigneeName", "ConsigneeMobile", "ConsigneeMobile2", "BuyerComment", "ConsigneeLng", "ConsigneeLat"})
return err
}
func UpdateOrderInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID int, payload map[string]interface{}) (num int64, err error) {
var (
db = dao.GetDB()
jxSubsidyMoney int64
)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if payload["consigneeLng"] != nil || payload["consigneeLat"] != nil {
payload["consigneeLng"] = jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["consigneeLng"], 0.0))
payload["consigneeLat"] = jxutils.StandardCoordinate2Int(utils.Interface2Float64WithDefault(payload["consigneeLat"], 0.0))
}
if payload["expectedDeliveredTime"] != nil {
payload["expectedDeliveredTime"] = utils.Str2Time(payload["expectedDeliveredTime"].(string))
}
if payload["jxSubsidyMoney"] != nil {
jxSubsidyMoney = utils.Interface2Int64WithDefault(payload["jxSubsidyMoney"], 0)
//if order.EarningType == model.EarningTypeQuote {
// payload["earningPrice"] = order.EarningPrice - order.JxSubsidyMoney + jxSubsidyMoney
//}
}
valid := dao.StrictMakeMapByStructObject(payload, order, ctx.GetUserName())
if len(valid) > 0 {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if num, err = dao.UpdateEntityByKV(db, order, valid, nil); err != nil {
dao.Rollback(db, txDB)
return 0, err
}
dao.Commit(db, txDB)
}
if payload["jxSubsidyMoney"] != nil {
var (
userIDs []string
)
storeDetail, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode)
if storeDetail != nil && storeDetail.Tel1 != "" {
user, _ := dao.GetUserByID(db, "mobile", storeDetail.Tel1)
if user != nil {
userIDs = append(userIDs, user.UserID)
}
if storeDetail.Tel2 != "" {
user2, _ := dao.GetUserByID(db, "mobile", storeDetail.Tel2)
if user2 != nil {
userIDs = append(userIDs, user2.UserID)
}
}
}
weixinmsg.SendUserMessage(jxcontext.AdminCtx, "订单补偿", fmt.Sprintf("您收到了%v元的订单补偿订单号[%v]", jxutils.IntPrice2Standard(jxSubsidyMoney), order.VendorOrderID), userIDs, true, true)
}
return num, err
}
func RefreshOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID, skuID int) (num int64, err error) {
var (
db = dao.GetDB()
shopPrice, earningPrice int64
)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if order.EarningType != model.EarningTypeQuote {
return 0, fmt.Errorf("目前只支持报价订单有此操作!")
}
updateOrderSku := func(v *model.OrderSku, skuID2 int) (err error) {
storeSkus, _ := dao.GetStoresSkusInfo(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, []int{skuID2})
if len(storeSkus) == 0 {
return fmt.Errorf("未找到此门店商品!")
}
storeSku := storeSkus[0]
//if v.ShopPrice == v.EarningPrice {
if beego.BConfig.RunMode == "jxgy" {
if v.SalePrice > v.ShopPrice {
v.EarningPrice = int64(math.Round(float64(storeSku.Price) * float64(order.OrderPayPercentage) / 100))
} else {
v.EarningPrice = int64(math.Round(float64(v.SalePrice) * float64(order.OrderPayPercentage) / 100))
}
} else {
v.EarningPrice = int64(math.Round(float64(storeSku.Price) * float64(order.OrderPayPercentage) / 100))
}
//}
v.ShopPrice = int64(storeSku.Price)
dao.UpdateEntity(db, v, "ShopPrice", "EarningPrice")
return err
}
for _, v := range order.Skus {
if v.SkuID == 0 {
if v.JxSkuID == skuID {
err = updateOrderSku(v, skuID)
}
} else {
if v.SkuID == skuID {
err = updateOrderSku(v, skuID)
}
}
}
if err != nil {
return 0, err
}
for _, v := range order.Skus {
shopPrice += v.ShopPrice * int64(v.Count)
earningPrice += v.EarningPrice * int64(v.Count)
}
order.ShopPrice = shopPrice
order.EarningPrice = earningPrice
num, err = dao.UpdateEntity(db, order, "ShopPrice", "EarningPrice")
return num, err
}
func UpdateJdsOrdersStatus(ctx *jxcontext.Context, orderCreatedStart, orderCreatedEnd time.Time) (err error) {
var (
pageSize = 20
orderIDs []int64
)
orderResult, err := jdshop.CurPurchaseHandler.GetJdsOrders(ctx, utils.Time2Str(orderCreatedStart), utils.Time2Str(orderCreatedEnd), 1, pageSize)
if orderResult.TotalCount > pageSize {
for pageNO := 1; pageNO < orderResult.TotalCount/pageSize+1; pageNO++ {
orderResult2, _ := jdshop.CurPurchaseHandler.GetJdsOrders(ctx, utils.Time2Str(orderCreatedStart), utils.Time2Str(orderCreatedEnd), pageNO, pageSize)
for _, order := range orderResult2.OrderList {
if order.OrderStatus == jdshopapi.OrderStatusCancelm2 {
orderIDs = append(orderIDs, order.OrderID)
}
}
}
}
for _, orderID := range orderIDs {
var goodsOrder *model.GoodsOrder
sql := `
SELECT * FROM goods_order WHERE vendor_order_id2 = ?
`
sqlParams := []interface{}{orderID}
if dao.GetRow(dao.GetDB(), &goodsOrder, sql, sqlParams); goodsOrder != nil {
if goodsOrder.Status != model.OrderStatusCanceled {
goodsOrder.Status = model.OrderStatusCanceled
dao.UpdateEntity(dao.GetDB(), goodsOrder, "Status")
}
}
}
return err
}
func SaveJdsOrders(ctx *jxcontext.Context, orderCreatedStart, orderCreatedEnd time.Time) (err error) {
var (
pageSize = 10
)
orderResult, err := jdshop.CurPurchaseHandler.GetJdsOrders(ctx, utils.Time2Str(orderCreatedStart), utils.Time2Str(orderCreatedEnd), 1, pageSize)
if err != nil {
noticeMsg := fmt.Sprintf("京东商城保存订单出错多半是cookie过期了,err :[%v]", err)
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "BF09DB25350611EB89AC525400E86DC0", "cookie", noticeMsg)
return err
}
orders, err := result2Orders(ctx, orderResult)
if orderResult.TotalCount > pageSize {
for pageNO := 2; pageNO <= orderResult.TotalCount/pageSize+1; pageNO++ {
orderResult, _ := jdshop.CurPurchaseHandler.GetJdsOrders(ctx, utils.Time2Str(orderCreatedStart), utils.Time2Str(orderCreatedEnd), pageNO, pageSize)
orders2, _ := result2Orders(ctx, orderResult)
orders = append(orders, orders2...)
}
}
for _, order := range orders {
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 += " 此订单地址有问题,需要矫正坐标!"
}
var role = autils.NewRole("jdshop", 0)
userIDList, _ := api2.RoleMan.GetRoleUserList(role)
for _, v := range userIDList {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, v, "京东商城来新订单了!", noticeMsg)
}
}
return err
}
func result2Orders(ctx *jxcontext.Context, result *jdshopapi.AllOrdersResult) (orders []*model.GoodsOrder, err error) {
var (
db = dao.GetDB()
)
for _, jdsOrder := range result.OrderList {
//等待付款的排除
//完成 19
//配送中 52
//待配送 51
//待接单 50
if jdsOrder.OrderStatus == jdshopapi.JdsOrderStatusWaittingPay || jdsOrder.OrderStatus == jdshopapi.JdsOrderStatusWaittingPayDel {
continue
}
//有可能是库里已经有这个订单了
orderE, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(jdsOrder.OrderID)+"00000001", model.VendorIDJDShop)
if orderE != nil {
continue
}
orderDetail, err := jdshop.GetAPI("2").OrderDetail(utils.Int64ToStr(jdsOrder.OrderID))
if err != nil {
continue
}
order := &model.GoodsOrder{
VendorOrderID2: utils.Int64ToStr(jdsOrder.OrderID),
VendorOrderID: utils.Int64ToStr(jdsOrder.OrderID) + "00000001",
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)),
StoreName: jdsOrder.StoreName,
OrderCreatedAt: utils.Str2Time(jdsOrder.OrderCreateTime + ":00"),
ConsigneeAddress: orderDetail.ConsigneeAddress,
ConsigneeName: orderDetail.ConsigneeName,
ActualPayPrice: orderDetail.ActualPayPrice,
Status: model.OrderStatusNew,
TotalShopMoney: utils.Float64TwoInt64(math.Round(utils.Int64ToFloat64(orderDetail.ActualPayPrice) * jdshopapi.JdsPayPercentage)),
DeliveryType: model.OrderDeliveryTypeStoreSelf,
StatusTime: utils.Str2Time(jdsOrder.OrderCreateTime + ":00"),
OrderSeq: 0,
VendorOrgCode: "2",
}
//获取真实手机号
fakeMobile, err := jdshop.GetAPI("2").PhoneSensltiveInfo(order.VendorOrderID2, orderDetail.MobileKey)
if err != nil {
continue
} else {
order.ConsigneeMobile = jxutils.DecryptDESECB([]byte(fakeMobile), []byte(jdshopapi.JdsMobileKey))
}
if order.TotalShopMoney < 100 {
order.TotalShopMoney = 100
}
//如果是暂停,表示是预订单
if jdsOrder.OrderStatus == jdshopapi.JdsOrderStatusPause {
order.BusinessType = model.BusinessTypeDingshida
order.ExpectedDeliveredTime = utils.Str2Time(orderDetail.ExpectedDeliveredTime)
order.PickDeadline = order.ExpectedDeliveredTime.Add(-time.Hour)
} else if jdsOrder.OrderStatus != jdshopapi.JdsOrderStatusWaittingPayDel {
order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour)
order.BusinessType = model.BusinessTypeImmediate
}
//表示可能是定时达的
if orderDetail.ExpectedDeliveredTime != "" {
order.BusinessType = model.BusinessTypeDingshida
order.ExpectedDeliveredTime = utils.Str2Time(orderDetail.ExpectedDeliveredTime)
order.PickDeadline = order.ExpectedDeliveredTime.Add(-time.Hour)
}
setJdsOrderSeq(order)
for _, v := range jdsOrder.OrderItems {
sku := &model.OrderSku{
VendorID: model.VendorIDJDShop,
VendorOrderID: order.VendorOrderID,
Count: v.SkuNum,
VendorSkuID: utils.Int64ToStr(v.SkuID),
SkuName: v.SkuName,
VendorPrice: jxutils.StandardPrice2Int(v.JdPrice),
SalePrice: jxutils.StandardPrice2Int(v.JdPrice),
}
var storeSku *model.StoreSkuBind
sql := `
SELECT * FROM store_sku_bind WHERE store_id = ? AND jds_id = ? AND deleted_at = ?
`
sqlParams := []interface{}{model.JdShopMainStoreID, v.SkuID, utils.DefaultTimeValue}
err = dao.GetRow(dao.GetDB(), &storeSku, sql, sqlParams)
if storeSku != nil {
sku.SkuID = storeSku.SkuID
}
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(v.SkuName)
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit)
order.Skus = append(order.Skus, sku)
}
var store *dao.StoreDetail
if jdsOrder.MdbStoreID != 0 {
if store, err = dao.GetStoreDetailByVendorStoreID(db, utils.Int64ToStr(jdsOrder.MdbStoreID), model.VendorIDJDShop, "2"); store != nil && err == nil {
order.StoreID = store.ID
order.JxStoreID = store.ID
order.StoreName = store.Name
order.VendorStoreID = utils.Int64ToStr(jdsOrder.MdbStoreID)
//结算类型
if store.PayPercentage < 50 {
order.EarningType = model.EarningTypePoints
} else {
order.EarningType = model.EarningTypeQuote
}
var (
shopPriceSum int
)
for _, sku := range order.Skus {
storeSkuList, _ := dao.GetStoresSkusInfo(db, []int{order.StoreID}, []int{sku.SkuID})
if len(storeSkuList) > 0 {
shopPriceSum += storeSkuList[0].Price * sku.Count
sku.ShopPrice = int64(storeSkuList[0].Price)
} else {
shopPriceSum += int(sku.SalePrice) * 70 / 100
}
}
if order.EarningType == model.EarningTypeQuote && shopPriceSum+700 > int(order.TotalShopMoney) {
buildOrderTo102919(order)
}
if order.ConsigneeAddress != "" {
var (
cityCode = 0
lng, lat, lng2, lat2 float64
)
if shopDetail, _ := api.JdShopAPI.ShopDetail(int(jdsOrder.MdbStoreID)); shopDetail != nil {
if shopDetail.AddCode2 != 0 {
var place = &model.Place{}
sql1 := "SELECT * FROM place WHERE jds_code = ?"
sqlParams1 := []interface{}{shopDetail.AddCode2}
if err2 := dao.GetRow(db, &place, sql1, sqlParams1); err2 == nil && place != nil {
cityCode = place.Code
} else {
sql2 := "SELECT * FROM place WHERE jd_code = ?"
sqlParams2 := []interface{}{shopDetail.AddCode2}
if err3 := dao.GetRow(db, &place, sql2, sqlParams2); err3 == nil && place != nil {
cityCode = place.Code
}
}
}
}
//if cityCode != 0 {
lng, lat, _ = api.AutonaviAPI.GetCoordinateFromAddressByPage(order.ConsigneeAddress, cityCode)
//} else {
lng2, lat2, _ = api.AutonaviAPI.GetCoordinateFromAddress(order.ConsigneeAddress, "")
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)
}
//}
distance := jxutils.EarthDistance(lng, lat, lng2, lat2)
if distance > 1 {
order.OrderType = model.OrderTypeAddressErr
order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled
}
}
} else {
continue
}
} else {
buildOrderTo102919(order)
}
//TODO 2021-10-11 取消限额
//if order.ActualPayPrice > 300000 {
// buildOrderTo102919(order)
// globals.SugarLogger.Debugf("resultjdsOrders return 8")
//}
if store != nil {
distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(order.ConsigneeLng), jxutils.IntCoordinate2Standard(order.ConsigneeLat), jxutils.IntCoordinate2Standard(store.Lng), jxutils.IntCoordinate2Standard(store.Lat))
if distance > 4 {
buildOrderTo102919(order)
}
if store.Status != model.StoreStatusOpened && store.Status != model.StoreStatusHaveRest {
buildOrderTo102919(order)
}
}
orders = append(orders, order)
}
return orders, err
}
func buildOrderTo102919(order *model.GoodsOrder) {
// if order.VendorOrgCode == "1" {
// order.StoreID = 102919
// order.JxStoreID = 102919
// order.StoreName = "商城模板(成都发货)"
// order.VendorStoreID = model.JdShopMainVendorStoreID
// } else {
order.StoreID = model.JdShopMainStoreID
order.JxStoreID = model.JdShopMainStoreID
order.StoreName = "商城模板店2"
order.VendorStoreID = model.JdShopMainVendorStoreID
// }
order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled
}
func RefreshJdAfsOrderTotalShopMoney() {
var (
db = dao.GetDB()
afsOrders []*model.AfsOrder
)
sql := `
SELECT * FROM afs_order WHERE afs_created_at > ? AND vendor_id = ? AND status = ? AND afs_total_shop_money = 0
`
sqlParams := []interface{}{time.Now().AddDate(0, 0, -3), model.VendorIDJD, model.AfsOrderStatusFinished}
dao.GetRows(db, &afsOrders, sql, sqlParams)
for _, v := range afsOrders {
//排除物竞天择的
if order, _ := partner.CurOrderManager.LoadOrder(v.VendorOrderID, v.VendorID); !strings.Contains(order.BuyerComment, "JD") {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(v.VendorID); handler != nil {
if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, v.VendorOrderID, v.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
v.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
}
}
dao.UpdateEntity(db, v, "AfsTotalShopMoney")
}
}
}
func DelOrderSkuInfo(ctx *jxcontext.Context, vendorOrderID string, vendorID, id int) (num int64, err error) {
var (
db = dao.GetDB()
shopPrice, earningPrice int64
orderSkus []*model.OrderSku
)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if order.EarningType != model.EarningTypeQuote {
return 0, fmt.Errorf("目前只支持报价订单有此操作!")
}
sql := `
SELECT * FROM order_sku WHERE vendor_order_id = ? ORDER BY id
`
sqlParams := []interface{}{vendorOrderID}
dao.GetRows(db, &orderSkus, sql, sqlParams)
if len(orderSkus) < 5 {
return 0, fmt.Errorf("商品数小于5不允许删除")
}
if orderSkus[0].ID == int64(id) {
//if orderSkus[0].JxSkuID == skuID {
return 0, fmt.Errorf("不允许删第一个商品!")
//}
//} else {
// if orderSkus[0].SkuID == skuID {
// return 0, fmt.Errorf("不允许删第一个商品!")
// }
//}
}
for _, v := range order.Skus {
if v.ID == int64(id) {
sql := `
DELETE FROM order_sku WHERE id = ?
`
sqlParams := []interface{}{v.ID}
dao.ExecuteSQL(db, sql, sqlParams)
shopPrice = v.ShopPrice * int64(v.Count)
earningPrice = v.EarningPrice * int64(v.Count)
}
//if v.SkuID == 0 {
// if v.JxSkuID == skuID {
// }
//} else {
// if v.SkuID == skuID {
// sql := `
// DELETE FROM order_sku WHERE id = ?
// `
// sqlParams := []interface{}{v.ID}
// dao.ExecuteSQL(db, sql, sqlParams)
// shopPrice = v.ShopPrice * int64(v.Count)
// earningPrice = v.EarningPrice * int64(v.Count)
// }
//}
}
order.ShopPrice -= shopPrice
order.EarningPrice -= earningPrice
num, err = dao.UpdateEntity(db, order, "ShopPrice", "EarningPrice")
return num, err
}
func BuildFakeMatterOrder() {
var (
db = dao.GetDB()
)
storeMaps, _ := dao.GetStoresMapList(db, []int{model.VendorIDJX}, []int{668202}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
task := tasksch.NewParallelTask("BuildFakeMatterOrder", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, storeMap.VendorID, "")
vendorOrderID := utils.Int64ToStr(jxutils.GenOrderNo())
order := &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDJX,
VendorStoreID: utils.Int2Str(model.MatterStoreID),
StoreID: model.MatterStoreID,
JxStoreID: model.MatterStoreID,
StoreName: "物料申请",
ShopPrice: 2000,
SalePrice: 2000,
Weight: 1460,
ConsigneeName: storeDetail.Name,
ConsigneeMobile: storeDetail.Tel1,
ConsigneeAddress: storeDetail.Address,
ConsigneeLng: storeDetail.Lng,
ConsigneeLat: storeDetail.Lat,
SkuCount: 1,
GoodsCount: 1,
Status: model.OrderStatusFinished,
VendorStatus: utils.Int2Str(model.OrderStatusFinished),
ExpectedDeliveredTime: time.Now().Add(time.Hour),
WaybillVendorID: 401,
OrderCreatedAt: time.Now(),
OrderFinishedAt: time.Now().Add(time.Hour * 2),
ActualPayPrice: 501,
StatusTime: time.Now().Add(time.Hour),
BusinessType: 1,
VendorPrice: 3100,
DeliveryType: "store",
TotalShopMoney: 471,
EarningPrice: 2000,
DeliveryFlag: 1,
FromStoreID: storeDetail.ID,
EarningType: 1,
OrderType: 1,
OrderPayPercentage: 100,
}
order.CreatedAt = time.Now()
order.UpdatedAt = time.Now()
orderSku := &model.OrderSku{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDJX,
Count: 1,
VendorSkuID: "6039382",
SkuID: 6039382,
JxSkuID: 6039382,
SkuName: "背心袋(京西菜市)1.46kg/件(100个)",
ShopPrice: 2000,
SalePrice: 1,
Weight: 1460,
OrderCreatedAt: time.Now(),
EarningPrice: 2000,
VendorPrice: 3100,
}
dao.CreateEntity(db, order)
dao.CreateEntity(db, orderSku)
statusList := []int{2, 5, 15, 20, 110}
for _, v := range statusList {
orderStatus := &model.OrderStatus{
VendorOrderID: vendorOrderID,
VendorID: model.VendorIDJX,
OrderType: 1,
RefVendorOrderID: vendorOrderID,
RefVendorID: model.VendorIDJX,
Status: v,
VendorStatus: utils.Int2Str(v),
StatusTime: time.Now().Add(time.Minute * time.Duration(v)),
}
orderStatus.CreatedAt = time.Now()
orderStatus.UpdatedAt = time.Now()
dao.CreateEntity(db, orderStatus)
}
return retVal, err
}, storeMaps)
tasksch.HandleTask(task, nil, true).Run()
task.GetResult(0)
}
func ExportOrderWithSku(ctx *jxcontext.Context, orders []*model.GoodsOrderExt) (downloadURL string, err error) {
type ExportOrderWithSkuExt struct {
StoreName string `json:"门店名"`
VendorName string `json:"平台名"`
OrderCreatedAt string `json:"下单时间"`
VendorOrderID string `orm:"column(vendor_order_id)" json:"订单号"`
EarningPrice float64 `json:"订单结算"`
SkuName string `json:"商品名"`
CategoryNameFst string `json:"一级分类名"`
CategoryNameSnd string `json:"二级分类名"`
ShopPrice float64 `json:"商品报价"`
Count int `json:"数量"`
EarningPriceSku float64 `json:"商品结算"`
Upc string `json:"条形码"`
IsAfs int `json:"是否已售后"`
AfsCount int `json:"售后数量"`
}
var (
db = dao.GetDB()
excelTitle = []string{
"门店名",
"平台名",
"下单时间",
"订单号",
"订单结算",
"商品名",
"一级分类名",
"二级分类名",
"商品报价",
"数量",
"商品结算",
"条形码",
"是否已售后",
"售后数量",
}
vendorOrderIDs []string
results []*ExportOrderWithSkuExt
)
for _, v := range orders {
vendorOrderIDs = append(vendorOrderIDs, v.VendorOrderID)
}
sql := `
SELECT IF(a.vendor_id = 0, '京东',IF(a.vendor_id = 1, '美团',IF(a.vendor_id = 3, '饿百','不明'))) vendor_name,
DATE_FORMAT(a.order_created_at,'%Y-%m-%d %h:%i:%s') order_created_at,
a.vendor_order_id, IF(b.earning_type = 1, b.earning_price, b.total_shop_money * (100-b.order_pay_percentage/2)/100) /100 earning_price,
a.shop_price /100 shop_price, a.count, IF(b.earning_type = 1, a.earning_price, 0) /100 earning_price_sku, a.sku_name, d.upc,
e.name store_name, f.name category_name_snd, g.name category_name_fst, IF(h.id IS NULL, 0, 1) is_afs, h.count afs_count
FROM order_sku a
LEFT JOIN goods_order b ON a.vendor_order_id = b.vendor_order_id
LEFT JOIN sku c ON c.id = a.sku_id
LEFT JOIN sku_name d ON d.id = c.name_id
LEFT JOIN store e ON IF(b.jx_store_id = 0, b.store_id, b.jx_store_id) = e.id
LEFT JOIN sku_category f ON f.id = d.category_id
LEFT JOIN sku_category g ON g.id = f.parent_id
LEFT JOIN order_sku_financial h ON h.vendor_order_id = a.vendor_order_id AND h.sku_id = a.sku_id AND is_afs_order = ?
WHERE a.vendor_order_id IN (` + dao.GenQuestionMarks(len(vendorOrderIDs)) + `)
ORDER BY store_name, order_created_at DESC
`
sqlParams := []interface{}{model.YES, vendorOrderIDs}
err = dao.GetRows(db, &results, sql, sqlParams)
if err != nil {
return "", err
}
var sheetList []*excel.Obj2ExcelSheetConfig
excelConf := &excel.Obj2ExcelSheetConfig{
Title: "sheet1",
Data: results,
CaptionList: excelTitle,
}
sheetList = append(sheetList, excelConf)
downloadURL, _, err = jxutils.UploadExeclAndPushMsg(sheetList, "订单导出")
baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess downloadURL: [%v]", downloadURL)
return downloadURL, err
}
// UpdateTiktokShopTotalMoney 定时任务更新抖店订单的平台结算
func UpdateTiktokShopTotalMoney() {
db := dao.GetDB()
var goodsOrders []*model.GoodsOrder
sql := `SELECT g.* FROM goods_order g WHERE g.order_created_at >= ? AND g.status = ? AND g.vendor_id = ? AND total_shop_money = ? ORDER BY g.order_created_at desc`
orderCreateTime := time.Now().AddDate(0, 0, -15)
param := []interface{}{orderCreateTime, model.OrderStatusFinished, model.VendorIDDD, model.NO}
if err := dao.GetRows(db, &goodsOrders, sql, param...); err != nil {
globals.SugarLogger.Debugf("Update GoodsOrder Total shop money err %s", err)
return
}
nextStartIndex := ""
for _, v := range goodsOrders {
orderDetail, err := tiktok_store.GetOrderDetail(v.VendorOrgCode, v.VendorOrderID)
if err != nil {
globals.SugarLogger.Errorf("定时任务:查询订单详情错误,更新订单结算信息,[%s]", err)
continue
}
childrenOrderList := make([]string, 0, 0)
for _, v := range orderDetail.SkuOrderList {
childrenOrderList = append(childrenOrderList, v.OrderId)
}
totalShopMoney, next, err := tiktok_store.GetOrderTotalShopMoney(v.VendorOrgCode, strings.Join(childrenOrderList, ","), nextStartIndex)
if err != nil {
globals.SugarLogger.Errorf("获取平台订单异常 : %s", err)
continue
}
nextStartIndex = next
v.TotalShopMoney = totalShopMoney
if v.EarningType == model.EarningTypePoints {
waybill, _ := partner.CurOrderManager.LoadWaybill(v.VendorWaybillID, v.WaybillVendorID)
// store, _ := c.LoadStoreDetail(jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
if waybill == nil {
if (v.NewEarningPrice == 0 || v.NewEarningPrice != v.TotalShopMoney*int64(100-v.OrderPayPercentage/2)/int64(100)) && v.OrderPayPercentage <= 50 {
v.NewEarningPrice = v.TotalShopMoney * int64(100-v.OrderPayPercentage/2) / int64(100)
}
} else {
if (v.NewEarningPrice == 0 || v.NewEarningPrice != (v.TotalShopMoney-waybill.DesiredFee)*int64(100-v.OrderPayPercentage/2)/int64(100)) && v.OrderPayPercentage <= 50 {
v.NewEarningPrice = v.TotalShopMoney*int64(100-v.OrderPayPercentage/2)/int64(100) - waybill.DesiredFee
}
}
}
if _, err := dao.UpdateEntity(db, v, "TotalShopMoney", "NewEarningPrice"); err != nil {
globals.SugarLogger.Errorf("更新本地订单结算信息错误 : %s", err)
continue
}
}
}