package localjx

import (
	"errors"
	"fmt"
	"math"
	"regexp"
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/platformapi/jdshopapi"

	"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"

	"git.rosy.net.cn/baseapi/platformapi/jdeclpapi"
	"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
	"git.rosy.net.cn/jx-callback/business/jxstore/event"

	"git.rosy.net.cn/jx-callback/globals/api"

	"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
	"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
	"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"

	"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/baseapi/utils/errlist"
	"git.rosy.net.cn/jx-callback/business/jxstore/cms"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
	"git.rosy.net.cn/jx-callback/business/model"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"git.rosy.net.cn/jx-callback/business/partner"
)

const (
	OrderCreateTypePre    = 0 // 预创建
	OrderCreateTypeNormal = 1 // 正常创建

	PayWaitingTime   = 10 * time.Minute // 等待支付的最长时间
	DingShiDaMinTime = 1 * time.Hour

	specialStoreID      = 100274
	specialFreightPrice = 1500

	wxAppID = "wx4b5930c13f8b1170"

	autoCancelOrderReason         = "支付超时，系统自动取消！"
	cancelMatterOrderReason       = "失败重发！"
	settleDiscountActRefundReason = "守价订单生成补退款"

	splitMatterOrderMinWeight = 4500               //物料订单分包最少要4.5kg
	jxwxfMatterEclpID         = "EMG4418113943423" //京西五香粉物料编码
)

type JxSkuInfo struct {
	SkuID int `json:"skuID"`
	Count int `json:"count"`

	Price     int64 `json:"price,omitempty"`     // 原价
	SalePrice int64 `json:"salePrice,omitempty"` // 售卖价

	Name      string `json:"name"`
	Weight    int    `json:"weight"`
	GroupSign bool   `json:"groupSign"`

	DefendPrice int64 `json:"defendPrice"` //守价
}

type JxSkuInfo2 struct {
	SkuID int `json:"skuID"`
	Count int `json:"count"`

	Price     int64 `json:"price,omitempty"`     // 原价
	SalePrice int64 `json:"salePrice,omitempty"` // 售卖价

	Name      string `json:"name"`
	Weight    int    `json:"weight"`
	GroupSign bool   `json:"groupSign"`
}

type JxSkuInfoList []*JxSkuInfo

func (l JxSkuInfoList) Len() int {
	return len(l)
}

func (l JxSkuInfoList) Less(i, j int) bool {
	if l[i].SkuID == l[j].SkuID {
		return l[i].SalePrice < l[j].SalePrice
	}
	return l[i].SkuID < l[j].SkuID
}

func (l JxSkuInfoList) Swap(i, j int) {
	l[i], l[j] = l[j], l[i]
}

type JxOrderInfo struct {
	BuyerComment string       `json:"buyerComment"` // 备注
	StoreID      int          `json:"storeID"`
	Skus         []*JxSkuInfo `json:"skus"`

	ExpectedDeliveredTimestamp int64 `json:"expectedDeliveredTimestamp"` // 预期送达时间

	TotalPrice     int64 `json:"totalPrice"`     // 单位为分 订单总价
	FreightPrice   int64 `json:"freightPrice"`   // 单位为分 订单配送费
	OrderPrice     int64 `json:"orderPrice"`     // 单位为分 订单商品价格
	ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付

	OrderID       int64  `json:"orderID"`
	StoreName     string `json:"storeName"`
	Weight        int    `json:"weight"`
	FromStoreID   int    `json:"fromStoreID"` //
	EarningType   int    `json:"earningType"`
	OrderType     int    `json:"orderType"`
	IsBuyNowPrice int    `json:"isBuyNowPrice"`
	IsPriceDefend int    `json:"isPriceDefend"`
	OrderID2      string `json:"-"`
	UserID        string `json:"userID"`
}

type DeliveryTimeItem struct {
	ViewTime        string `json:"viewTime"`
	UnixTime        int64  `json:"unixTime"`
	ViewShippingFee string `json:"viewShippingFee"`
}

type DeliveryDayTimeInfo struct {
	Date     string              `json:"date"`
	TimeList []*DeliveryTimeItem `json:"timeList"`
}

type MatterOrderStatus struct {
	Time   time.Time `json:"time"`
	Status string    `json:"status"`
	Name   string    `json:"name"`
	Sign   int       `sign`
}

var (
	weekdayMap = map[int]string{
		1: "一",
		2: "二",
		3: "三",
		4: "四",
		5: "五",
		6: "六",
		0: "日",
	}
	dayList = []string{"今天", "明天", "后天"}

	bagMap = map[int]int{
		6039382: 100,
		6039383: 200,
		6039384: 100,
		6039387: 200,
		6039390: 200,
	}

	regexpCnameAndCmobile  = regexp.MustCompile(`配送员，(.*)，手机号，(.*)`)
	regexpCnameAndCmobile2 = regexp.MustCompile(`（快递员：(.*)，联系电话：(.*)）`)

	bagSkuMap = map[int]int{ //京西物料袋子skuid
		6039382: 6039382,
		6039383: 6039383,
		6039384: 6039384,
		6039387: 6039387,
		6039390: 6039390,
	}
)

func init() {
}

func GetMyOrders(ctx *jxcontext.Context, fromDateStr, toDateStr string, params map[string]interface{}, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
	db := dao.GetDB()
	params["vendorIDs"] = string(utils.MustMarshal([]int{model.VendorIDJX}))
	tmpOrderList, totalCount, err := dao.GetOrders(db, nil, false, false, fromDateStr, toDateStr, false, nil, false, ctx.GetUserID(), params, offset, pageSize)
	if err == nil {
		pagedInfo = &model.PagedInfo{
			TotalCount: totalCount,
		}
		if totalCount > 0 {
			var ids []int64
			for _, v := range tmpOrderList {
				ids = append(ids, v.ID)
			}
			orderSkuList, _, err2 := dao.GetOrders(db, ids, true, false, "", "", false, nil, false, "", nil, 0, model.UnlimitedPageSize)
			if err = err2; err == nil {
				orderMap := make(map[string]*model.GoodsOrderExt)
				var orderList []*model.GoodsOrderExt
				for _, v := range orderSkuList {
					universalOrderID := jxutils.ComposeUniversalOrderID(v.VendorOrderID, v.VendorID)
					if orderMap[universalOrderID] == nil {
						orderMap[universalOrderID] = v
						orderList = append(orderList, v)
					}
					orderMap[universalOrderID].SkuList = append(orderMap[universalOrderID].SkuList, &v.ShortSkuInfo)
				}
				pagedInfo.Data = orderList
			} else {
				pagedInfo = nil
			}
		}
	}
	return pagedInfo, err
}

func GetMyAfsOrders(ctx *jxcontext.Context, vendorOrderID, afsOrderID, userID, fromTime, toTime string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
	afsOrderList, totalCount, err := dao.GetAfsOrdersByPage(dao.GetDB(), vendorOrderID, afsOrderID, userID, utils.Str2Time(fromTime), utils.Str2Time(toTime), offset, pageSize)
	pagedInfo = &model.PagedInfo{
		TotalCount: totalCount,
		Data:       afsOrderList,
	}
	return pagedInfo, err
}

func GetMyOrderCountInfo(ctx *jxcontext.Context, fromDate, toDate time.Time, statuss []int) (countInfo []*model.GoodsOrderCountInfo, err error) {
	countInfo, err = dao.GetMyOrderCountInfo(dao.GetDB(), ctx.GetUserID(), fromDate, toDate, statuss)
	return countInfo, err
}

//fromStoreID 为0 表示非物料订单（京西商城订单等）
//fromStoreID 为 门店ID ，表示是物料订单，fromStoreID表示是哪个门店申请的物料,或者进货方门店
//fromStoreID 为-1 表示也是物料订单，但是不是门店申请，是个人申请的
//fromStoreID 在后面 generateOrder中有用
//IsAuto  是否是守价结算而自动创建的守价订单
func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, createType int, fromStoreID int, IsDeliverySelf bool, couponIDs []int) (outJxOrder *JxOrderInfo, err error) {
	outJxOrder, deliveryAddress, err := generateOrder(ctx, jxOrder, addressID, fromStoreID, "", IsDeliverySelf, couponIDs)
	if err != nil {
		return nil, err
	}

	if jxOrder.OrderType == model.OrderTypeMatter {
		checkMatterDeliveryAddress(deliveryAddress)
	}
	if createType == OrderCreateTypeNormal {
		if jxOrder.OrderType == model.OrderTypeDefendPrice && jxOrder.IsPriceDefend != model.YES {
			vendorOrderID := buildDefendPriceOrder(ctx, jxOrder, addressID)
			outJxOrder.OrderID = utils.Str2Int64(vendorOrderID)
			return outJxOrder, err
		}

		if outJxOrder.TotalPrice != jxOrder.TotalPrice && jxOrder.IsPriceDefend != model.YES {
			return nil, fmt.Errorf("商品或配送信息发生改变，请重新下单")
		}
		if jxOrder.IsPriceDefend == model.YES {
			outJxOrder.OrderID = jxOrder.OrderID
		} else {
			outJxOrder.OrderID = jxutils.GenOrderNo()
		}
		order, err2 := jxOrder2GoodsOrder(ctx, outJxOrder, deliveryAddress, "", IsDeliverySelf, couponIDs)

		if err = err2; err == nil {
			order.AddressID = addressID
			if jxOrder.IsPriceDefend == model.YES {
				order.Status = model.OrderStatusAccepted
			} else {
				order.Status = model.OrderStatusWait4Pay
			}
			callNewOrder(order)
		}
	}
	return outJxOrder, err
}

func buildDefendPriceOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64) (vendorOrderID string) {
	var (
		issue = 0
		db    = dao.GetDB()
	)
	issue = jxutils.GetDefendPriceIssue()
	priceDefendOrder := &model.PriceDefendOrder{
		VendorOrderID: utils.Int64ToStr(jxutils.GenOrderNo()),
		StoreID:       jxOrder.StoreID,
		SkuID:         jxOrder.Skus[0].SkuID,
		AddressID:     addressID,
		Count:         jxOrder.Skus[0].Count,
		DefendPrice:   jxOrder.Skus[0].DefendPrice,
		OriginPrice:   jxOrder.Skus[0].Price,
		IsBuyNowPrice: jxOrder.IsBuyNowPrice,
		Issue:         issue,
		IsSuccess:     model.NO, //默认是不成功
		IsPay:         model.NO,
	}
	dao.WrapAddIDCULDEntity(priceDefendOrder, ctx.GetUserName())
	priceDefendOrder.ActualPayPrice = int64(priceDefendOrder.Count)*jxOrder.Skus[0].Price + jxOrder.FreightPrice
	dao.CreateEntity(db, priceDefendOrder)
	return priceDefendOrder.VendorOrderID
}

// 买家取消（或申请取消）订单
func BuyerCancelOrder(ctx *jxcontext.Context, orderID int64, reason string) (canceled bool, err error) {
	order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(orderID), model.VendorIDJX)
	if err == nil {
		if order.Status < model.OrderStatusNew {
			order.Status = model.OrderStatusCanceled
			order.VendorStatus = utils.Int2Str(model.OrderStatusCanceled)
			if err = partner.CurOrderManager.UpdateOrderFields(order, []string{model.FieldStatus, "VendorStatus"}); err == nil {
				canceled = true
			}
		} else {
			err = fmt.Errorf("暂不支持自行取消订单，请联系商家取消")
			// err = changeOrderStatus(utils.Int64ToStr(orderID), model.OrderStatusApplyCancel, fmt.Sprintf("用户%s主动取消", ctx.GetUserName()))
		}
	}
	return canceled, err
}

func Pay4Order(ctx *jxcontext.Context, orderID int64, payType int, vendorPayType, subAppID string) (orderPay *model.OrderPay, err error) {
	var (
		db = dao.GetDB()
	)
	order, err := partner.CurOrderManager.LoadOrder(utils.Int64ToStr(orderID), model.VendorIDJX)
	if err == nil {
		switch payType {
		case model.PayTypeWX:
			if orderPay, err = pay4OrderByWX(ctx, order, vendorPayType); err == nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		case model.PayTypeTL:
			//if subAppID == tiktok.TiktokAppId || subAppID == tiktok.TiktokJXDJAppID {
			//	subAppID = model.JXC4AppId // 京西商城
			//}
			if orderPay, err = pay4OrderByTL(ctx, order, payType, vendorPayType, subAppID, ""); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		case model.PayTypeLaKaLa: //
			if orderPay, err = pay4OrderByLaKaLa(ctx, order, payType, vendorPayType, subAppID, "", ""); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		case model.PayTypeTicTok:
			if orderPay, err = pay4OrderByTT(ctx, order, vendorPayType, subAppID); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		case model.PayTypeKuaiShou:
			if orderPay, err = pay4OrderByKs(ctx, order, vendorPayType, subAppID); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		default:
			err = fmt.Errorf("支付方式:%d当前不支持", payType)
		}
	} else {
		priceDefendOrders, _ := dao.GetPriceDefendOrder(db, utils.Int64ToStr(orderID), nil, nil, []int{jxutils.GetDefendPriceIssue()}, 0, -1, -1, 0, "", utils.ZeroTimeValue, utils.ZeroTimeValue, false)
		if len(priceDefendOrders) == 0 {
			err = fmt.Errorf("未查询到待支付订单！order_id: %v", orderID)
		}
		order2 := &model.GoodsOrder{
			VendorOrderID:  priceDefendOrders[0].VendorOrderID,
			ActualPayPrice: priceDefendOrders[0].ActualPayPrice,
			VendorID:       model.VendorIDJX,
		}
		if orderPay, err = pay4OrderByTL(ctx, order2, payType, vendorPayType, subAppID, ""); err == nil && orderPay != nil {
			dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
			err = dao.CreateEntity(dao.GetDB(), orderPay)
		}
	}
	return orderPay, err
}

