Files
jx-callback/business/partner/purchase/jx/localjx/order.go
2020-03-06 13:46:04 +08:00

970 lines
33 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 localjx
import (
"crypto/md5"
"fmt"
"math"
"sort"
"time"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"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"
"git.rosy.net.cn/jx-callback/business/partner/delivery"
)
const (
OrderCreateTypePre = 0 // 预创建
OrderCreateTypeNormal = 1 // 正常创建
PayWaitingTime = 10 * time.Minute // 等待支付的最长时间
DingShiDaMinTime = 1 * time.Hour
specialStoreID = 100274
specialFreightPrice = 1500
wxAppID = "wx4b5930c13f8b1170"
autoCancelOrderReason = "支付超时,系统自动取消!"
)
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"`
}
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"`
}
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 string `json:"time"`
Status string `json:"status"`
Name string `json:"name"`
}
var (
orderNoBeginTimestamp int64
weekdayMap = map[int]string{
1: "一",
2: "二",
3: "三",
4: "四",
5: "五",
6: "六",
7: "七",
}
dayList = []string{"今天", "明天", "后天"}
)
func init() {
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
}
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 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
}
func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, createType int, fromStoreID int) (outJxOrder *JxOrderInfo, err error) {
outJxOrder, deliveryAddress, err := generateOrder(ctx, jxOrder, addressID, fromStoreID)
if err != nil {
return nil, err
}
if createType != OrderCreateTypePre {
if outJxOrder.TotalPrice != jxOrder.TotalPrice {
return nil, fmt.Errorf("商品或配送信息发生改变,请重新下单")
}
outJxOrder.OrderID = GenOrderNo(ctx)
order, err2 := jxOrder2GoodsOrder(ctx, outJxOrder, deliveryAddress)
if err = err2; err == nil {
order.Status = model.OrderStatusWait4Pay
callNewOrder(order)
}
}
return outJxOrder, err
}
// 买家取消(或申请取消)订单
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 string) (orderPay *model.OrderPay, err error) {
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 orderPay, err = pay4OrderByTL(ctx, order, vendorPayType); err == nil {
dao.WrapAddIDCULDEntity(orderPay, ctx.GetUserName())
err = dao.CreateEntity(dao.GetDB(), orderPay)
}
default:
err = fmt.Errorf("支付方式:%d当前不支持", payType)
}
}
return orderPay, err
}
func time2ShortTimeStr(t time.Time) string {
return t.Format("15:04")
}
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,
})
}
}
deliverTimerList = append(deliverTimerList, timeInfo)
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,
})
}
}
}
beginDate = beginDate.Add(24 * time.Hour)
}
return deliverTimerList, err
}
func OnPayFinished(orderPay *model.OrderPay) (err error) {
order, err := partner.CurOrderManager.LoadOrder(orderPay.VendorOrderID, orderPay.VendorID)
if err == nil {
db := dao.GetDB()
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)
}
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 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) (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
}
addressList, _, err := dao.QueryUserDeliveryAddress(db, addressID, []string{ctx.GetUserID()}, 0, 0)
if err != nil {
return nil, nil, err
}
if len(addressList) == 0 {
return nil, nil, fmt.Errorf("地址ID不正确")
}
deliveryAddress = addressList[0]
if distance := jxutils.Point2StoreDistance(deliveryAddress.Lng, deliveryAddress.Lat, storeDetail.Lng, storeDetail.Lat, storeDetail.DeliveryRangeType, storeDetail.DeliveryRange); distance == 0 {
return nil, nil, fmt.Errorf("当前送货地址不在门店%s的配送范围", storeDetail.Name)
}
//表示此订单为物料配送订单
if fromStoreID != 0 {
storeDetail2, err2 := dao.GetStoreDetail(db, fromStoreID, model.VendorIDJX)
if err = err2; err != nil {
return nil, nil, fmt.Errorf("fromStoreID有误,[%v]", fromStoreID)
}
deliveryAddress.ConsigneeName = storeDetail2.Name
outJxOrder.FromStoreID = fromStoreID
}
// 营业状态及时间检查
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("预订单只能预定当天或第二天")
}
}
// if !isTimeInOpTime(storeDetail.OpenTime1, storeDetail.CloseTime1, storeDetail.OpenTime2, storeDetail.CloseTime2, checkTime) {
// return nil, nil, fmt.Errorf("门店:%s不在营业时间范围", storeDetail.Name)
// }
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 {
storeSkuMap[v2.SkuID] = v2
}
}
skuList, err := dao.GetSkus(db, skuIDs, nil, nil, nil)
if err != nil {
return nil, nil, err
}
skuMap := make(map[int]*model.SkuAndName)
for _, v := range skuList {
skuMap[v.ID] = v
}
for _, v := range skus {
if storeSkuBind := storeSkuMap[v.SkuID]; storeSkuBind != nil {
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 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
}
}
if jxSku != nil {
outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
outJxOrder.OrderPrice += int64(jxSku.Count) * jxSku.SalePrice
outJxOrder.Weight += jxSku.Count * jxSku.Weight
}
}
}
}
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)
// if jxOrder.StoreID == specialStoreID {
// outJxOrder.FreightPrice = 0
// }
} else {
outJxOrder.FreightPrice = 0
}
if outJxOrder.FreightPrice > specialFreightPrice {
outJxOrder.FreightPrice = specialFreightPrice
}
if outJxOrder.OrderPrice >= int64(storeDetail.DeliveryFeeDeductionSill) {
outJxOrder.FreightPrice -= int64(storeDetail.DeliveryFeeDeductionFee)
if outJxOrder.FreightPrice < 0 {
outJxOrder.FreightPrice = 0
}
}
if err == nil {
outJxOrder.TotalPrice = outJxOrder.OrderPrice + outJxOrder.FreightPrice
outJxOrder.ActualPayPrice = outJxOrder.TotalPrice
} else {
outJxOrder = nil
deliveryAddress = nil
}
return outJxOrder, deliveryAddress, err
}
func jxOrder2GoodsOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, deliveryAddress *dao.UserDeliveryAddressEx) (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(),
}
order.OrderCreatedAt = order.StatusTime
order.VendorUserID = order.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 = order.TotalShopMoney
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, "")
err = orderSolutionForWuLiao(order)
return err
}
func orderSolutionForWuLiao(order *model.GoodsOrder) (err error) {
if order.FromStoreID != 0 {
// var (
// goodsNos []string
// prices []int
// quantities []int
// db = dao.GetDB()
// )
err = changeOrderStatus(order.VendorOrderID, model.OrderStatusDelivering, "")
// goods, err := dao.QueryOrders(db, order.VendorOrderID, -1, []int{model.VendorIDJX}, -1, utils.ZeroTimeValue, utils.ZeroTimeValue)
// if err != nil || len(goods) == 0 {
// return err
// }
// for _, v := range goods[0].Skus {
// skus, err := dao.GetSkus(db, []int{v.SkuID}, nil, nil, nil)
// if err != nil || len(skus) == 0 {
// continue
// }
// goodsNos = append(goodsNos, skus[0].EclpID)
// prices = append(prices, 0)
// quantities = append(quantities, v.Count)
// }
// result, err := api.JdEclpAPI.AddOrder(&jdeclpapi.AddOrderParam{
// IsvUUID: order.VendorOrderID,
// IsvSource: jdeclpapi.IsvSource,
// ShopNo: jdeclpapi.ShopNo,
// DepartmentNo: jdeclpapi.DepartmentNo,
// WarehouseNo: jdeclpapi.WarehouseNo,
// SalesPlatformOrderNo: order.VendorOrderID,
// SalePlatformSource: "",
// ConsigneeName: order.ConsigneeName,
// ConsigneeMobile: order.ConsigneeMobile,
// ConsigneeAddress: order.ConsigneeAddress,
// OrderMark: jdeclpapi.OrderMark,
// GoodsNo: goodsNos,
// Price: prices,
// Quantity: quantities,
// })
// if err != nil {
// return err
// }
// order.EclpOutID = result.EclpSoNo
// dao.UpdateEntity(db, order, "EclpOutID")
}
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
if orderPay.PayType == 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))
MarkArrears(db, order, orderPay)
CancelMatterOrder(db, order)
} else {
errList.AddErr(err)
}
} else if orderPay.PayType == model.PayTypeTL {
orderPayRefund, err = refundOrderByTL(ctx, orderPay, refundID, orderPay.TotalFee, reason)
if err == nil {
MarkArrears(db, order, orderPay)
CancelMatterOrder(db, order)
} else {
errList.AddErr(err)
}
}
} 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()
} else {
err = fmt.Errorf("当前订单状态:%s不允许取消", model.OrderStatusName[order.Status])
}
return err
}
func CancelMatterOrder(db *dao.DaoDB, order *model.GoodsOrder) (err error) {
if order.FromStoreID != 0 {
_, err = api.JdEclpAPI.CancelOrder(order.EclpOutID)
}
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) (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"}, "", "", "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"}, "", "", "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"}, "", "", "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")
globals.SugarLogger.Debugf("每日订单打款:[%v]", cms.BuildDiffData(mapResult))
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 := CancelOrder(ctx, v, 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 GetMatterOrderStatus(ctx *jxcontext.Context, vendorOrderID string) (result []*MatterOrderStatus, err error) {
var (
db = dao.GetDB()
)
waybills, err := dao.GetWayBillByOrderID(db, -1, model.VendorIDJX, -1, vendorOrderID)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDJX)
if len(waybills) > 0 {
// queryOrderStatus, err := api.JdEclpAPI.QueryOrderStatus(waybills[0].VendorWaybillID)
}
// getTrackMessagePlusByOrderResult, err := api.JdEclpAPI.GetTrackMessagePlusByOrder(vendorOrderID)
dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db)
panic(r)
}
}()
dao.UpdateEntity(db, order, "Status")
waybills[0].StatusTime = time.Now()
dao.UpdateEntity(db, waybills[0], "Status", "StatusTime")
dao.Commit(db)
return result, err
}