Files
jx-callback/business/jxutils/jxutils.go
2018-08-30 00:32:57 +08:00

271 lines
7.2 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 jxutils
import (
"fmt"
"math"
"math/rand"
"regexp"
"strings"
"sync"
"time"
"unicode/utf8"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/routinepool"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
routinePool *routinepool.Pool
skuNamePat *regexp.Regexp
)
type SyncMapWithTimeout struct {
sync.Map
timers sync.Map
}
func init() {
rand.Seed(time.Now().Unix())
routinePool = routinepool.New(1000, 1000)
// Go regex does not support lookarounds.
// https://stackoverflow.com/questions/38933898/error-parsing-regexp-invalid-or-unsupported-perl-syntax
skuNamePat = regexp.MustCompile(`([\(\[【][^\(\[【\)\]】]*[\)\]】])?(.*?)([(].*[)])?\s*约?([1-9][\d\.]*)(g|G|kg|kG|Kg|KG|l|L|ml|mL|Ml|ML|克)\s*([(].*[)])?\s*(?:\/||)\s*([^\s()]{0,2})\s*([(].*[)])?$`)
}
func (m *SyncMapWithTimeout) StoreWithTimeout(key, value interface{}, timeout time.Duration) {
m.Map.Store(key, value)
m.timers.Store(key, time.AfterFunc(timeout, func() {
m.Delete(key)
}))
}
func (m *SyncMapWithTimeout) Delete(key interface{}) {
m.Map.Delete(key)
if value, ok := m.timers.Load(key); ok {
timer := value.(*time.Timer)
timer.Stop()
}
m.timers.Delete(key)
}
func GetJxStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
if order.JxStoreID != 0 {
return order.JxStoreID
}
return order.StoreID
}
func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID int) {
index := strings.Index(universalOrderID, "|")
if index != -1 {
orderID = universalOrderID[:index]
vendorID = int(utils.Str2Int64(universalOrderID[index:]))
} else {
// 800402581000221 jd order
// 3022716176275221584 elm order
orderIDLen := len(universalOrderID)
if orderIDLen == len("800402581000221") {
vendorID = model.VendorIDJD
} else if orderIDLen == len("3022716176275221584") {
vendorID = model.VendorIDELM
} else {
// globals.SugarLogger.Errorf("unkown order type:%v", universalOrderID)
panic(fmt.Sprintf("unkown order type:%v, orderIDLen:%d", universalOrderID, orderIDLen))
vendorID = model.VendorIDUnknown
}
orderID = universalOrderID
}
return orderID, vendorID
}
func ComposeUniversalOrderID(orderID string, vendorID int) string {
// return fmt.Sprintf("%s|%d", orderID, vendorID)
return orderID // 当前用长度就能区分先不加上vendorID
}
func GetUniversalOrderIDFromWaybill(bill *model.Waybill) string {
return ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID)
}
func GetUniversalOrderIDFromOrder(order *model.GoodsOrder) string {
return ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)
}
func GetUniversalOrderIDFromOrderStatus(status *model.OrderStatus) string {
return ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)
}
func EarthDistance(lat1, lng1, lat2, lng2 float64) float64 {
radius := 6378.137
rad := math.Pi / 180.0
lat1 = lat1 * rad
lng1 = lng1 * rad
lat2 = lat2 * rad
lng2 = lng2 * rad
theta := lng2 - lng1
dist := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(theta))
return dist * radius
}
func StandardCoordinate2Int(value float64) int {
return int(math.Round(value * 1000000))
}
func IntCoordinate2Standard(value int) float64 {
return float64(value) / 1000000
}
func IntCoordinate2MarsStandard(gpsLng, gpsLat int, coordinateType int) (marsLng, marsLat float64, err error) {
marsLng = IntCoordinate2Standard(gpsLng)
marsLat = IntCoordinate2Standard(gpsLat)
coordSys := ""
switch coordinateType {
case model.CoordinateTypeGPS:
coordSys = autonavi.CoordSysGPS
case model.CoordinateTypeMars:
coordSys = autonavi.CoordSysAutonavi
case model.CoordinateTypeBaiDu:
coordSys = autonavi.CoordSysBaidu
case model.CoordinateTypeMapbar:
coordSys = autonavi.CoordSysMapbar
default:
panic(fmt.Sprintf("known coordinate type:%d", coordinateType))
}
return api.AutonaviAPI.CoordinateConvert(marsLng, marsLat, coordSys)
}
func IntPrice2Standard(value int64) float64 {
return float64(value) / 100
}
func StandardPrice2Int(value float64) int64 {
return int64(math.Round(value * 100))
}
func IntPrice2StandardString(value int64) string {
return fmt.Sprintf("%.2f", IntPrice2Standard(value))
}
func CallMsgHandler(handler func(), primaryID string) {
routinePool.CallFun(func() {
handler()
}, primaryID)
}
func CallMsgHandlerAsync(handler func(), primaryID string) {
routinePool.CallFunAsync(func() {
handler()
}, primaryID)
}
func GetNameAndUnitFromSkuName(fullName string) (name string, unit string) {
unit = "份"
index := strings.Index(fullName, "/")
if index >= 0 {
name = fullName[:index]
unitTmp := []rune(fullName[index+1:])
if len(unitTmp) >= 1 {
unit = string(unitTmp[:1])
}
} else {
name = fullName
}
return name, unit
}
func MapValue2Scope(value, fromMin, fromMax, toMin, toMax int64) int64 {
if value < fromMin {
value = fromMin
}
if value > fromMax {
value = fromMax
}
return int64(math.Round(float64(value-fromMin)/float64(fromMax-fromMin)*float64(toMax-toMin) + float64(toMin)))
}
func Errs2Str(sep string, errs ...error) (retVal string) {
if sep == "" {
sep = "\n"
}
for _, err := range errs {
if err != nil {
retVal += err.Error() + sep
}
}
return retVal
}
func IntWeight2Float(weight int) float32 {
return float32(weight) / 1000.0
}
func FloatWeight2Int(weight float32) int {
return int(math.Round(float64(weight * 1000)))
}
func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) {
if prefix != "" {
skuName = "[" + prefix + "]"
}
skuName += name
if unit == "份" {
skuName += "约"
}
if math.Round(float64(spec_quality)) == float64(spec_quality) || (spec_unit != "L" && spec_unit != "kg") {
skuName += fmt.Sprintf("%d", int(spec_quality))
} else {
skuName += fmt.Sprintf("%.2f", spec_quality)
}
skuName += spec_unit
skuName += "/" + unit
if maxLen > 0 {
skuName = skuName[:maxLen]
}
return skuName
}
// 1商品特殊前缀
// 2商品名字
// 3商品说明1可缺失
// 4质量数字
// 5质量单位
// 6商品说明2可缺失
// 7商品单位
// 8商品说明3可缺失
func SplitSkuName(skuName string) (prefix, name, comment, specUnit, unit string, specQuality float32) {
searchResult := skuNamePat.FindStringSubmatch(skuName)
if searchResult != nil {
if searchResult[3] != "" {
comment = searchResult[3]
} else if searchResult[6] != "" {
comment = searchResult[6]
} else if searchResult[8] != "" {
comment = searchResult[8]
}
comment = strings.Trim(comment, " ()")
name = strings.Trim(searchResult[2], " ")
if comment != "" {
if utf8.RuneCountInString(comment) <= 5 {
name += "-" + comment
comment = ""
}
}
specUnit = strings.ToLower(strings.Replace(searchResult[5], "克", "g", -1))
if specUnit == "l" {
specUnit = "L"
}
if searchResult[7] == "" {
unit = "份"
} else {
unit = searchResult[7]
}
specQuality = float32(utils.Str2Float64(searchResult[4]))
prefix = strings.Trim(searchResult[1], " []()【】()")
}
return prefix, name, comment, specUnit, unit, specQuality
}