func Pay4User(ctx *jxcontext.Context, thingID int, vendorOrderID string, payType int, vendorPayType, subAppID, code string) (orderPay *model.OrderPay, err error) {
	var (
		db           = dao.GetDB()
		order        *model.GoodsOrder
		dicountCards []*model.DiscountCard
	)
	switch payType {
	case model.PayTypeTL_DiscountCard:
		if configList, err := dao.QueryConfigs(db, "会员折扣卡", model.ConfigTypeDiscountCard, ""); err == nil {
			jxutils.Strings2Objs(configList[0].Value, &dicountCards)
			if err != nil {
				return nil, err
			}
			discountCard := findDiscountCard(dicountCards, thingID)
			flag, userMemberOrigin, err := checkMember(db, ctx.GetUserID(), discountCard)
			if err != nil {
				return nil, err
			}
			vendorOrderID = utils.Int64ToStr(jxutils.GenOrderNo())
			order = &model.GoodsOrder{
				VendorOrderID:  vendorOrderID,
				ActualPayPrice: int64(discountCard.Price),
				VendorID:       model.VendorIDJX,
			}
			if orderPay, err = pay4OrderByTL(ctx, order, payType, vendorPayType, subAppID, code); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
			mobile, userID := ctx.GetMobileAndUserID()
			userMember := &model.UserMember{
				VendorOrderID: vendorOrderID,
				UserID:        userID,
				MemberType:    model.MemberTypeDiscountCard,
				EndAt:         utils.Str2Time(time.Now().AddDate(0, 1, 0).AddDate(0, 0, -1).Format("2006-01-02") + " 23:59:59"),
				MemberTypeID:  thingID,
				IsPay:         model.NO,
				VendorID:      model.VendorIDJX,
				Mobile:        mobile,
			}
			dao.WrapAddIDCULDEntity(userMember, ctx.GetUserName())
			if flag == 0 {
				dao.CreateEntity(db, userMember)
			} else if flag == 1 {
				userMemberOrigin.EndAt = userMemberOrigin.EndAt.AddDate(0, 1, 0)
				dao.UpdateEntity(db, userMemberOrigin, "EndAt")
			}
		}
	case model.PayTypeTL_StoreAcctPay: // 门店账户充值
		storeOrder := &model.StoreAcctOrder{
			VendorOrderID: vendorOrderID,
		}
		if err = dao.GetEntity(db, storeOrder, "VendorOrderID"); err == nil && storeOrder.ID != 0 {
			order = &model.GoodsOrder{
				VendorOrderID:  vendorOrderID,
				ActualPayPrice: int64(storeOrder.ActualPayPrice),
				VendorID:       model.VendorIDJX,
			}
			if orderPay, err = pay4OrderByTL(ctx, order, payType, vendorPayType, subAppID, code); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		}
	case model.PayTypeTL_BrandBillCharge: // 品牌账户充值
		brandOrder := &model.StoreAcctOrder{
			VendorOrderID: vendorOrderID,
		}
		if err = dao.GetEntity(db, brandOrder, "VendorOrderID"); err == nil && brandOrder.ID != 0 {
			order = &model.GoodsOrder{
				VendorOrderID:  vendorOrderID,
				ActualPayPrice: int64(brandOrder.ActualPayPrice),
				VendorID:       model.VendorIDJX,
			}
			if orderPay, err = pay4OrderByTL(ctx, order, payType, vendorPayType, subAppID, code); err == nil && orderPay != nil {
				dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
				err = dao.CreateEntity(dao.GetDB(), orderPay)
			}
		}
	default:
		err = fmt.Errorf("支付方式:%d当前不支持", payType)
	}
	return orderPay, err
}

//flag
//0 正常购买
//1 续费
//-1 不能购买
func checkMember(db *dao.DaoDB, userID string, discountCard *model.DiscountCard) (flag int, userMember *model.UserMember, err error) {
	userMembers, err := dao.GetUserMember(db, userID, "", "", model.VendorIDJX, model.MemberTypeDiscountCard, model.YES)
	if len(userMembers) > 0 {
		userMember = userMembers[0]
		if userMember.ID < discountCard.ID {
			return 0, userMember, err
		} else if userMember.ID == discountCard.ID {
			return 1, userMember, err
		} else {
			return -1, userMember, fmt.Errorf("已购买更高档次的会员，无法继续购买！")
		}
	}
	return 0, userMember, err
}

func time2ShortTimeStr(t time.Time) string {
	return t.Format("15:04")
}

func findDiscountCard(dicountCards []*model.DiscountCard, thingID int) (dicountCard *model.DiscountCard) {
	for _, v := range dicountCards {
		if v.ID == thingID {
			return v
		}
	}
	return dicountCard
}

func GetAvailableDeliverTime(ctx *jxcontext.Context, storeID int) (deliverTimerList []*DeliveryDayTimeInfo, err error) {
	db := dao.GetDB()
	storeDetail, err := dao.GetStoreDetail(db, storeID, model.VendorIDJX, "")
	if err != nil {
		return nil, err
	}
	if storeDetail.Status != model.StoreStatusOpened {
		return nil, fmt.Errorf("门店:%s不是营业状态,状态是:%s", storeDetail.Name, model.StoreStatusName[storeDetail.Status])
	}
	// now := utils.Str2Time(timeStr)
	now := time.Now()
	// beginDate := utils.Time2Date(utils.Str2Time(timeStr))
	beginDate := utils.Time2Date(now)
	minDingShiDaTime := now.Add(DingShiDaMinTime)
	viewShippingFee := "约6.6元配送费"
	if storeID == specialStoreID {
		viewShippingFee = "免费配送"
	}
	var isOrder = false
	if storeDetail.IsOrder == model.YES {
		isOrder = true
		beginDate = beginDate.AddDate(0, 0, 1)
	}
	for i, dayStr := range dayList {
		if isOrder {
			isOrder = false
			continue
		}
		openTime1 := jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime1, beginDate)
		closeTime1 := jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime1, beginDate)
		openTime2 := jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime2, beginDate)
		closeTime2 := jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime2, beginDate)
		timeInfo := &DeliveryDayTimeInfo{
			Date: fmt.Sprintf("%s(周%s)", dayStr, weekdayMap[int(beginDate.Weekday())]),
		}
		if i == 0 {
			if isTimeInOpTime(storeDetail.OpenTime1, storeDetail.CloseTime1, storeDetail.OpenTime2, storeDetail.CloseTime2, now) {
				timeInfo.TimeList = append(timeInfo.TimeList, &DeliveryTimeItem{
					ViewTime:        "立即送出",
					UnixTime:        0,
					ViewShippingFee: viewShippingFee,
				})
			}
		}
		for j := 0; j < 24*3; j++ {
			deliveryTime := beginDate.Add(time.Duration(j) * 20 * time.Minute)
			if deliveryTime.Sub(minDingShiDaTime) >= 0 {
				if (deliveryTime.Sub(openTime1) >= 0 && deliveryTime.Sub(closeTime1) <= 0) ||
					(storeDetail.OpenTime2 > 0 && deliveryTime.Sub(openTime2) >= 0 && deliveryTime.Sub(closeTime2) <= 0) {
					timeInfo.TimeList = append(timeInfo.TimeList, &DeliveryTimeItem{
						ViewTime:        time2ShortTimeStr(deliveryTime),
						UnixTime:        deliveryTime.Unix(),
						ViewShippingFee: viewShippingFee,
					})
				}
			}
		}
		if len(timeInfo.TimeList) > 0 {
			deliverTimerList = append(deliverTimerList, timeInfo)
		}
		beginDate = beginDate.Add(24 * time.Hour)
	}
	if len(deliverTimerList) > 0 {
		if deliverTimerList[0].TimeList[0].UnixTime != 0 {
			deliverTimerList[0].TimeList[0].ViewTime = "营业即送"
		}
	}
	return deliverTimerList, err
}

func OnPayFinished(orderPay *model.OrderPay) (err error) {
	// 查询订单是购物订单还是充值订单
	var (
		db = dao.GetDB()
	)
	order, err := partner.CurOrderManager.LoadOrder(orderPay.VendorOrderID, orderPay.VendorID)
	if err == nil {
		dao.UpdateEntity(db, orderPay)
		if count, err2 := dao.GetJxOrderCount(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorOrderID, order.OrderCreatedAt); err2 == nil {
			order.OrderSeq = count + 1
			partner.CurOrderManager.UpdateOrderFields(order, []string{"OrderSeq"})
		}
		order.Status = model.OrderStatusNew
		order.VendorStatus = utils.Int2Str(model.OrderStatusNew)
		order.StatusTime = *orderPay.PayFinishedAt
		err = callNewOrder(order)
		//如果是物料的订单，直接到拣货完成，配送中的状态
		if order.OrderType != model.OrderTypeNormal {
			if order.OrderType != model.OrderTypeDefendPrice {
				netprinter.PrintOrderByOrder(jxcontext.AdminCtx, order, model.PrintTypeOrder, nil)
			}
			PickupGoods(order, false, "jxadmin")
		} else {
			//普通的订单要看用没用优惠券，用了的话，要把这个用户用过的优惠券状态改了
			if order.CouponIDs != "" {
				sCouponIDs := strings.Split(order.CouponIDs, ",")
				couponIDs := []int{}
				for _, v := range sCouponIDs {
					couponIDs = append(couponIDs, utils.Str2Int(v))
				}
				if userCoupons, err := dao.GetUserCoupons(db, couponIDs, []string{order.UserID}, nil, model.CouponStatusNormal); err == nil {
					for _, vv := range userCoupons {
						vv.UserCouponStatus = model.UserCouponStatusUsed
						vv.UpdatedAt = time.Now()
						dao.UpdateEntity(db, vv, "UserCouponStatus", "UpdatedAt")
					}
				}
			}
		}
	} else {
		switch orderPay.PayType {
		case model.PayTypeTL_DiscountCard:
			userMembers, _ := dao.GetUserMember(db, "", orderPay.VendorOrderID, "", model.VendorIDJX, model.MemberTypeDiscountCard, model.NO)
			if len(userMembers) > 0 {
				userMembers[0].IsPay = model.YES
				dao.UpdateEntity(db, userMembers[0], "IsPay")
				err = nil
			}
		case model.PayTypeTL_StoreAcctPay: //门店账户充值完成后直接入账
			storeOrder := &model.StoreAcctOrder{
				VendorOrderID: orderPay.VendorOrderID,
			}
			if err = dao.GetEntity(db, storeOrder, "VendorOrderID"); err == nil && storeOrder.ID != 0 {
				storeOrder.OrderFinishedAt = time.Now()
				storeOrder.Status = model.OrderStatusFinished
				_, err = dao.UpdateEntity(db, storeOrder, "OrderFinishedAt", "Status")
				if err != nil {
					return err
				}
				partner.CurStoreAcctManager.InsertStoreAcctIncomeAndUpdateStoreAcctBalance(jxcontext.AdminCtx, storeOrder.StoreID, storeOrder.ActualPayPrice, partner.StoreAcctTypeIncomePay, storeOrder.VendorOrderID, "", 0)
			}
		case model.PayTypeTL_BrandBillCharge: // 品牌充值入账
			brandOrder := &model.StoreAcctOrder{
				VendorOrderID: orderPay.VendorOrderID,
			}
			if err = dao.GetEntity(db, brandOrder, "VendorOrderID"); err == nil && brandOrder.ID != 0 {
				brandOrder.OrderFinishedAt = time.Now()
				brandOrder.Status = model.OrderStatusFinished
				if _, err = dao.UpdateEntity(db, brandOrder, "OrderFinishedAt", "Status"); err == nil {
					store, _ := dao.GetStoreDetail(db, brandOrder.StoreID, 0, "")
					partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, store.BrandID, brandOrder.ActualPayPrice, model.BrandBillTypeIncome, model.BrandBillFeeTypeCharge, orderPay.VendorOrderID, "")
				}
			}
		default:
			priceDefendOrders, _ := dao.GetPriceDefendOrder(db, orderPay.VendorOrderID, nil, nil, []int{jxutils.GetDefendPriceIssue()}, 0, -1, -1, 0, "", utils.ZeroTimeValue, utils.ZeroTimeValue, false)
			if len(priceDefendOrders) > 0 {
				priceDefendOrders[0].IsPay = model.YES
				dao.UpdateEntity(db, priceDefendOrders[0], "IsPay")
				err = nil
			}
		}
		err = nil
	}
	return err
}

func GenPayOrderID(order *model.GoodsOrder) (payOrderID int64) {
	return utils.Str2Int64(order.VendorOrderID)
}

func GenRefundID(order *model.GoodsOrder) (refundID int64) {
	const suffix = 100000
	refundID = utils.Str2Int64(order.VendorOrderID) * suffix
	refundID += int64(time.Now().Sub(order.OrderFinishedAt) / time.Minute)
	return refundID
}

func formalizeSkus(skus []*JxSkuInfo) (outSkus []*JxSkuInfo) {
	skuMap := make(map[int]int)
	for _, v := range skus {
		skuMap[v.SkuID] += v.Count
	}
	for skuID, skuCount := range skuMap {
		outSkus = append(outSkus, &JxSkuInfo{
			SkuID: skuID,
			Count: skuCount,
		})
	}
	return outSkus
}

func isTimeInOpTime(openTime1, closeTime1, openTime2, closeTime2 int16, time2Check time.Time) bool {
	timeStrList := []string{
		jxutils.OperationTime2StrWithSecond(openTime1),
		jxutils.OperationTime2StrWithSecond(closeTime1),
	}
	if openTime1 > 0 {
		timeStrList = append(timeStrList,
			jxutils.OperationTime2StrWithSecond(openTime2),
			jxutils.OperationTime2StrWithSecond(closeTime2),
		)
	}
	checkTimeStr := utils.Time2TimeStr(time2Check)
	for i := 0; i < len(timeStrList); i += 2 {
		if checkTimeStr >= timeStrList[i] && checkTimeStr <= timeStrList[i+1] {
			return true
		}
	}
	return false
}

func generateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, fromStoreID int, userID string, IsDeliverySelf bool, couponIDs []int) (outJxOrder *JxOrderInfo, deliveryAddress *dao.UserDeliveryAddressEx, err error) {
	db := dao.GetDB()
	if jxOrder.StoreID == 0 {
		return nil, nil, fmt.Errorf("没有指定门店信息")
	}
	// 配送范围检查
	storeDetail, err := dao.GetStoreDetail(db, jxOrder.StoreID, model.VendorIDJX, "")
	if err != nil {
		return nil, nil, err
	}
	if IsDeliverySelf && storeDetail.DeliverySelf != model.YES {
		return nil, nil, fmt.Errorf("门店暂不支持自提订单")
	}
	var addressList []*dao.UserDeliveryAddressEx
	if userID == "" {
		addressList, _, err = dao.QueryUserDeliveryAddress(db, addressID, nil, 0, 0)
	} else if addressID == 464 { // 默认的地址ID,此种类型的订单为到店消费
		addressList = append(addressList, &dao.UserDeliveryAddressEx{
			UserDeliveryAddress: model.UserDeliveryAddress{
				UserID:          ctx.GetUserID(),
				Tag:             "门店地址",
				ConsigneeName:   storeDetail.Name,
				ConsigneeMobile: storeDetail.Tel1,
				Address:         storeDetail.Address,
				DetailAddress:   storeDetail.Address,
				Lng:             jxutils.IntCoordinate2Standard(storeDetail.Lng),
				Lat:             jxutils.IntCoordinate2Standard(storeDetail.Lat),
				AutoAddress:     storeDetail.Address,
				CityCode:        storeDetail.CityCode,
				DistrictCode:    storeDetail.DistrictCode,
				Remark:          "",
				IsDefault:       1,
			},
			UserName:     ctx.GetUserName(),
			CityName:     storeDetail.CityName,
			DistrictName: storeDetail.DistrictName,
			ParentCode:   0,
		})
	} else {
		addressList, _, err = dao.QueryUserDeliveryAddress(db, addressID, nil, 0, 0)
	}
	if err != nil {
		return nil, nil, err
	}
	if len(addressList) == 0 {
		return nil, nil, fmt.Errorf("地址ID不正确")
	}
	deliveryAddress = addressList[0]
	distance := jxutils.Point2StoreDistance(deliveryAddress.Lng, deliveryAddress.Lat, storeDetail.Lng, storeDetail.Lat, storeDetail.DeliveryRangeType, storeDetail.DeliveryRange)
	if distance == 0 && !IsDeliverySelf {
		return nil, nil, fmt.Errorf("当前送货地址不在门店%s的配送范围", storeDetail.Name)
	}
	//结算类型
	if storeDetail.PayPercentage < 50 {
		jxOrder.EarningType = model.EarningTypePoints
	} else {
		jxOrder.EarningType = model.EarningTypeQuote
	}

	// 营业状态及时间检查
	if !IsDeliverySelf {
		if storeDetail.Status != model.StoreStatusOpened { // model.StoreStatusDisabled {
			return nil, nil, fmt.Errorf("门店:%s状态是:%s", storeDetail.Name, model.StoreStatusName[storeDetail.Status])
		}
		checkTime := time.Now()
		if jxOrder.ExpectedDeliveredTimestamp == 0 {
			if storeDetail.Status != model.StoreStatusOpened {
				return nil, nil, fmt.Errorf("门店:%s不是营业状态,状态是:%s", storeDetail.Name, model.StoreStatusName[storeDetail.Status])
			}
		} else {
			checkTime = utils.Timestamp2Time(jxOrder.ExpectedDeliveredTimestamp)
			if checkTime.Sub(time.Now()) < DingShiDaMinTime {
				return nil, nil, fmt.Errorf("预订单只能在1小时后")
			}
			if utils.Time2Date(time.Now()).Sub(utils.Time2Date(checkTime)) > 24*time.Hour {
				return nil, nil, fmt.Errorf("预订单只能预定当天或第二天")
			}
		}
	}
	outJxOrder2 := *jxOrder
	outJxOrder2.Skus = nil
	outJxOrder2.OrderPrice = 0
	outJxOrder2.Weight = 0
	outJxOrder = &outJxOrder2
	outJxOrder.StoreName = storeDetail.Name
	skus := formalizeSkus(jxOrder.Skus)
	// 允许空商品列表（一般用于测试配送地址，门店信息是否合适）
	if len(skus) > 0 {
		var skuIDs []int
		for _, v := range skus {
			skuIDs = append(skuIDs, v.SkuID)
		}
		storeSkuInfo, err := cms.GetStoreSkus(ctx, jxOrder.StoreID, skuIDs, true, "", true, false, map[string]interface{}{
			"actVendorID": model.VendorIDJX,
		}, 0, model.UnlimitedPageSize)
		if err != nil {
			return nil, nil, err
		}
		storeSkuMap := make(map[int]*dao.StoreSkuExt)
		for _, v1 := range storeSkuInfo.SkuNames {
			for _, v2 := range v1.Skus {
				if v2.StoreSkuStatus != model.SkuStatusNormal {
					return nil, nil, fmt.Errorf("此商品已下架，请联系管理员！skuID:[%v]", v2.SkuID)
				}
				storeSkuMap[v2.SkuID] = v2
			}
		}

		skuList, err := dao.GetSkus(db, skuIDs, nil, nil, nil, nil)
		if err != nil {
			return nil, nil, err
		}
		skuMap := make(map[int]*model.SkuAndName)
		for _, v := range skuList {
			// if fromStoreID != 0 {

			// }
			if jxOrder.OrderType == model.OrderTypeMatter {
				if v.EclpID == "" {
					return nil, nil, fmt.Errorf("此商品物料编码为空，请联系管理员！skuID:[%v]", v.ID)
				}
			}
			skuMap[v.ID] = v
		}
		var (
			result *orderman.OrderCount
			sum    int     //申请物料的店的最近销量，以下会根据销量计算具体袋子的价格
			flag   = false //新店袋子拆分当个参数
		)
		// if fromStoreID != 0 && fromStoreID != -1 {
		// 	result, _ = orderman.GetMatterStoreOrderCount(nil, fromStoreID)
		// 	sum = result.Count
		// }
		if jxOrder.OrderType == model.OrderTypeMatter && fromStoreID != -1 {
			result, _ = orderman.GetMatterStoreOrderCount(nil, fromStoreID)
			sum = result.Count
		}
		if jxOrder.Weight == 0 {
			for _, v := range jxOrder.Skus {
				v.Weight = storeSkuMap[v.SkuID].Weight
				jxOrder.Weight += v.Weight * v.Count
			}
		}
		for _, v := range skus {
			if storeSkuBind := storeSkuMap[v.SkuID]; storeSkuBind != nil {
				// if fromStoreID != 0 {
				if jxOrder.OrderType == model.OrderTypeMatter {
					result2, _ := api.JdEclpAPI.QueryStock(storeSkuBind.EclpID)
					if len(result2) > 0 {
						if result2[0].UsableNum < v.Count {
							//							return nil, nil, fmt.Errorf("此商品库存不足无法购买，请联系管理员！skuID:[%v]", v.SkuID)
						}
					}
				}
				// }
				if sku := skuMap[v.SkuID]; sku != nil {
					jxSku := &JxSkuInfo{
						SkuID:     v.SkuID,
						Price:     int64(storeSkuBind.JxPrice),
						Count:     v.Count,
						SalePrice: int64(storeSkuBind.JxPrice), // todo 考虑活动价
						Weight:    sku.Weight,
						Name:      jxutils.ComposeSkuName(sku.Prefix, sku.Name, sku.Comment, sku.Unit, sku.SpecQuality, sku.SpecUnit, 0, sku.ExPrefix, sku.ExPrefixBegin, sku.ExPrefixEnd),
					}
					if fromStoreID != -1 && storeSkuBind.ActType != model.ActSkuDiscount {
						//活动商品要拆分，一分钱的单独列一个(count为1)，正常价格的列在一起(count叠加)
						if storeSkuBind.ActPrice != 0 && storeSkuBind.ActPrice < storeSkuBind.JxPrice {
							jxSku.SalePrice = int64(storeSkuBind.ActPrice)
							jxSku.Count = 1

							outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
							outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
							outJxOrder.Weight += jxSku.Count * jxSku.Weight
							if v.Count-1 > 0 {
								jxSku2 := *jxSku
								jxSku2.SalePrice = jxSku.Price
								jxSku2.Count = v.Count - 1

								jxSku = &jxSku2
							} else {
								jxSku = nil
							}
						}
					} else if storeSkuBind.ActType == model.ActSkuDiscount && jxOrder.OrderType != model.OrderTypeDefendPrice { //守价的订单是支付原价
						jxSku.SalePrice = int64(storeSkuBind.ActPrice)
					}
					if jxSku != nil {
						// if fromStoreID == 0 || fromStoreID == -1 {
						if jxOrder.OrderType != model.OrderTypeMatter || (jxOrder.OrderType == model.OrderTypeMatter && fromStoreID == -1) {
							outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
							outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
						} else { //以下else为物料订单袋子金额和数量处理
							if !result.Flag { //只要flag是false就按原价申请，是true再按订单量
								outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
								outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
							} else {
								if result.Count == 0 { //这个条件被认为是新店，袋子限量
									if bagMap[jxSku.SkuID] != 0 { //如果他买了袋子，第一个袋子算1分钱，其余按原价（包括所有袋子）
										if !flag {
											salePirce := jxSku.SalePrice
											count := jxSku.Count
											jxSku.SalePrice = 1
											jxSku.Count = 1
											outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
											outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
											if count > 1 {
												jxSku2 := *jxSku
												jxSku2.SalePrice = salePirce
												jxSku2.Count = count - 1
												outJxOrder.Skus = append(outJxOrder.Skus, &jxSku2)
												outJxOrder.OrderPrice += int64(jxSku2.Count) * jxSku2.SalePrice
												outJxOrder.Weight += jxSku2.Count * jxSku2.Weight
											}
											flag = true
										} else {
											outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
											outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
										}
									} else {
										outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
										outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
									}
								} else {
									//袋子总数小于等于销量就是1分钱，只要大于销量其他就按原价
									//这个袋子规格是一份100个
									if jxSku.SkuID == 6039382 || jxSku.SkuID == 6039384 {
										if bagMap[jxSku.SkuID] != 0 {
											if sum > 0 {
												if bagMap[jxSku.SkuID]*jxSku.Count <= sum+100 {
													jxSku.SalePrice = 1
													outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
													outJxOrder.OrderPrice += int64(1 * jxSku.Count)
												} else {
													jxSku2 := *jxSku
													jxSku2.SalePrice = jxSku.SalePrice
													jxSku2.Count = int(int64(jxSku.Count) - utils.Float64TwoInt64(math.Ceil(utils.Int2Float64(sum)/100)))
													outJxOrder.Weight += jxSku2.Count * jxSku2.Weight
													jxSku.SalePrice = 1
													jxSku.Count = int(utils.Float64TwoInt64(math.Ceil(utils.Int2Float64(sum) / 100)))
													outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
													outJxOrder.Skus = append(outJxOrder.Skus, &jxSku2)
													outJxOrder.OrderPrice += jxSku.SalePrice * int64(jxSku.Count)
													outJxOrder.OrderPrice += jxSku2.SalePrice * int64(jxSku2.Count)
												}
											} else {
												outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
												outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
											}
											sum = sum - bagMap[jxSku.SkuID]*jxSku.Count
										}
									} else if jxSku.SkuID == 6039383 || jxSku.SkuID == 6039387 || jxSku.SkuID == 6039390 { //这些袋子是一份200个 jxSku.SkuID == 6039384 ||
										if bagMap[jxSku.SkuID] != 0 {
											if sum > 0 {
												if bagMap[jxSku.SkuID]*jxSku.Count <= sum+200 {
													jxSku.SalePrice = 1
													outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
													outJxOrder.OrderPrice += int64(1 * jxSku.Count)
												} else {
													jxSku2 := *jxSku
													jxSku2.SalePrice = jxSku.SalePrice
													jxSku2.Count = int(int64(jxSku.Count) - utils.Float64TwoInt64(math.Ceil(utils.Int2Float64(sum)/200)))
													outJxOrder.Weight += jxSku2.Count * jxSku2.Weight
													jxSku.SalePrice = 1
													jxSku.Count = int(utils.Float64TwoInt64(math.Ceil(utils.Int2Float64(sum) / 200)))
													outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
													outJxOrder.Skus = append(outJxOrder.Skus, &jxSku2)
													outJxOrder.OrderPrice += jxSku.SalePrice * int64(jxSku.Count)
													outJxOrder.OrderPrice += jxSku2.SalePrice * int64(jxSku2.Count)
												}
											} else {
												outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
												outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
											}
											sum = sum - bagMap[jxSku.SkuID]*jxSku.Count
										}
									} else {
										outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
										outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
									}
								}
							}
						}
						outJxOrder.Weight += jxSku.Count * jxSku.Weight
					}
				}
			}
		}
		// if fromStoreID == 0 {
		// 	sort.Sort(JxSkuInfoList(outJxOrder.Skus))
		// outJxOrder.FreightPrice, _, err = delivery.CalculateDeliveryFee(dao.GetDB(), jxOrder.StoreID, "",
		// 	jxutils.StandardCoordinate2Int(deliveryAddress.Lng), jxutils.StandardCoordinate2Int(deliveryAddress.Lat),
		// 	model.CoordinateTypeMars, outJxOrder.Weight, checkTime)
		//TODO 2020-08-06 配送费固定5元
		if !IsDeliverySelf {
			outJxOrder.FreightPrice = 500
		}
		// }
		//如果是守价的订单，需要查询本期中该用户是否已经守价过，如果守价过就只算一次运费
		if jxOrder.OrderType == model.OrderTypeDefendPrice {
			priceDefendOrders, _ := dao.GetPriceDefendOrder(db, "", nil, nil, []int{jxutils.GetDefendPriceIssue()}, 0, -1, -1, 1, deliveryAddress.UserID, utils.ZeroTimeValue, utils.ZeroTimeValue, false)
			if len(priceDefendOrders) > 0 {
				flag2 := false
				for _, v := range priceDefendOrders {
					if v.StoreID != jxOrder.StoreID {
						flag2 = true
					}
				}
				if flag2 {
					return nil, nil, fmt.Errorf("同一期不允许相同用户在不同门店进行守价!")
				}
				outJxOrder.FreightPrice = 0
			}
		}
	} else {
		outJxOrder.FreightPrice = 0
	}

	//表示此订单为物料配送订单
	if jxOrder.OrderType != model.OrderTypeNormal {
		// if fromStoreID != 0 {
		storeDetail2, err2 := dao.GetStoreDetail(db, fromStoreID, model.VendorIDJX, "")
		if err = err2; err != nil {
			return nil, nil, fmt.Errorf("fromStoreID有误,[%v]", fromStoreID)
		}
		outJxOrder.FromStoreID = fromStoreID
		if jxOrder.OrderType == model.OrderTypeMatter {
			//TODO 修改配送费规则，2020-04-28
			//3kg 5元，每多1kg加2元
			//配送费要按分包规则计算
			if outJxOrder.Weight <= 3000 {
				outJxOrder.FreightPrice = 500
			} else if outJxOrder.Weight > 3000 && outJxOrder.Weight <= splitMatterOrderMinWeight {
				outJxOrder.FreightPrice = utils.Float64TwoInt64(500 + math.Ceil((utils.Int2Float64(outJxOrder.Weight)-3000)/1000)*200)
			} else {
				_, freightPrice, _ := tryToSplitMatterOrder(jxOrder)
				outJxOrder.FreightPrice = freightPrice
			}
		}
		//要求配送人姓名填门店名
		if fromStoreID != -1 {
			deliveryAddress.ConsigneeName = storeDetail2.Name
		}
		//内蒙古海南统一35
		//新疆西藏统一45
		if deliveryAddress.ParentCode == 150000 || deliveryAddress.ParentCode == 460000 {
			outJxOrder.FreightPrice = 3500
		}
		if deliveryAddress.ParentCode == 650000 || deliveryAddress.ParentCode == 540000 {
			outJxOrder.FreightPrice = 4500
		}
	} else {
		if outJxOrder.FreightPrice > specialFreightPrice {
			outJxOrder.FreightPrice = specialFreightPrice
		}
		if outJxOrder.OrderPrice >= int64(storeDetail.DeliveryFeeDeductionSill) {
			outJxOrder.FreightPrice -= int64(storeDetail.DeliveryFeeDeductionFee)
			if outJxOrder.FreightPrice < 0 || IsDeliverySelf {
				outJxOrder.FreightPrice = 0
			}
		}
	}

	// B2B门店，订单不足一千配送费一百
	if strings.Contains(storeDetail.BrandName, model.B2BTag) {
		outJxOrder.FreightPrice = 10000 // b2b运费一百元
	}
	// 订单超过一千配送费优惠(门店运费)
	discountPrice, err := cms.GetStoreVendorMaps(ctx, nil, jxOrder.StoreID, -1)
	if len(discountPrice) == 1 && outJxOrder.OrderPrice >= int64(discountPrice[0].DeliveryFeeDeductionSill) {
		if outJxOrder.FreightPrice-int64(discountPrice[0].DeliveryFeeDeductionFee) >= 0 {
			outJxOrder.FreightPrice = outJxOrder.FreightPrice - int64(discountPrice[0].DeliveryFeeDeductionFee)
		} else {
			outJxOrder.FreightPrice = 0
		}
	}

	if err == nil {
		if jxOrder.OrderType == model.OrderTypeNormal {
			outJxOrder.TotalPrice = outJxOrder.OrderPrice + outJxOrder.FreightPrice
			var (
				tuserID      string
				dicountCards []*model.DiscountCard
			)
			if userID == "" {
				tuserID = deliveryAddress.UserID
			} else {
				tuserID = userID
			}
			// 1.先扣除优惠券
			if len(couponIDs) > 0 {
				if userCoupons, err := dao.GetUserCoupons(db, couponIDs, []string{tuserID}, nil, model.CouponStatusNormal); err == nil {
					if len(userCoupons) != len(couponIDs) {
						return nil, nil, fmt.Errorf("选择的优惠券状态不正常，请刷新后重试！")
					}
					for _, v := range userCoupons {
						coupon := &model.Coupons{}
						coupon.ID = int64(v.CouponID)
						if err = dao.GetEntity(db, coupon); err == nil && coupon.Name != "" {
							checkPrice := func(price int64) (rPrice int64, err error) {
								priceInt := int(price)
								if priceInt < coupon.UpperLimit {
									return 0, fmt.Errorf("抱歉，该订单价格未达到此优惠券[%v]满减额度！", coupon.Name)
								}
								if priceInt <= coupon.Cut {
									rPrice = 0
								} else {
									rPrice = int64(priceInt - coupon.Cut)
								}
								return rPrice, err
							}
							switch coupon.CouponType {
							case model.CouponTypeDiscount:
								outJxOrder.OrderPrice, err = checkPrice(outJxOrder.OrderPrice)
							case model.CouponTypeDelivery:
								outJxOrder.FreightPrice, err = checkPrice(outJxOrder.FreightPrice)
							default:
								return nil, nil, fmt.Errorf("暂不支持的优惠券类型！[%v]", coupon.CouponType)
							}
							if err != nil {
								return nil, nil, err
							}
						}
					}
				} else {
					return nil, nil, err
				}
			}
			// 2.判断用户是否是会员
			userMembers, _ := dao.GetUserMember(db, tuserID, "", "", model.VendorIDJX, model.MemberTypeDiscountCard, model.YES)
			if len(userMembers) > 0 {
				if configList, err := dao.QueryConfigs(db, "会员折扣卡", model.ConfigTypeDiscountCard, ""); err == nil {
					jxutils.Strings2Objs(configList[0].Value, &dicountCards)
					discountCard := findDiscountCard(dicountCards, userMembers[0].MemberTypeID)
					outJxOrder.OrderPrice = utils.Float64TwoInt64(math.Round(float64(outJxOrder.OrderPrice) * float64(int64(discountCard.PicePercentage)) / float64(100)))
				}
			}
			outJxOrder.ActualPayPrice = outJxOrder.OrderPrice + outJxOrder.FreightPrice
		} else if jxOrder.OrderType == model.OrderTypeDefendPrice {
			outJxOrder.Skus[0].DefendPrice = jxOrder.Skus[0].DefendPrice
		} else {
			outJxOrder.TotalPrice = outJxOrder.OrderPrice + outJxOrder.FreightPrice
			outJxOrder.ActualPayPrice = outJxOrder.TotalPrice
		}
		if jxOrder.UserID != "" {
			outJxOrder.UserID = jxOrder.UserID
		}
	} else {
		outJxOrder = nil
		deliveryAddress = nil
	}

	if IsDeliverySelf {
		outJxOrder.FreightPrice = 0
	}

	return outJxOrder, deliveryAddress, err
}

