Files
jx-callback/business/partner/purchase/jx/localjx/order.go
2019-11-20 15:55:09 +08:00

293 lines
9.4 KiB
Go

package localjx
import (
"crypto/md5"
"fmt"
"math"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
)
const (
OrderCreateTypePre = 0 // 预创建
OrderCreateTypeNormal = 1 // 正常创建
PayWaitingTime = 10 * time.Minute // 等待支付的最长时间
)
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"`
}
type JxOrderInfo struct {
BuyerComment string
StoreID int `json:"storeID"`
Skus []*JxSkuInfo `json:"skus"`
ExpectedDeliveredTime *time.Time `orm:"type(datetime)" json:"expectedDeliveredTime"` // 预期送达时间
TotalPrice int64 `json:"totalPrice"` // 单位为分 订单总价
FreightPrice int64 `json:"freightPrice"` // 单位为分 订单配送费
OrderPrice int64 `json:"orderPrice"` // 单位为分 订单商品价格
ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付
OrderID int64 `json:"orderID"`
StoreName string `json:"storeName"`
}
var (
orderNoBeginTimestamp int64
)
func init() {
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
}
func CreateOrder(ctx *jxcontext.Context, jxOrder *JxOrderInfo, addressID int64, createType int) (outJxOrder *JxOrderInfo, err error) {
outJxOrder, deliveryAddress, err := generateOrder(ctx, jxOrder, addressID)
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 {
partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
}
}
return outJxOrder, 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:
orderPay, err = pay4OrderByWX(ctx, order, vendorPayType)
default:
err = fmt.Errorf("支付方式:%d当前不支持", payType)
}
}
return orderPay, 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)
order.Status = model.OrderStatusNew
order.StatusTime = *orderPay.PayFinishedAt
// OnOrderNew逻辑需要修改
// err = partner.CurOrderManager.OnOrderNew(order, model.Order2Status(order))
}
return err
}
func GenOrderNo(ctx *jxcontext.Context) (orderNo int64) {
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)) * 88
return orderNo
}
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) (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不在门店%s的配送范围", deliveryAddress.DetailAddress, storeDetail.Name)
}
// 营业状态及时间检查
if storeDetail.Status == model.StoreStatusDisabled {
return nil, nil, fmt.Errorf("门店:%s状态是:%s", storeDetail.Name, model.StoreStatusName[storeDetail.Status])
}
checkTime := time.Now()
if jxOrder.ExpectedDeliveredTime == nil {
if storeDetail.Status != model.StoreStatusOpened {
return nil, nil, fmt.Errorf("门店:%s不是营业状态,状态是:%s", storeDetail.Name, model.StoreStatusName[storeDetail.Status])
}
} else {
checkTime = *jxOrder.ExpectedDeliveredTime
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)
}
skus := formalizeSkus(jxOrder.Skus)
if len(skus) == 0 {
return nil, nil, fmt.Errorf("商品列表为空")
}
var skuIDs []int
for _, v := range skus {
skuIDs = append(skuIDs, v.SkuID)
}
storeSkuList, err := dao.GetStoresSkusInfo(db, []int{jxOrder.StoreID}, skuIDs)
if err != nil {
return nil, nil, err
}
storeSkuMap := make(map[int]*model.StoreSkuBind)
for _, v := range storeSkuList {
storeSkuMap[v.SkuID] = v
}
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
}
outJxOrder2 := *jxOrder
outJxOrder2.Skus = nil
outJxOrder2.OrderPrice = 0
outJxOrder = &outJxOrder2
outJxOrder.StoreName = storeDetail.Name
for _, v := range skus {
if storeSkuBind := storeSkuMap[v.SkuID]; storeSkuBind != nil {
if sku := skuMap[v.SkuID]; sku != nil {
jxSku := &JxSkuInfo{
SkuID: v.SkuID,
Count: v.Count,
Price: int64(storeSkuBind.JxPrice),
SalePrice: int64(storeSkuBind.JxPrice), // todo 考虑活动价
Name: jxutils.ComposeSkuName(sku.Prefix, sku.Name, sku.Comment, sku.Unit, sku.SpecQuality, sku.SpecUnit, 0),
}
outJxOrder.Skus = append(outJxOrder.Skus, jxSku)
outJxOrder.OrderPrice += int64(v.Count) * jxSku.SalePrice
}
}
}
outJxOrder.TotalPrice = outJxOrder.OrderPrice + outJxOrder.FreightPrice
outJxOrder.ActualPayPrice = outJxOrder.TotalPrice
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: 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.ExpectedDeliveredTime != nil {
order.ExpectedDeliveredTime = *jxOrder.ExpectedDeliveredTime
order.BusinessType = model.BusinessTypeDingshida
} else {
order.ExpectedDeliveredTime = utils.DefaultTimeValue
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
}