//根据销量限制门店申请袋子数，现暂不使用该判断，万一以后要用就先没删
func matterSkusLimited(skus []*JxSkuInfo, storeID int) (err error) {
	result, err := orderman.GetMatterStoreOrderCount(nil, storeID)
	sum := 0
	if result.Count != 0 {
		for _, sku := range skus {
			if sku.SkuID == 6039382 {
				sum1 := 0
				if bagMap[sku.SkuID] != 0 {
					sum1 += bagMap[sku.SkuID] * sku.Count
					sum += sum1
				}
				if utils.Int2Float64(sum1/100) >= math.Ceil(utils.Int2Float64(result.Count)/100) {
					return fmt.Errorf("订单100个一份背心袋订购数量过多，请按照实际销量购买！，大概销量：[%v]，购买数量：[%v]", result.Count, sum1)
				}
			}
			if sku.SkuID == 6039383 || sku.SkuID == 6039384 || sku.SkuID == 6039387 || sku.SkuID == 6039390 {
				sum2 := 0
				if bagMap[sku.SkuID] != 0 {
					sum2 += bagMap[sku.SkuID] * sku.Count
					sum += sum2
				}
				if utils.Int2Float64(sum2/200) >= math.Ceil(utils.Int2Float64(result.Count)/200) {
					return fmt.Errorf("订单200个一份背心袋订购数量过多，请按照实际销量购买！，大概销量：[%v]，购买数量：[%v]", result.Count, sum2)
				}
			}
		}
		if sum-result.Count > 100 {
			return fmt.Errorf("订单背心袋订购数量过多，请按照实际销量购买！，大概销量：[%v]，购买数量：[%v]", result.Count, sum)
		}
	}
	return err
}

func jxOrder2GoodsOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, deliveryAddress *dao.UserDeliveryAddressEx, userID string, IsDeliverySelf bool, couponIDs []int) (order *model.GoodsOrder, err error) {
	order = &model.GoodsOrder{
		VendorOrderID: utils.Int64ToStr(jxOrder.OrderID),
		VendorID:      model.VendorIDJX,
		VendorStoreID: utils.Int2Str(jxOrder.StoreID),
		StoreID:       jxOrder.StoreID,
		StoreName:     jxOrder.StoreName,
		// UserID:        ctx.GetUserID(),

		ConsigneeName:    deliveryAddress.ConsigneeName,
		ConsigneeMobile:  deliveryAddress.ConsigneeMobile,
		ConsigneeMobile2: deliveryAddress.ConsigneeMobile,
		ConsigneeAddress: fmt.Sprintf("%s%s", deliveryAddress.Address, deliveryAddress.DetailAddress),
		CoordinateType:   model.CoordinateTypeMars,
		ConsigneeLng:     jxutils.StandardCoordinate2Int(deliveryAddress.Lng),
		ConsigneeLat:     jxutils.StandardCoordinate2Int(deliveryAddress.Lat),

		Status:       model.OrderStatusUnknown,
		VendorStatus: "realnew",
		OrderSeq:     0,
		BuyerComment: jxOrder.BuyerComment,

		DeliveryType:   model.OrderDeliveryTypeStoreSelf,
		StatusTime:     time.Now(),
		EarningType:    jxOrder.EarningType,
		OrderType:      jxOrder.OrderType,
		VendorOrderID2: jxOrder.OrderID2,
	}
	orderSeq, _ := dao.GetVendorOrderNumber(dao.GetDB(), model.VendorIDJX, order.VendorStoreID)
	order.OrderSeq = orderSeq + 1

	if len(couponIDs) > 0 {
		strCounponIDs := []string{}
		for _, v := range couponIDs {
			strCounponIDs = append(strCounponIDs, utils.Int2Str(v))
		}
		order.CouponIDs = strings.Join(strCounponIDs, ",")
	}
	if userID == "" {
		order.UserID = ctx.GetUserID()
	} else {
		order.UserID = userID
	}
	order.OrderCreatedAt = order.StatusTime
	order.VendorUserID = order.UserID
	if order.UserID == "" && order.VendorUserID == "" {
		if jxOrder.UserID != "" {
			order.UserID = jxOrder.UserID
			order.VendorUserID = jxOrder.UserID
		}
	}
	if jxOrder.ExpectedDeliveredTimestamp != 0 {
		order.ExpectedDeliveredTime = utils.Timestamp2Time(jxOrder.ExpectedDeliveredTimestamp)
		order.BusinessType = model.BusinessTypeDingshida
	} else {
		order.ExpectedDeliveredTime = order.OrderCreatedAt.Add(time.Hour)
		order.BusinessType = model.BusinessTypeImmediate
	}
	for _, sku := range jxOrder.Skus {
		order.Skus = append(order.Skus, &model.OrderSku{
			Count:       sku.Count,
			VendorSkuID: utils.Int2Str(sku.SkuID),
			SkuID:       sku.SkuID,
			SkuName:     sku.Name,
			VendorPrice: sku.Price,
			SalePrice:   sku.SalePrice,
		})
		order.TotalShopMoney += int64(sku.Count) * sku.SalePrice
	}
	order.TotalShopMoney += jxOrder.FreightPrice
	order.ActualPayPrice = jxOrder.ActualPayPrice
	order.TotalShopMoney = utils.Float64TwoInt64(float64(order.TotalShopMoney) * jdshopapi.JdsPayPercentage)
	if jxOrder.FromStoreID != 0 {
		order.FromStoreID = jxOrder.FromStoreID
		order.DeliveryFlag = model.OrderDeliveryFlagMaskScheduleDisabled
		order.Flag = 1
		if jxOrder.OrderType == model.OrderTypeMatter {
			order.WaybillVendorID = model.VendorIDJDWL
			order.ConsigneeAddress = fmt.Sprintf("%s%s", deliveryAddress.Address, deliveryAddress.DetailAddress)
		}
	}
	//如果是自提单就设置
	if IsDeliverySelf {
		order.DeliveryType = model.OrderDeliveryTypeSelfTake
	}

	store, _ := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
	order.PackagePrice = store.PackageSetting
	return order, err
}

func AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
	var status int
	if isAcceptIt {
		status = model.OrderStatusAccepted
	} else {
		status = model.OrderStatusCanceled
	}
	return changeOrderStatus(order.VendorOrderID, status, "")
}

func AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
	return err
}

func PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
	err = changeOrderStatus(order.VendorOrderID, model.OrderStatusFinishedPickup, "")
	//如果是物料订单则直接进行京东物流的发单，并且状态直接变为配送中
	//如果是进货的订单，直接变为配送中
	if order.OrderType != model.OrderTypeNormal {
		err = orderSolutionForWuLiao(order)
	}
	return err
}

func orderSolutionForWuLiao(order *model.GoodsOrder) (err error) {
	err = changeOrderStatus(order.VendorOrderID, model.OrderStatusDelivering, "")
	if order.OrderType == model.OrderTypeMatter {
		var (
			db = dao.GetDB()
		)
		goods, err := dao.QueryOrders(db, order.VendorOrderID, -1, []int{model.VendorIDJX}, -1, utils.ZeroTimeValue, utils.ZeroTimeValue)
		if err != nil || len(goods) == 0 {
			return err
		}
		order.WaybillVendorID = model.VendorIDJDWL
		dao.UpdateEntity(db, order, "WaybillVendorID")
		orderSkus := goods[0].Skus
		if order.Weight <= splitMatterOrderMinWeight { //2020-04-26, 从5kg 改为小于4.5kg
			var (
				goodsNos   []string
				prices     []string
				quantities []string
				countSum   int
			)
			for _, v := range orderSkus {
				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))
				countSum += v.Count
			}
			//总订单不足3kg && 商品数量不足3个 && 五香粉有库存，要送五香粉，补足3个
			stockResult, err := api.JdEclpAPI.QueryStock(jxwxfMatterEclpID)
			if err == nil && len(stockResult) > 0 && stockResult[0].UsableNum > 0 {
				if order.Weight < 3000 && countSum < 3 {
					//要判断他本身买没买五香粉EMG4418113943423
					var index = 9999
					for k, v := range goodsNos {
						if v == jxwxfMatterEclpID {
							index = k
						}
					}
					//说明他买了五香粉
					if index != 9999 {
						quantities[index] = utils.Int2Str(utils.Str2Int(quantities[index]) + 3 - countSum)
					} else {
						goodsNos = append(goodsNos, jxwxfMatterEclpID)
						prices = append(prices, "0")
						quantities = append(quantities, utils.Int2Str(3-countSum))
					}
				}
			}
			//TODO 2021-10-21 物料暂时不发京东配送，后续如果要发把下面注释放开就行了
			//result, err := api.JdEclpAPI.AddOrder(&jdeclpapi.AddOrderParam{
			//	IsvUUID:              order.VendorOrderID,
			//	IsvSource:            jdeclpapi.IsvSource,
			//	ShopNo:               jdeclpapi.ShopNo,
			//	DepartmentNo:         jdeclpapi.DepartmentNo,
			//	ShipperNo:            jdeclpapi.ShipperNo,
			//	WarehouseNo:          jdeclpapi.WarehouseNo,
			//	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, ","),
			//})
			//if err != nil {
			//	return err
			//}
			//order.EclpOutID = result
			dao.UpdateEntity(db, order, "EclpOutID")
			waybill := &model.Waybill{
				VendorOrderID:     order.VendorOrderID,
				OrderVendorID:     model.VendorIDJX,
				VendorWaybillID:   order.EclpOutID,
				WaybillVendorID:   model.VendorIDJDWL,
				Status:            model.WaybillStatusDelivering,
				WaybillCreatedAt:  time.Now(),
				StatusTime:        time.Now(),
				WaybillFinishedAt: utils.DefaultTimeValue,
				DeliveryFlag:      model.OrderDeliveryFlagMaskScheduleDisabled,
			}
			dao.CreateEntity(db, waybill)
		} else { //如果重量超过5kg则需要进行拆单分包，商品分包规则。最后一个包不超过5kg,其他包不超过3kg ,收到发单,不需要分包裹了
			//outOrders, _, _ := tryToSplitMatterOrder(buildJxOrderInfo(order, orderSkus))
			////以下为仿照CreateOrder，改了一些参数
			//for k, v := range outOrders {
			//	v.OrderType = model.OrderTypeMatter
			//	v.FromStoreID = order.FromStoreID
			//	outJxOrder, deliveryAddress, err := generateOrder(jxcontext.AdminCtx, v, order.AddressID, order.FromStoreID, order.UserID, false, nil)
			//	if err != nil {
			//		return err
			//	}
			//	//分包后的子订单ID默认是原订单ID后面加两位（目前的规则），要改的话要注意取消订单那的判断
			//	outJxOrder.OrderID = utils.Str2Int64(order.VendorOrderID)*100 + int64(k+1)
			//	checkMatterDeliveryAddress(deliveryAddress)
			//	order2, err2 := jxOrder2GoodsOrder(jxcontext.AdminCtx, outJxOrder, deliveryAddress, order.UserID, false, nil)
			//	if err = err2; err == nil {
			//		order2.FromStoreID = v.FromStoreID
			//		order2.AddressID = order.AddressID
			//		order2.Status = model.OrderStatusDelivering
			//		err = partner.CurOrderManager.OnOrderNew(order2, model.Order2Status(order2))
			//		orderSolutionForWuLiao(order2)
			//	}
			//}
			////刷新一下库存
			//for _, v := range goods[0].Skus {
			//	cms.RefreshMatterStock(jxcontext.AdminCtx, v.SkuID)
			//}
		}
		for _, v := range order.Skus {
			if bagSkuMap[v.SkuID] != 0 {
				stores, _ := dao.GetStoreList(db, []int{order.FromStoreID}, nil, nil, nil, nil, "")
				if len(stores) > 0 {
					store := stores[0]
					store.IsBoughtMatter = model.YES
					dao.UpdateEntity(db, store, "IsBoughtMatter")
				}
			}
		}
	}
	return err
}

func SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
	return changeOrderStatus(order.VendorOrderID, model.OrderStatusDelivering, "")
}

func SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
	return changeOrderStatus(order.VendorOrderID, model.OrderStatusFinished, "")
}

func CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
	if true { //order.Status < model.OrderStatusDelivering {
		errList := errlist.New()
		db := dao.GetDB()
		payList, err2 := dao.GetOrderPayList(db, order.VendorOrderID, jxutils.GetPossibleVendorIDFromVendorOrderID(order.VendorOrderID))
		if err = err2; err == nil {
			for _, orderPay := range payList {
				if orderPay.Status == model.PayStatusYes {
					// refundID := utils.Int64ToStr(GenRefundID(order))
					refundID := order.VendorOrderID
					var orderPayRefund *model.OrderPayRefund
					switch orderPay.PayType {
					case model.PayTypeWX:
						orderPayRefund, err = refundOrderByWX(ctx, orderPay, refundID, orderPay.TotalFee, reason)
						if err == nil {
							dao.WrapAddIDCULDEntity(orderPayRefund, ctx.GetUserName())
							errList.AddErr(dao.CreateEntity(dao.GetDB(), orderPayRefund))
						} else {
							errList.AddErr(err)
						}
					case model.PayTypeTL:
						orderPayRefund, err = RefundOrderByTL(ctx, orderPay, refundID, orderPay.TotalFee, reason)
						if err != nil {
							errList.AddErr(err)
						}
					case model.PayTypeTicTok:
						orderPayRefund, err = RefundOrderByTT(ctx, orderPay, refundID, orderPay.TotalFee, reason)
						if err != nil {
							errList.AddErr(err)
						}
					case model.PayTypeKuaiShou:
						orderPayRefund, err = RefundOrderByKS(ctx, orderPay, refundID, orderPay.TotalFee, reason)
						if err != nil {
							errList.AddErr(err)
						}
					}

					if err == nil {
						//如果用了优惠券，状态要刷回去
						if order.CouponIDs != "" {
							sCouponIDs := strings.Split(order.CouponIDs, ",")
							couponIDs := []int{}
							for _, v := range sCouponIDs {
								couponIDs = append(couponIDs, utils.Str2Int(v))
							}
							if userCoupons, err := dao.GetUserCoupons(db, couponIDs, []string{order.UserID}, nil, model.CouponStatusNormal); err == nil {
								for _, vv := range userCoupons {
									vv.UserCouponStatus = model.CouponStatusNormal
									vv.UpdatedAt = time.Now()
									dao.UpdateEntity(db, vv, "UserCouponStatus", "UpdatedAt")
								}
							}
						}
						MarkArrears(db, order, orderPay)
						err2 := CancelMatterOrder(db, order, reason)
						errList.AddErr(err2)
					}
				} else {
					orderPay.Status = model.PayStatusCanceled
					_, err2 := dao.UpdateEntity(db, orderPay)
					errList.AddErr(err2)
				}
			}
		} else if dao.IsNoRowsError(err) {
			err = nil
		} else {
			errList.AddErr(err)
		}
		if errList.GetErrListAsOne() == nil {
			errList.AddErr(changeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, reason))
		}
		err = errList.GetErrListAsOne()
		if len(payList) == 0 {
			err = CancelMatterOrder(db, order, "")
		}
	} else {
		err = fmt.Errorf("当前订单状态:%s不允许取消", model.OrderStatusName[order.Status])
	}
	return err
}

func CancelMatterOrder(db *dao.DaoDB, order *model.GoodsOrder, reason string) (err error) {
	// if order.FromStoreID != 0 {
	if order.OrderType == model.OrderTypeMatter {
		if order.EclpOutID != "" {
			//表示是京西的物料订单的子订单（拆分后的订单）
			if len(order.VendorOrderID) == 16 && order.VendorID == model.VendorIDJX {
				return fmt.Errorf("不允许取消该子订单，请取消主订单进行退货退款！主订单ID :[%v]", order.VendorOrderID[:len(order.VendorOrderID)-2])
			}
			_, err = api.JdEclpAPI.CancelOrder(order.EclpOutID)
		} else {
			goodsList, err := dao.GetMatterChildOrders(db, order.VendorOrderID)
			if err == nil && len(goodsList) > 0 {
				for _, v := range goodsList {
					_, err = api.JdEclpAPI.CancelOrder(v.EclpOutID)
					changeOrderStatus(v.VendorOrderID, model.OrderStatusCanceled, reason)
				}
			}
		}
		stores, _ := dao.GetStoreList(db, []int{order.FromStoreID}, nil, nil, nil, nil, "")
		if len(stores) > 0 {
			//如果这周还买过其他物料，则不刷新是否购买标志
			var (
				orderPays []*model.OrderPay
				day       int
			)
			sql := `
				SELECT b.*
				FROM goods_order a
				JOIN order_pay b ON a.vendor_order_id = b.vendor_order_id
				WHERE IF(a.store_id = 0, a.jx_store_id, a.store_id) = 666666
				AND a.from_store_id = ?
				AND a.status >= ? AND a.status <> ?
				AND b.status = ?
				AND b.pay_finished_at <= NOW() AND b.pay_finished_at >= ?
			`
			weekInt := int(time.Now().Weekday())
			if weekInt == 0 {
				day = 7
			} else {
				day = weekInt
			}
			lastTime := utils.Str2Time(time.Now().AddDate(0, 0, -(day-1)).Format("2006-01-02") + " 01:00:00")
			sqlParams := []interface{}{order.FromStoreID, model.OrderStatusDelivering, model.OrderStatusCanceled, model.PayStatusYes, lastTime}
			err = dao.GetRows(db, &orderPays, sql, sqlParams)
			if len(orderPays) == 0 {
				store := stores[0]
				store.IsBoughtMatter = model.NO
				dao.UpdateEntity(db, store, "IsBoughtMatter")
			}
		}
	}
	return err
}

func MarkArrears(db *dao.DaoDB, order *model.GoodsOrder, orderPay *model.OrderPay) {
	//退款后，若此订单下单用户有推广人，则需要将分给推广人的金额记录到该推广人的欠款中
	orders, _ := dao.QueryOrders(db, order.VendorOrderID, 0, []int{model.VendorIDJX}, 0, utils.DefaultTimeValue, utils.DefaultTimeValue)
	if len(orders) > 0 {
		user, _ := dao.GetUserByID(db, "user_id", orders[0].UserID)
		if user.ParentMobile != "" {
			user2, _ := dao.GetUserByID(db, "mobile", user.ParentMobile)
			user2.Arrears = user2.Arrears + (orderPay.TotalFee * user2.DividePercentage / 100)
			dao.UpdateEntity(db, user2, "Arrears")
			if user2.ParentMobile != "" {
				user3, _ := dao.GetUserByID(db, "mobile", user2.ParentMobile)
				user3.Arrears = user3.Arrears + ((orderPay.TotalFee - user2.Arrears) * user3.DividePercentage / 100)
				dao.UpdateEntity(db, user3, "Arrears")
			}
		}
	}
}

func AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string,refundParam interface{}) (err error) {
	if isAgree {
		err = CancelOrder(ctx, order, reason)
	} else {
		err = changeOrderStatus(order.VendorOrderID, model.OrderStatusVendorRejectCancel, reason)
	}
	return err
}

// todo 消息用异步可能导致丢失，单同步又有重入相关的问题
func callNewOrder(order *model.GoodsOrder) (err error) {
	jxutils.CallMsgHandlerAsync(func() {
		err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
	}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, model.VendorIDJX))
	return err
}

func changeOrderStatus(vendorOrderID string, status int, remark string) (err error) {
	orderStatus := &model.OrderStatus{
		VendorOrderID:    vendorOrderID,
		VendorID:         model.VendorIDJX,
		OrderType:        model.OrderTypeOrder,
		RefVendorOrderID: vendorOrderID,
		RefVendorID:      model.VendorIDJX,
		VendorStatus:     utils.Int2Str(status),
		Status:           status,
		StatusTime:       time.Now(),
		Remark:           remark,
	}
	jxutils.CallMsgHandlerAsync(func() {
		err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
	}, jxutils.ComposeUniversalOrderID(vendorOrderID, model.VendorIDJX))
	return err
}

func GetOrderPay(ctx *jxcontext.Context, vendorOrderID string) (payList []*model.OrderPay, err error) {
	db := dao.GetDB()
	payList, err = dao.GetOrderPayList(db, vendorOrderID, jxutils.GetPossibleVendorIDFromVendorOrderID(vendorOrderID))
	return payList, err
}

func PayForPopluarMan(ctx *jxcontext.Context, vendorOrderID, userID string, price int) (err error) {
	db := dao.GetDB()
	user, err := dao.GetUserByID(db, "user_id", userID)
	if user == nil {
		return fmt.Errorf("未找到此用户！用户ID：[%v]\n", userID)
	}
	auth, err := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{"weixinmini"}, "", "", []string{"wx4b5930c13f8b1170"})
	if len(auth) == 0 {
		return fmt.Errorf("未找到此用户的微信验证方式！用户ID：[%v]\n", userID)
	}
	goods, err := dao.QueryOrders(db, vendorOrderID, 0, []int{model.VendorIDJX}, 0, utils.ZeroTimeValue, utils.ZeroTimeValue)
	if len(goods) == 0 {
		return fmt.Errorf("未找到此订单！订单ID：[%v]\n", vendorOrderID)
	}
	param := &wxpayapi.TransfersParam{
		CheckName:      wxpayapi.CheckName,
		PartnerTradeNo: vendorOrderID,
		Desc:           "每日推广人订单分成分到个人",
		SpbillCreateIP: ctx.GetRealRemoteIP(),
		OpenID:         auth[0].AuthID,
		Amount:         price,
	}
	_, err = api.WxpayAPI.Transfers(param)
	return err
}

//自动打款给市场推广人
func AutoPayForPopluarMan(ctx *jxcontext.Context) (err error) {
	var (
		errMsg      string
		errCode     string
		db          = dao.GetDB()
		fromDateStr = time.Now().AddDate(0, 0, -1).Format("2006-1-2") + " 00:00:00"
		toDateStr   = time.Now().AddDate(0, 0, -1).Format("2006-1-2") + " 23:59:59"
		mapResult   = make(map[string]interface{})
	)
	result, err := dao.GetOrdersForJxPay(db, utils.Str2Time(fromDateStr), utils.Str2Time(toDateStr))
	for _, goods := range result {
		var (
			param = &wxpayapi.TransfersParam{
				CheckName:      wxpayapi.CheckName,
				Desc:           "每日推广人订单分成分到个人",
				SpbillCreateIP: ctx.GetRealRemoteIP(),
			}
			payPrice1 int
			payPrice2 int
		)
		user, err := dao.GetUserByID(db, "user_id", goods.UserID)
		if user.ParentMobile == "" {
			return err
		}
		user2, err := dao.GetUserByID(db, "mobile", user.ParentMobile)
		auths, err := dao.GetUserBindAuthInfo(db, user2.UserID, model.AuthBindTypeAuth, []string{"weixinmini"}, "", "", []string{"wx4b5930c13f8b1170"})
		if err != nil {
			return err
		}
		if len(auths) == 0 {
			errMsg += fmt.Sprintf("打款失败！未找到此用户的微信验证方式！订单号：[%v]，用户ID：[%v]\n", goods.VendorOrderID, user2.UserID)
		} else {
			var openID string
			for _, auth := range auths {
				if auth.TypeID == wxAppID {
					openID = auth.AuthID
				}
			}
			payPrice1 = int(goods.ActualPayPrice) * user2.DividePercentage / 100
			//表示这个人之前有欠款，意思是取消订单退款时，这个推广人的分成收不回来，算作欠款，打钱的时候要扣除
			//表示这个人之前有小于3毛钱的款没有打（微信付款api付款最低3毛），记录下来加到以后的款项中
			rPrice := payPrice1 - user2.Arrears + user2.Profit
			err = updateUserAndTransfers(db, param, user2, openID, rPrice)
			if err != nil {
				errMsg += err.Error()
			}
			mapResult["打款人1"] = user2.Name
			mapResult["打款人金额1"] = rPrice
			mapResult["打款人电话1"] = user2.Mobile
			mapResult["打款人1userID"] = user2.UserID
		}
		if user2.ParentMobile != "" {
			user3, err := dao.GetUserByID(db, "mobile", user2.ParentMobile)
			auths, err := dao.GetUserBindAuthInfo(db, user3.UserID, model.AuthBindTypeAuth, []string{"weixinmini"}, "", "", []string{"wx4b5930c13f8b1170"})
			if err != nil {
				return err
			}
			if len(auths) == 0 {
				errMsg += fmt.Sprintf("打款失败！未找到此用户的微信验证方式！订单号：[%v]，用户ID：[%v]\n", goods.VendorOrderID, user3.UserID)
			} else {
				var openID string
				for _, auth := range auths {
					if auth.TypeID == wxAppID {
						openID = auth.AuthID
					}
				}
				payPrice2 = (int(goods.ActualPayPrice) - payPrice1) * user3.DividePercentage / 100
				rPrice := payPrice2 - user3.Arrears + user3.Profit
				err = updateUserAndTransfers(db, param, user3, openID, rPrice)
				if err != nil {
					errMsg += err.Error()
				}
				mapResult["打款人2"] = user3.Name
				mapResult["打款人金额2"] = rPrice
				mapResult["打款人电话2"] = user3.Mobile
				mapResult["打款人2userID"] = user3.UserID
			}
		}
	}
	user, _ := dao.GetUserByID(dao.GetDB(), "mobile", "18160030913")
	if user != nil && errMsg != "" {
		ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "每日打款错误", errMsg)
	}
	if err != nil || errMsg != "" {
		errMsg += err.Error()
		errCode = model.ErrCodeGeneralFailed
	} else {
		errCode = model.ErrCodeSuccess
	}
	err = event.AddOperateEvent(ctx, ctx.GetTrackInfo(), cms.BuildDiffData(mapResult), errCode, errMsg, 0, "AutoPayForPopluarMan")
	return err
}

func updateUserAndTransfers(db *dao.DaoDB, param *wxpayapi.TransfersParam, user *model.User, authID string, rPrice int) (err error) {
	if rPrice >= 30 {
		param.OpenID = authID
		param.Amount = rPrice
		param.PartnerTradeNo = utils.GetUUID()
		_, err = api.WxpayAPI.Transfers(param)
		user.ProfitSum = user.ProfitSum + rPrice
		user.Profit = 0
		user.Arrears = 0
	} else if rPrice >= 0 && rPrice < 30 {
		user.Profit = rPrice
		user.Arrears = 0
	} else {
		user.Profit = 0
		user.Arrears = int(utils.Float64TwoInt64(math.Abs(utils.Int2Float64(rPrice))))
	}
	_, err = dao.UpdateEntity(db, user, "ProfitSum", "Profit", "Arrears")
	return err
}

func CancelPayTimeOutOrder(ctx *jxcontext.Context) (err error) {
	db := dao.GetDB()
	var orders []*model.GoodsOrder
	sql := `
		SELECT *
		  FROM goods_order 
		 WHERE order_created_at >= ? AND order_created_at <= NOW()
		   AND status = ?
		   AND vendor_id = ? 
	`
	sqlParams := []interface{}{
		time.Now().Add(-time.Minute * 30),
		model.OrderStatusWait4Pay,
		model.VendorIDJX,
	}
	err = dao.GetRows(db, &orders, sql, sqlParams)
	for _, v := range orders {
		if v.OrderCreatedAt.Add(PayWaitingTime).Before(time.Now()) {
			err2 := changeOrderStatus(v.VendorOrderID, model.OrderStatusCanceled, autoCancelOrderReason)
			err = err2
		}
	}
	return err
}

func GetHalfHoursList() (strs []string) {
	for k := 0; k < 3; k++ {
		for i := 0; i < 10; i++ {
			for j := 0; j < 4; j += 3 {
				if k == 2 && i > 3 {
					break
				}
				strs = append(strs, utils.Int2Str(k)+utils.Int2Str(i)+":"+utils.Int2Str(j)+"0"+":00")
			}
		}
	}
	return strs
}

func GetDiscountActHoursList() (str []string) {
	for k := 1; k < 3; k++ {
		for i := 0; i < 10; i++ {
			for j := 0; j < 6; j++ {
				if k == 1 && i == 0 && j == 0 {
					continue
				}
				if k == 2 && i > 2 {
					break
				}
				if k == 2 && i == 2 && j > 0 {
					break
				}
				str = append(str, utils.Int2Str(k)+utils.Int2Str(i)+":"+utils.Int2Str(j)+"0"+":00")
			}
		}
	}
	return str
}

func RefreshAllMatterOrderStatus(ctx *jxcontext.Context) (err error) {
	var (
		db        = dao.GetDB()
		goodsList []*model.GoodsOrder
		realTime  time.Time
	)
	realTime = time.Now().AddDate(0, 0, -7)
	//有分包的主订单
	sql := `
		SELECT * FROM goods_order WHERE store_id = 666666 AND order_created_at >= ? AND status < ? AND vendor_id = ? AND LENGTH(vendor_order_id) = 14
	`
	sqlParams := []interface{}{realTime, model.OrderStatusEndBegin, model.VendorIDJX}
	err = dao.GetRows(db, &goodsList, sql, sqlParams)
	for _, v := range goodsList {
		if v.EclpOutID == "" {
			var (
				goodsList2      []*model.GoodsOrder
				cancelCount     int
				deliveringCount int
			)
			sql2 := "SELECT * FROM goods_order WHERE vendor_order_id LIKE ? OR vendor_order_id LIKE ? AND vendor_id = ? AND eclp_out_id <> '' AND LENGTH(vendor_order_id) = 16"
			sqlParams2 := []interface{}{v.VendorOrderID + "0%", v.VendorOrderID + "1%", model.VendorIDJX}
			err = dao.GetRows(db, &goodsList2, sql2, sqlParams2)
			for _, vv := range goodsList2 {
				if vv.Status < model.OrderStatusFinished {
					queryOrderStatus, err := api.JdEclpAPI.QueryOrderStatus(vv.EclpOutID)
					if err != nil || queryOrderStatus == nil {
						continue
					}
					if len(queryOrderStatus.OrderStatusList) > 0 {
						if queryOrderStatus.OrderStatusList[len(queryOrderStatus.OrderStatusList)-1].SoStatusCode == jdeclpapi.SoStatusCode10034 {
							txDB, _ := dao.Begin(db)
							defer func() {
								if r := recover(); r != nil {
									dao.Rollback(db, txDB)
									panic(r)
								}
							}()
							vv.Status = model.OrderStatusFinished
							dao.UpdateEntity(db, vv, "Status")
							waybills, err := dao.GetWaybills(db, vv.VendorOrderID, nil)
							if err == nil && len(waybills) > 0 {
								waybills[0].Status = model.WaybillStatusDelivered
								dao.UpdateEntity(db, waybills[0], "Status")
							}
							dao.Commit(db, txDB)
							changeOrderStatus(vv.VendorOrderID, model.OrderStatusFinished, "")
							getTrackMessagePlusByOrderResult, _ := api.JdEclpAPI.GetTrackMessagePlusByOrder(vv.VendorOrderID)
							updateJdWayBillInfo(db, vv, getTrackMessagePlusByOrderResult)
						} else {
							deliveringCount++
						}
					}
				} else if vv.Status == model.OrderStatusCanceled {
					cancelCount++
				}
			}
			if len(goodsList2) > 0 {
				txDB, _ := dao.Begin(db)
				defer func() {
					if r := recover(); r != nil {
						dao.Rollback(db, txDB)
						panic(r)
					}
				}()
				if deliveringCount == 0 {
					v.Status = model.OrderStatusFinished
				} else {
					if cancelCount == len(goodsList2) {
						v.Status = model.OrderStatusCanceled
					}
				}
				if v.Status < model.OrderStatusDelivering {
					v.Status = model.OrderStatusCanceled
				}
				dao.UpdateEntity(db, v, "Status")
				dao.Commit(db, txDB)
				changeOrderStatus(v.VendorOrderID, v.Status, "")
			}
		} else {
			queryOrderStatus, _ := api.JdEclpAPI.QueryOrderStatus(v.EclpOutID)
			getTrackMessagePlusByOrderResult, _ := api.JdEclpAPI.GetTrackMessagePlusByOrder(v.VendorOrderID)
			updateMatterOrderStatus(db, v, queryOrderStatus)
			updateJdWayBillInfo(db, v, getTrackMessagePlusByOrderResult)
		}
	}
	return err
}

func GetMatterOrderStatus(ctx *jxcontext.Context, vendorOrderID string) (result []*MatterOrderStatus, err error) {
	var (
		db = dao.GetDB()
	)
	order, err := dao.GetSimpleOrder(db, vendorOrderID)
	if err != nil {
		return nil, err
	}
	if order.EclpOutID == "" {
		return nil, err
	}
	queryOrderStatus, err := api.JdEclpAPI.QueryOrderStatus(order.EclpOutID)
	getTrackMessagePlusByOrderResult, err := api.JdEclpAPI.GetTrackMessagePlusByOrder(vendorOrderID)
	if err != nil || queryOrderStatus == nil {
		return nil, err
	}
	if len(queryOrderStatus.OrderStatusList) > 0 {
		for _, v := range queryOrderStatus.OrderStatusList {
			matter := &MatterOrderStatus{}
			matter.Time = utils.Str2Time(v.OperateTime)
			matter.Status = v.SoStatusName
			matter.Name = v.SoStatusName
			matter.Sign = 1
			result = append(result, matter)
		}
	}

	if len(getTrackMessagePlusByOrderResult.ResultData) > 0 {
		for _, vv := range getTrackMessagePlusByOrderResult.ResultData {
			matter := &MatterOrderStatus{}
			matter.Time = utils.Str2Time(strings.ReplaceAll(vv.OpeTime, "/", "-"))
			matter.Status = vv.OpeTitle
			matter.Name = vv.OpeRemark
			matter.Sign = 2
			result = append(result, matter)
		}
	}
	for i := 0; i < len(result)-1; i++ {
		for j := 0; j < len(result)-i-1; j++ {
			if result[j].Time.Unix() > result[j+1].Time.Unix() || (result[j].Time.Unix() == result[j+1].Time.Unix() && result[j].Sign > result[j+1].Sign) {
				tmp := result[j]
				result[j] = result[j+1]
				result[j+1] = tmp
			}
		}
	}
	if len(queryOrderStatus.OrderStatusList) > 0 {
		updateMatterOrderStatus(db, order, queryOrderStatus)
	}
	if len(getTrackMessagePlusByOrderResult.ResultData) > 0 {
		updateJdWayBillInfo(db, order, getTrackMessagePlusByOrderResult)
	}
	return result, err
}

func updateMatterOrderStatus(db *dao.DaoDB, order *model.GoodsOrder, queryOrderStatus *jdeclpapi.QueryOrderStatusResult) {
	code := queryOrderStatus.OrderStatusList[len(queryOrderStatus.OrderStatusList)-1].SoStatusCode
	if code == jdeclpapi.SoStatusCode10034 || code == jdeclpapi.SoStatusCode10038 {
		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				panic(r)
			}
		}()
		order.Status = model.OrderStatusFinished
		dao.UpdateEntity(db, order, "Status")
		waybills, err := dao.GetWaybills(db, order.VendorOrderID, nil)
		if err == nil && len(waybills) > 0 {
			waybills[0].Status = model.WaybillStatusDelivered
			dao.UpdateEntity(db, waybills[0], "Status")
		}
		dao.Commit(db, txDB)
		changeOrderStatus(order.VendorOrderID, model.OrderStatusFinished, "")
	}
}

func updateJdWayBillInfo(db *dao.DaoDB, order *model.GoodsOrder, getTrackMessagePlusByOrderResult *jdeclpapi.GetTrackMessagePlusByOrderResult) (err error) {
	var (
		waybillCode string
		cName       string
		cMobile     string
		waybills    []*model.Waybill
	)
	if len(getTrackMessagePlusByOrderResult.ResultData) > 0 {
		waybillCode = getTrackMessagePlusByOrderResult.ResultData[0].WaybillCode
	} else {
		return err
	}
	for _, vv := range getTrackMessagePlusByOrderResult.ResultData {
		if vv.OpeTitle == "配送员收货" {
			result := regexpCnameAndCmobile.FindAllStringSubmatch(vv.OpeRemark, -1)
			if len(result) > 0 {
				cName = result[0][1]
				cMobile = result[0][2]
			} else {
				result2 := regexpCnameAndCmobile2.FindAllStringSubmatch(vv.OpeRemark, -1)
				if len(result2) > 0 {
					cName = result2[0][1]
					cMobile = result2[0][2]
				}
			}
			break
		}
	}
	waybills, err = dao.GetWaybills(db, order.VendorOrderID, nil)
	if len(waybills) > 0 {
		waybills[0].VendorWaybillID = waybillCode
		waybills[0].CourierName = cName
		waybills[0].CourierMobile = cMobile
		order.VendorWaybillID = waybillCode
		order.WaybillVendorID = model.VendorIDJDWL
		dao.UpdateEntity(db, order, "VendorWaybillID", "WaybillVendorID")
		dao.UpdateEntity(db, waybills[0], "VendorWaybillID", "CourierName", "CourierMobile")
	}
	return err
}

func tryToSplitMatterOrder(jxOrder *JxOrderInfo) (outOrders []*JxOrderInfo, freightPrice int64, err error) {
	var (
		skus       = jxOrder.Skus
		weightList []*JxSkuInfo2
	)
	//我的思路为把所有商品依次按重量销量从大到小排列，然后第一个包尽量分出3kg，后面分出4.5kg
	//但是我把JxSkuInfo放进list的时候，想根据一个参数GroupSign判断是否这个商品已经分出去了
	//但是在list中同一个商品通过以下方式放进去的地址是一样的，我改了一个商品的GroupSign，所有的都变了，所以只有分出一个JxSkuInfo2去弄。。
	//要做优化的话更好
	for _, v := range skus {
		for i := 0; i < v.Count; i++ {
			var sku2 = &JxSkuInfo2{}
			sku2.Count = v.Count
			sku2.Name = v.Name
			sku2.Price = v.Price
			sku2.SalePrice = v.SalePrice
			sku2.Weight = v.Weight
			sku2.SkuID = v.SkuID
			weightList = append(weightList, sku2)
		}
	}
	for i := 0; i < len(weightList)-1; i++ {
		for j := 0; j < len(weightList)-i-1; j++ {
			if weightList[j].Weight < weightList[j+1].Weight {
				tmp := weightList[j]
				weightList[j] = weightList[j+1]
				weightList[j+1] = tmp
			}
		}
	}
	weight := jxOrder.Weight
	for {
		//每拿出一组就删掉list里的值
		outOrders = append(outOrders, loop2(weightList, jxOrder.StoreID, &weight))
		for i := 0; i < len(weightList); {
			if weightList[i].GroupSign {
				var weightList3 []*JxSkuInfo2
				weightList3 = append(weightList[:i], weightList[i+1:]...)
				weightList = weightList3
			} else {
				i++
			}
		}
		if len(weightList) == 0 {
			break
		}
	}
	for _, v := range outOrders {
		if v.Weight <= 3000 {
			freightPrice += 500
		} else if v.Weight > 3000 && v.Weight <= splitMatterOrderMinWeight {
			freightPrice += utils.Float64TwoInt64(500 + math.Ceil((utils.Int2Float64(v.Weight)-3000)/1000)*200)
		}
	}
	return outOrders, freightPrice, err
}

func jxOrderChange(sku2 *JxSkuInfo2) *JxSkuInfo {
	sku := &JxSkuInfo{}
	sku.Count = 1
	sku.Name = sku2.Name
	sku.Price = sku2.Price
	sku.SalePrice = sku2.SalePrice
	sku.SkuID = sku2.SkuID
	sku.Weight = sku2.Weight
	return sku
}

//TODO 修改为4.5kg 2020-04-2?
//商品分包规则2。最后一个包不超过5kg,其他包不超过3kg
// 举例1：5.1kg，分为 2.5kg,2.6kg,确保每个包不超过3kg,最后一个包不超过5kg
// 举例2：4kg,分为4kg
// 举例3：10kg，分为 3kg,3kg,4kg
// 举例4：8.1kg，分为 3kg,3kg,2.1kg ; 不能分为3kg,5.1kg
//sum3表示3kg的计算
func loop2(weightList []*JxSkuInfo2, storeID int, weight *int) (outOrder *JxOrderInfo) {
	outOrder = &JxOrderInfo{}
	outOrder.StoreID = storeID
	sum3 := 0
	if *weight <= splitMatterOrderMinWeight {
		for i := 0; i < len(weightList); i++ {
			buildOutOrderSkus(weightList[i], outOrder)
		}
	} else {
		for i := 0; i < len(weightList); i++ {
			if weightList[i].Weight+sum3 <= 3000 {
				sum3 += weightList[i].Weight
				*weight -= weightList[i].Weight
				buildOutOrderSkus(weightList[i], outOrder)
			} else {
				if sum3 >= 3000 {
					break
				}
				continue
			}
		}
	}
	return outOrder
}

func buildOutOrderSkus(weightp *JxSkuInfo2, outOrder *JxOrderInfo) {
	weightp.GroupSign = true
	outOrder.Weight += weightp.Weight
	if len(outOrder.Skus) > 0 {
		var flag = false
		for _, v := range outOrder.Skus {
			if v.SkuID == weightp.SkuID {
				v.Count++
				flag = true
			}
		}
		if !flag {
			outOrder.Skus = append(outOrder.Skus, jxOrderChange(weightp))
		}
	} else {
		outOrder.Skus = append(outOrder.Skus, jxOrderChange(weightp))
	}
}

func checkMatterDeliveryAddress(deliveryAddress *dao.UserDeliveryAddressEx) {
	var (
		db = dao.GetDB()
	)
	if !strings.Contains(deliveryAddress.Address, "区") {
		deliveryAddress.Address = deliveryAddress.DistrictName + deliveryAddress.Address
	}
	if !strings.Contains(deliveryAddress.Address, "市") {
		deliveryAddress.Address = deliveryAddress.CityName + deliveryAddress.Address
	}
	if !strings.Contains(deliveryAddress.Address, "省") {
		if place1, err := dao.GetPlaceByCode(db, deliveryAddress.CityCode); err == nil {
			if place2, err2 := dao.GetPlaceByCode(db, place1.ParentCode); err2 == nil {
				deliveryAddress.Address = place2.Name + deliveryAddress.Address
			}
		}
	}
}

func SendFailedMatterOrder(ctx *jxcontext.Context, vendorOrderID string) (err error) {
	var (
		db = dao.GetDB()
	)
	order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX)
	if err != nil {
		return err
	}
	if order == nil || order.StoreID != model.MatterStoreID || order.FromStoreID == 0 {
		return fmt.Errorf("只允许物料店重发物料订单调用此接口！")
	}
	err = CancelMatterOrder(db, order, cancelMatterOrderReason)
	// queryOrderStatus, err := api.JdEclpAPI.QueryOrderStatus(order.EclpOutID)
	// if len(queryOrderStatus.OrderStatusList) > 0 {
	// 	code := queryOrderStatus.OrderStatusList[len(queryOrderStatus.OrderStatusList)-1].SoStatusCode
	// 	if code == jdeclpapi.SoStatusCode10022 || code == jdeclpapi.SoStatusCode10038 { //表示该订单在京东物流为暂停或已经逆向发货完成
	childs, err := dao.GetMatterChildOrders(db, vendorOrderID)
	if len(childs) > 0 {
		goodsList, err := dao.GetMatterChildOrders(db, order.VendorOrderID)
		if err != nil {
			return err
		}
		if len(goodsList) > 0 {
			for _, v := range goodsList {
				cOrder, err := partner.CurOrderManager.LoadOrder(v.VendorOrderID, model.VendorIDJX)
				if err != nil {
					return err
				}
				suffix := utils.Str2Int64(cOrder.VendorOrderID[len(cOrder.VendorOrderID)-2:]) + int64(len(goodsList))
				_, err = createMatterOrder(buildJxOrderInfo(cOrder, cOrder.Skus), order, suffix)
				for _, v := range cOrder.Skus {
					cms.RefreshMatterStock(jxcontext.AdminCtx, v.SkuID)
				}
			}
		}
		changeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, cancelMatterOrderReason)
	} else {
		_, err = createMatterOrder(buildJxOrderInfo(order, order.Skus), order, int64(01))
		if err != nil {
			return err
		}
		changeOrderStatus(order.VendorOrderID, model.OrderStatusCanceled, cancelMatterOrderReason)
		for _, v := range order.Skus {
			cms.RefreshMatterStock(jxcontext.AdminCtx, v.SkuID)
		}
	}
	// if len(order.VendorOrderID) == 14 && order.EclpOutID != "" { //这是不分包的订单

	// } else if len(order.VendorOrderID) == 14 && order.EclpOutID == "" { //这是分包的主订单

	// } else if len(order.VendorOrderID) == 16 && order.EclpOutID != "" { // 这是分包的子订单
	// 	return fmt.Errorf("请重发主订单！主订单号：[%v]", order.VendorOrderID[len(order.VendorOrderID)-2:])
	// }
	// 	} else {
	// 		return fmt.Errorf("只允许物流订单为暂停或逆向完成才能调用此接口！")
	// 	}
	// }
	return err
}

func createMatterOrder(jxOrder *JxOrderInfo, order *model.GoodsOrder, newOrderIDSuffix int64) (order2 *model.GoodsOrder, err error) {
	outJxOrder, deliveryAddress, err := generateOrder(jxcontext.AdminCtx, jxOrder, order.AddressID, order.FromStoreID, order.UserID, false, nil)
	if err != nil {
		return nil, err
	}
	outJxOrder.OrderID = utils.Str2Int64(order.VendorOrderID)*100 + newOrderIDSuffix
	checkMatterDeliveryAddress(deliveryAddress)
	order2, err2 := jxOrder2GoodsOrder(jxcontext.AdminCtx, outJxOrder, deliveryAddress, order.UserID, false, nil)
	if err = err2; err == nil {
		order2.AddressID = order.AddressID
		order2.Status = model.OrderStatusDelivering
		err = partner.CurOrderManager.OnOrderNew(order2, model.Order2Status(order2))
		err = orderSolutionForWuLiao(order2)
	}
	return order2, err
}

func buildJxOrderInfo(order *model.GoodsOrder, orderSkus []*model.OrderSku) (jxOrder *JxOrderInfo) {
	jxOrder = &JxOrderInfo{}
	jxOrder.StoreID = order.StoreID
	weight := 0
	var skus []*JxSkuInfo
	for _, v := range orderSkus {
		weight += v.Weight * v.Count
		sku := &JxSkuInfo{}
		sku.SkuID = v.SkuID
		sku.SalePrice = v.SalePrice
		sku.Name = v.SkuName
		sku.Weight = v.Weight
		sku.Count = v.Count
		skus = append(skus, sku)
	}
	jxOrder.Skus = skus
	jxOrder.Weight = weight
	jxOrder.OrderType = model.OrderTypeMatter
	return jxOrder
}

func GetSupplySupportStoreSkus(ctx *jxcontext.Context, fromDate, toDate string, fromStoreID, storeID int, percentage string) (orderSkus []*dao.GetSupplySupportStoreSkusResult, err error) {
	var (
		db = dao.GetDB()
	)
	orderSkus, err = dao.GetSupplySupportStoreSkus(db, utils.Str2Time(fromDate), utils.Str2Time(toDate), fromStoreID, storeID, utils.Str2Float64(percentage))
	return orderSkus, err
}

func CreateOrderByPriceDefend(ctx *jxcontext.Context) (err error) {
	var (
		db           = dao.GetDB()
		userOrderMap = make(map[int64][]*model.PriceDefendOrder)
	)
	priceDefends, _ := dao.GetPriceDefendOrder(db, "", nil, nil, []int{jxutils.GetLastDefendPriceIssue()}, 0, -1, 1, 1, "", utils.ZeroTimeValue, utils.ZeroTimeValue, false)
	if len(priceDefends) > 0 {
		for _, v := range priceDefends {
			userOrderMap[v.AddressID] = append(userOrderMap[v.AddressID], v)
		}
		for kk, vv := range userOrderMap {
			addressList, _, _ := dao.QueryUserDeliveryAddress(db, kk, nil, 0, 0)
			address := addressList[0]
			if len(vv) == 1 {
				jxOrder := &JxOrderInfo{
					BuyerComment: "守价订单",
					StoreID:      vv[0].StoreID,
					Skus: []*JxSkuInfo{
						&JxSkuInfo{
							SkuID: vv[0].SkuID,
							Count: vv[0].Count,
						},
					},
					IsPriceDefend: model.YES,
					OrderID:       utils.Str2Int64(vv[0].VendorOrderID),
					UserID:        address.UserID,
				}
				if _, err := CreateOrder(ctx, jxOrder, kk, OrderCreateTypeNormal, 0, false, nil); err == nil {
					err = SettleDiscountActByPriceDefend(ctx, vv[0], false)
				}
			} else {
				var (
					skus     []*JxSkuInfo
					orderIDs []string
				)
				jxOrder := &JxOrderInfo{
					BuyerComment:  "守价订单",
					StoreID:       vv[0].StoreID,
					IsPriceDefend: model.YES,
					OrderID:       jxutils.GenOrderNo(),
					UserID:        address.UserID,
				}
				for _, priceDefend := range vv {
					sku := &JxSkuInfo{
						SkuID: priceDefend.SkuID,
						Count: priceDefend.Count,
					}
					skus = append(skus, sku)
					orderIDs = append(orderIDs, priceDefend.VendorOrderID)
					err = SettleDiscountActByPriceDefend(ctx, priceDefend, false)
				}
				jxOrder.Skus = skus
				jxOrder.OrderID2 = strings.Join(orderIDs, ",")
				if _, err := CreateOrder(ctx, jxOrder, kk, OrderCreateTypeNormal, 0, false, nil); err == nil {
				}
			}
		}
	}
	priceDefends2, _ := dao.GetPriceDefendOrder(db, "", nil, nil, []int{jxutils.GetLastDefendPriceIssue()}, 0, -1, 0, 1, "", utils.ZeroTimeValue, utils.ZeroTimeValue, false)
	if len(priceDefends2) > 0 {
		for _, v := range priceDefends2 {
			err = SettleDiscountActByPriceDefend(ctx, v, true)
		}
	}
	return err
}

//结算因京西折扣活动而参与守价的订单
func SettleDiscountActByPriceDefend(ctx *jxcontext.Context, order *model.PriceDefendOrder, isFull bool) (err error) {
	var (
		db = dao.GetDB()
	)
	payList, err2 := dao.GetOrderPayList(db, order.VendorOrderID, jxutils.GetPossibleVendorIDFromVendorOrderID(order.VendorOrderID))
	if err = err2; err == nil {
		for _, orderPay := range payList {
			if orderPay.Status == model.PayStatusYes {
				refundID := order.VendorOrderID
				if orderPay.PayType == model.PayTypeTL {
					if !isFull {
						minusPrice := int(order.OriginPrice - order.RealPrice)
						_, err = RefundOrderByTL(ctx, orderPay, refundID, order.Count*minusPrice, settleDiscountActRefundReason)
					} else {
						_, err = RefundOrderByTL(ctx, orderPay, refundID, int(order.ActualPayPrice), settleDiscountActRefundReason)
					}
				}
			} else {
				orderPay.Status = model.PayStatusCanceled
				_, err = dao.UpdateEntity(db, orderPay)
			}
		}
	}
	return err
}

func GetMyPriceDefendOrders(ctx *jxcontext.Context, fromTime, toTime string) (priceDefendOrders []*model.PriceDefendOrder, err error) {
	var (
		db     = dao.GetDB()
		userID = ctx.GetUserID()
	)
	priceDefendOrders, err = dao.GetPriceDefendOrder(db, "", nil, nil, nil, 0, -1, -1, -1, userID, utils.Str2Time(fromTime), utils.Str2Time(toTime), true)
	return priceDefendOrders, err
}

func GetCoupons(ctx *jxcontext.Context, couponType int, couponStatuss, storeIDs []int, keyword string) (coupons []*model.Coupons, err error) {
	var (
		db = dao.GetDB()
	)
	coupons, err = dao.GetCoupons(db, couponType, couponStatuss, storeIDs, "", "", keyword)
	return coupons, err
}

func AddCoupons(ctx *jxcontext.Context, coupons *model.Coupons, count int, storeIDs []int) (err error) {
	var (
		db = dao.GetDB()
	)
	if coupons.BeginAt == utils.ZeroTimeValue || coupons.EndAt == utils.ZeroTimeValue {
		return fmt.Errorf("请输入正确的起始时间！")
	} else {
		if coupons.BeginAt.Sub(coupons.EndAt) > 0 {
			return fmt.Errorf("请输入正确的起始时间！")
		}
		//优惠券还没开始生效
		if time.Now().Sub(coupons.BeginAt) < 0 {
			coupons.CouponStatus = model.CouponStatusRe
		}
	}
	if coupons.IsAll == model.NO {
		if len(storeIDs) == 0 {
			return fmt.Errorf("不是全国生效则必须选择生效门店！")
		}
	} else {
		storeIDs = []int{} //全国不需要选门店
	}
	if coupons.UpperLimit == 0 || coupons.Cut == 0 {
		return fmt.Errorf("请输入正确的满减！")
	} else {
		if coupons.Cut > coupons.UpperLimit {
			return fmt.Errorf("请输入正确的满减！")
		}
	}
	if coupons.CouponType == 0 {
		return fmt.Errorf("请选择一个优惠券类型！")
	}
	if count == 0 {
		count += 1
	}
	for i := 1; i < count; i++ {
		dao.WrapAddIDCULDEntity(coupons, ctx.GetUserName())
		if err = dao.CreateEntity(db, coupons); err == nil {
			//门店优惠券表
			if coupons.IsAll == 0 {
				for _, v := range storeIDs {
					storeCoupons := &model.StoreCoupons{
						CouponID: int(coupons.ID),
						StoreID:  v,
					}
					dao.WrapAddIDCULEntity(storeCoupons, ctx.GetUserName())
					dao.CreateEntity(db, v)
				}
			}
		}
	}
	return err
}

func UpdateCoupons(ctx *jxcontext.Context, payload map[string]interface{}, storeIDs []int, isDel bool) (err error) {
	var (
		db      = dao.GetDB()
		coupons = &model.Coupons{}
	)
	coupons.ID = utils.MustInterface2Int64(payload["id"])
	dao.GetEntity(db, coupons)
	if isDel {
		coupons.CouponStatus = model.CouponStatusDeleted
		coupons.UpdatedAt = time.Now()
		coupons.LastOperator = ctx.GetUserName()
		dao.UpdateEntity(db, coupons, "CouponStatus", "UpdatedAt", "LastOperator")
	} else {
		valid := dao.StrictMakeMapByStructObject(payload, coupons, ctx.GetUserName())
		if len(valid) > 0 {
			txDB, _ := dao.Begin(db)
			defer func() {
				if r := recover(); r != nil {
					dao.Rollback(db, txDB)
					panic(r)
				}
			}()
			if valid["isAll"] != nil {
				if utils.MustInterface2Int64(valid["isAll"]) == model.NO && len(storeIDs) == 0 {
					return fmt.Errorf("改成全国不生效要选门店！")
				}
			}
			if _, err = dao.UpdateEntityByKV(db, coupons, valid, nil); err != nil {
				dao.Rollback(db, txDB)
				return err
			}
			if valid["isAll"] != nil {
				storeCouponss, _ := dao.GetStoreCoupons(db, []int{int(coupons.ID)}, nil)
				for _, v := range storeCouponss {
					v.DeletedAt = time.Now()
					v.LastOperator = ctx.GetUserName()
					dao.UpdateEntity(db, v, "DeletoedAt", "LastOperator")
				}
				if utils.MustInterface2Int64(valid["isAll"]) == model.NO {
					for _, v := range storeIDs {
						storeCoupons := &model.StoreCoupons{
							StoreID:  v,
							CouponID: int(coupons.ID),
						}
						dao.WrapAddIDCULEntity(storeCoupons, ctx.GetUserName())
						dao.CreateEntity(db, storeCoupons)
					}
				}
			}
			dao.Commit(db, txDB)
		}
	}
	return err
}

func ReceiveCoupons(ctx *jxcontext.Context, couponID int) (err error) {
	var (
		db      = dao.GetDB()
		userID  = ctx.GetUserID()
		coupons = &model.Coupons{}
	)
	coupons.ID = int64(couponID)
	dao.GetEntity(db, coupons)
	if coupons == nil {
		return fmt.Errorf("领取优惠券失败！")
	}
	if coupons.CouponStatus != model.CouponStatusNormal {
		return fmt.Errorf("优惠券状态有误，领取失败！")
	}
	if time.Now().Sub(coupons.EndAt) > 0 {
		return fmt.Errorf("优惠券已过期，领取失败！")
	}
	if time.Now().Sub(coupons.BeginAt) < 0 {
		return fmt.Errorf("优惠券未生效，领取失败！")
	}
	userCoupons, _ := dao.GetUserCoupons(db, []int{couponID}, []string{userID}, nil, model.CouponStatusNormal)
	if len(userCoupons) > 0 {
		return fmt.Errorf("您已经领取过该优惠券了，请使用后再领取！")
	}
	userCoupon := &model.UserCoupons{
		CouponID: couponID,
		UserID:   userID,
	}
	dao.WrapAddIDCULEntity(userCoupon, ctx.GetUserName())
	err = dao.CreateEntity(db, userCoupon)
	return err
}

func RefreshCouponsStatus(ctx *jxcontext.Context) (err error) {
	var (
		db = dao.GetDB()
	)
	task := tasksch.NewParallelTask("RefreshCouponsStatus", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
		func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
			step := batchItemList[0].(int)
			switch step {
			case 0:
				//还没生效的弄成生效
				coupons, _ := dao.GetCoupons(db, 0, []int{model.CouponStatusRe}, nil, "", "", "")
				task := tasksch.NewParallelTask("RefreshCouponsStatusRe", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
					func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
						coupon := batchItemList[0].(*model.Coupons)
						if time.Now().Sub(coupon.BeginAt) > 0 {
							coupon.CouponStatus = model.CouponStatusNormal
							coupon.UpdatedAt = time.Now()
							dao.UpdateEntity(db, coupon, "CouponStatus", "UpdatedAt")
						}
						return retVal, err
					}, coupons)
				tasksch.HandleTask(task, nil, true).Run()
				_, err = task.GetResult(0)
			case 1:
				//过期的弄成过期
				coupons, _ := dao.GetCoupons(db, 0, []int{model.CouponStatusNormal}, nil, "", "", "")
				task := tasksch.NewParallelTask("RefreshCouponsStatusNormal", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
					func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
						coupon := batchItemList[0].(*model.Coupons)
						if time.Now().Sub(coupon.EndAt) > 0 {
							coupon.CouponStatus = model.CouponStatusOverdue
							coupon.UpdatedAt = time.Now()
							dao.UpdateEntity(db, coupon, "CouponStatus", "UpdatedAt")
							//用户手上的优惠券也要弄成过期
							if userCoupons, err := dao.GetUserCoupons(db, []int{int(coupon.ID)}, nil, nil, 0); err == nil {
								for _, v := range userCoupons {
									v.UserCouponStatus = model.CouponStatusOverdue
									v.UpdatedAt = time.Now()
									dao.UpdateEntity(db, v, "UserCouponStatus", "UpdatedAt")
								}
							}
						}
						return retVal, err
					}, coupons)
				tasksch.HandleTask(task, nil, true).Run()
				_, err = task.GetResult(0)
			}
			return retVal, err
		}, []int{0, 1})
	tasksch.HandleTask(task, nil, true).Run()
	task.GetID()
	return err
}

// 创建门店充值订单
func CreateStoreAcctOrder(ctx *jxcontext.Context, orderType, storeID, price int, goodsVendorOrderID string) (vendorOrderID string, err error) {
	var (
		db        = dao.GetDB()
		storeAcct = &model.StoreAcct{
			StoreID: storeID,
		}
	)
	if err = dao.GetEntity(db, storeAcct, "StoreID"); err != nil && dao.IsNoRowsError(err) {
		//新增门店账单
		dao.WrapAddIDCULEntity(storeAcct, ctx.GetUserName())
		dao.CreateEntity(db, storeAcct)
	}

	order := &model.StoreAcctOrder{
		VendorOrderID:      utils.Int64ToStr(jxutils.GenOrderNo()),
		UserID:             ctx.GetUserID(),
		StoreID:            storeID,
		OrderType:          orderType,
		Status:             model.OrderStatusWait4Pay,
		ActualPayPrice:     price,
		VendorID:           model.VendorIDJX,
		GoodsVendorOrderID: goodsVendorOrderID,
	}
	dao.WrapAddIDCULEntity(order, ctx.GetUserName())
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.CreateEntity(db, order); err != nil {
		dao.Rollback(db, txDB)
	}
	dao.Commit(db, txDB)
	return order.VendorOrderID, err
}

// 根据订单号获取门店充值记录
func GetStoreAcctOrderByVendorId(vendorOrderID string) (int, error) {
	if vendorOrderID == "" {
		return 0, errors.New("参数vendorOrderID 不能为空")
	}
	sql := `
	SELECT t1.*
	FROM store_acct_order t1
	WHERE 1 = 1
	AND  t1.vendor_order_id = ? 
`
	var sqlParams []interface{}
	sqlParams = append(sqlParams, vendorOrderID)

	data := &model.StoreAcctOrder{}
	err := dao.GetRow(dao.GetDB(), &data, sql, sqlParams...)
	if data.StoreID == 0 {
		return 0, errors.New("充值订单为异常订单，无门店信息")
	}
	if err != nil {
		return 0, err
	}

	// 获取门店所属品牌
	storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), data.StoreID, -1, "")
	return storeDetail.BrandID, nil
}

func CreateBrandOrder(ctx *jxcontext.Context, brandID, price int) (vendorOrderID string, err error) {
	var (
		db = dao.GetDB()
	)
	brandOrder := &model.BrandOrder{
		VendorOrderID:  utils.Int64ToStr(jxutils.GenOrderNo()),
		UserID:         ctx.GetUserID(),
		BrandID:        brandID,
		OrderType:      model.OrderTypeBrand,
		Status:         model.OrderStatusWait4Pay,
		ActualPayPrice: price,
	}
	dao.WrapAddIDCULEntity(brandOrder, ctx.GetUserName())
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	if err = dao.CreateEntity(db, brandOrder); err != nil {
		dao.Rollback(db, txDB)
	}
	dao.Commit(db, txDB)
	return brandOrder.VendorOrderID, err
}
