792 lines
30 KiB
Go
792 lines
30 KiB
Go
package report
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
"math"
|
||
"sort"
|
||
"strings"
|
||
"time"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/partner"
|
||
|
||
"git.rosy.net.cn/jx-callback/business/jxstore/permission"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"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"
|
||
)
|
||
|
||
type tStoreSkuBindAndSkuName struct {
|
||
CityCode int
|
||
StoreID int `orm:"column(store_id)"`
|
||
NameID int `orm:"column(name_id)"`
|
||
UnitPrice int
|
||
UnitPriceList []int
|
||
}
|
||
|
||
func GetStatisticsReportForOrders(ctx *jxcontext.Context, storeIDs, vendorIDs []int, fromDate, toDate, marketPhone, jdPhone, mtPhone, ebaiPhone string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
|
||
db := dao.GetDB()
|
||
fromDateParm := utils.Str2Time(fromDate)
|
||
toDateParm := utils.Str2Time(toDate)
|
||
//若时间间隔大于3个月则不允许查询
|
||
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
|
||
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月!: 时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||
}
|
||
statisticsReportForOrdersList, err = dao.GetStatisticsReportForOrders(db, storeIDs, vendorIDs, fromDateParm, toDateParm, marketPhone, jdPhone, mtPhone, ebaiPhone)
|
||
return statisticsReportForOrdersList, err
|
||
}
|
||
|
||
func GetStatisticsReportForAfsOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
|
||
db := dao.GetDB()
|
||
fromDateParm := utils.Str2Time(fromDate)
|
||
toDateParm := utils.Str2Time(toDate)
|
||
//若时间间隔大于3个月则不允许查询
|
||
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
|
||
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月!: 时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||
}
|
||
statisticsReportForOrdersList, err = dao.GetGetStatisticsReportForAfsOrders(db, storeIDs, fromDateParm, toDateParm)
|
||
return statisticsReportForOrdersList, err
|
||
}
|
||
|
||
func StatisticsReportForStoreSkusPrice(ctx *jxcontext.Context, cityCodes, skuIDs []int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||
var snapDateParam time.Time
|
||
db := dao.GetDB()
|
||
if snapDate != "" {
|
||
snapDateParam = utils.Str2Time(snapDate)
|
||
}
|
||
priceReferSnapshot, totalCount, err := dao.GetPriceReferSnapshot(db, cityCodes, skuIDs, 0, snapDateParam, offset, pageSize)
|
||
pagedInfo = &model.PagedInfo{
|
||
Data: priceReferSnapshot,
|
||
TotalCount: totalCount,
|
||
}
|
||
return
|
||
}
|
||
|
||
func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||
var priceReferSnapshotList []*model.PriceReferSnapshot
|
||
db := dao.GetDB()
|
||
snapshotAt := utils.Time2Date(time.Now().AddDate(0, 0, -1))
|
||
dao.DeletePriceReferHistory(db, utils.Time2Date(snapshotAt.AddDate(0, 0, -7)))
|
||
priceReferSnapshotDelete := &model.PriceReferSnapshot{SnapshotAt: snapshotAt}
|
||
dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt")
|
||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||
switch step {
|
||
case 0:
|
||
priceReferSnapshot, err := dao.GetStatisticsReportForStoreSkusPrice(db, cityCodes, skuIDs)
|
||
if len(priceReferSnapshot) > 0 {
|
||
txDB, _ := dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db, txDB)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
for _, v := range priceReferSnapshot {
|
||
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
|
||
v.SnapshotAt = snapshotAt
|
||
}
|
||
dao.CreateMultiEntities(db, priceReferSnapshot)
|
||
dao.Commit(db, txDB)
|
||
}
|
||
case 1:
|
||
priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, nil, nil, nil, snapshotAt)
|
||
var (
|
||
citySkuMap = make(map[int]map[int][]int)
|
||
countryMap = make(map[int][]int)
|
||
resultMap = make(map[int]map[int]*model.PriceReferSnapshot)
|
||
resultCountryMap = make(map[int]*model.PriceReferSnapshot)
|
||
)
|
||
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
|
||
if err != nil {
|
||
return result, err
|
||
}
|
||
for _, v := range storeList {
|
||
if v.PayPercentage < 50 {
|
||
continue
|
||
}
|
||
var tList []*tStoreSkuBindAndSkuName
|
||
sql := `
|
||
SELECT DISTINCT b.city_code, a.store_id, Round(a.unit_price * IF(b.pay_percentage < 50 , 70, b.pay_percentage) / 100) AS unit_price, c.name_id
|
||
FROM store_sku_bind a
|
||
JOIN store b ON b.id = a.store_id AND b.deleted_at = ? AND b.status != ?
|
||
JOIN sku c ON c.id = a.sku_id
|
||
WHERE a.store_id = ?
|
||
AND c.name_id NOT IN(
|
||
SELECT b.name_id
|
||
FROM store_sku_bind a
|
||
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
|
||
WHERE a.deleted_at = ?
|
||
AND a.store_id = ?
|
||
AND b.name_id NOT IN(SELECT DISTINCT b.name_id
|
||
FROM store_sku_bind a
|
||
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
|
||
WHERE a.deleted_at = ?
|
||
AND a.store_id = ?
|
||
AND a.status = ?)
|
||
)
|
||
AND a.deleted_at = ?
|
||
`
|
||
sqlParams := []interface{}{
|
||
utils.DefaultTimeValue,
|
||
model.StoreStatusDisabled,
|
||
v.ID,
|
||
utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
v.ID,
|
||
utils.DefaultTimeValue,
|
||
utils.DefaultTimeValue,
|
||
v.ID,
|
||
model.StoreSkuBindStatusNormal,
|
||
utils.DefaultTimeValue,
|
||
}
|
||
dao.GetRows(db, &tList, sql, sqlParams...)
|
||
skuNameMap := make(map[int][]int)
|
||
if len(tList) > 0 {
|
||
for _, vv := range tList {
|
||
skuNameMap[vv.NameID] = append(skuNameMap[vv.NameID], vv.UnitPrice)
|
||
countryMap[vv.NameID] = append(countryMap[vv.NameID], vv.UnitPrice)
|
||
}
|
||
if citySkuMap[v.CityCode] != nil {
|
||
for nameID, unitPriceList := range skuNameMap {
|
||
if citySkuMap[v.CityCode][nameID] != nil {
|
||
citySkuMap[v.CityCode][nameID] = append(citySkuMap[v.CityCode][nameID], unitPriceList...)
|
||
} else {
|
||
citySkuMap[v.CityCode][nameID] = unitPriceList
|
||
}
|
||
}
|
||
} else {
|
||
citySkuMap[v.CityCode] = skuNameMap
|
||
}
|
||
}
|
||
}
|
||
for k, v := range countryMap {
|
||
var midUnitPrice int
|
||
var avgUnitPrice int
|
||
sort.Ints(v)
|
||
if len(v)%2 == 0 {
|
||
midUnitPrice = v[len(v)/2-1]
|
||
} else {
|
||
midUnitPrice = v[len(v)/2]
|
||
}
|
||
for _, vv := range v {
|
||
avgUnitPrice += vv
|
||
}
|
||
priceRefer := &model.PriceReferSnapshot{
|
||
MidUnitPrice: midUnitPrice,
|
||
MaxUnitPrice: v[len(v)-1],
|
||
MinUnitPrice: v[0],
|
||
AvgUnitPrice: avgUnitPrice / len(v),
|
||
}
|
||
resultCountryMap[k] = priceRefer
|
||
}
|
||
for k1, v := range citySkuMap {
|
||
skuNameMap := make(map[int]*model.PriceReferSnapshot)
|
||
for k2, _ := range v {
|
||
var midUnitPrice int
|
||
var avgUnitPrice int
|
||
sort.Ints(v[k2])
|
||
if len(v[k2])%2 == 0 {
|
||
midUnitPrice = v[k2][len(v[k2])/2-1]
|
||
} else {
|
||
midUnitPrice = v[k2][len(v[k2])/2]
|
||
}
|
||
for _, vv := range v[k2] {
|
||
avgUnitPrice += vv
|
||
}
|
||
skuNameMap[k2] = &model.PriceReferSnapshot{
|
||
MidUnitPrice: midUnitPrice,
|
||
MaxUnitPrice: v[k2][len(v[k2])-1],
|
||
MinUnitPrice: v[k2][0],
|
||
AvgUnitPrice: avgUnitPrice / len(v[k2]),
|
||
}
|
||
}
|
||
resultMap[k1] = skuNameMap
|
||
}
|
||
txDB, _ := dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db, txDB)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
if len(priceReferSnapshotList) > 0 {
|
||
for _, v := range priceReferSnapshotList {
|
||
if v.CityCode == 0 {
|
||
if resultCountryMap[v.NameID] != nil {
|
||
v.MidUnitPrice = resultCountryMap[v.NameID].MidUnitPrice
|
||
v.MaxUnitPrice = resultCountryMap[v.NameID].MaxUnitPrice
|
||
v.AvgUnitPrice = resultCountryMap[v.NameID].AvgUnitPrice
|
||
v.MinUnitPrice = resultCountryMap[v.NameID].MinUnitPrice
|
||
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
|
||
}
|
||
continue
|
||
}
|
||
if resultMap[v.CityCode][v.NameID] != nil {
|
||
v.MidUnitPrice = resultMap[v.CityCode][v.NameID].MidUnitPrice
|
||
v.MaxUnitPrice = resultMap[v.CityCode][v.NameID].MaxUnitPrice
|
||
v.AvgUnitPrice = resultMap[v.CityCode][v.NameID].AvgUnitPrice
|
||
v.MinUnitPrice = resultMap[v.CityCode][v.NameID].MinUnitPrice
|
||
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
|
||
}
|
||
}
|
||
}
|
||
dao.Commit(db, txDB)
|
||
case 2:
|
||
txDB, _ := dao.Begin(db)
|
||
defer func() {
|
||
if r := recover(); r != nil || err != nil {
|
||
dao.Rollback(db, txDB)
|
||
if r != nil {
|
||
panic(r)
|
||
}
|
||
}
|
||
}()
|
||
if len(priceReferSnapshotList) > 0 {
|
||
for _, v := range priceReferSnapshotList {
|
||
result, _ := dao.GetPriceReferPrice(db, v.CityCode, v.SkuID, snapshotAt)
|
||
if result != nil {
|
||
v.MaxPrice = result.MaxPrice
|
||
v.MinPrice = result.MinPrice
|
||
v.AvgPrice = result.AvgPrice
|
||
v.MidPrice = result.MidPrice
|
||
dao.UpdateEntity(db, v, "MidPrice", "MaxPrice", "MinPrice", "AvgPrice")
|
||
}
|
||
}
|
||
}
|
||
dao.Commit(db, txDB)
|
||
//TODO 京东查询接口报错,暂时屏蔽了
|
||
// case 3:
|
||
// priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, []int{0}, nil, nil, snapshotAt)
|
||
// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
// v := batchItemList[0].(*model.PriceReferSnapshot)
|
||
// for _, appOrg := range apimanager.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD) {
|
||
// directPrice, _ := jd.GetAPI(appOrg).GetJdSkuDirectPrice(v.SkuID)
|
||
// v.JdDirectPrice = int(directPrice)
|
||
// dao.UpdateEntity(db, v, "JdDirectPrice")
|
||
// }
|
||
// return retVal, err
|
||
// }
|
||
// taskParallel := tasksch.NewParallelTask("获取并更新京东指导价格", tasksch.NewParallelConfig(), ctx, taskFunc, priceReferSnapshotList)
|
||
// tasksch.HandleTask(taskParallel, task, true).Run()
|
||
// _, err = taskParallel.GetResult(0)
|
||
}
|
||
return result, err
|
||
}
|
||
taskSeq := tasksch.NewSeqTask2("生成每日价格统计", ctx, isContinueWhenError, taskSeqFunc, 3)
|
||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||
if !isAsync {
|
||
_, err = taskSeq.GetResult(0)
|
||
hint = "1"
|
||
} else {
|
||
hint = taskSeq.GetID()
|
||
}
|
||
return hint, err
|
||
}
|
||
|
||
type GetManageStateResult struct {
|
||
OpenStoreCount int `json:"openStoreCount"` //营业店铺数
|
||
HaveRestStoreCount int `json:"haveRestStoreCount"` //临时休息店铺数
|
||
RestStoreCount int `json:"restStoreCount"` //休息店铺数
|
||
FinishOrderState *GetManageStateOrderInfo //完成订单情况
|
||
IngOrderState *GetManageStateOrderInfo //进行中订单情况
|
||
CancelOrderState *GetManageStateOrderInfo //取消订单情况
|
||
}
|
||
|
||
type GetManageStateOrderInfo struct {
|
||
ActualPayPrice int `json:"actualPayPrice"` //支付总额
|
||
TotalShopMoney int `json:"totalShopMoney"` //平台结算
|
||
DesiredFee int `json:"desiredFee"` //配送费
|
||
Yhld string `json:"yhld"` //优惠力度(支付总额-平台结算-配送支出)/支付总额*100%
|
||
}
|
||
|
||
func getStoreStatusCount(db *dao.DaoDB, cityCodes []int, vendorID, status int) (count int, err error) {
|
||
countType := &struct{ Count int }{}
|
||
sqlParams := []interface{}{}
|
||
sql := `
|
||
SELECT COUNT(DISTINCT a.id) count
|
||
FROM store a
|
||
LEFT JOIN store_map b ON a.id = b.store_id AND b.deleted_at = ?
|
||
WHERE a.deleted_at = ?
|
||
`
|
||
sqlParams = append(sqlParams, utils.DefaultTimeValue, utils.DefaultTimeValue)
|
||
if len(cityCodes) > 0 {
|
||
sql += " AND a.city_code IN (" + dao.GenQuestionMarks(len(cityCodes)) + ")"
|
||
sqlParams = append(sqlParams, cityCodes)
|
||
}
|
||
if vendorID != -1 {
|
||
sql += " AND b.vendor_id = ? AND b.status = ?"
|
||
sqlParams = append(sqlParams, vendorID, status)
|
||
} else {
|
||
sql += " AND a.status = ?"
|
||
sqlParams = append(sqlParams, status)
|
||
}
|
||
err = dao.GetRow(db, &countType, sql, sqlParams)
|
||
return countType.Count, err
|
||
}
|
||
|
||
func getOrderStateCount(db *dao.DaoDB, cityCodes []int, vendorID, status int) (getManageStateOrderInfo *GetManageStateOrderInfo, err error) {
|
||
sqlParams := []interface{}{}
|
||
getManageStateOrderInfo = &GetManageStateOrderInfo{}
|
||
endTime := time.Now().AddDate(0, -3, 0)
|
||
sql := `
|
||
SELECT SUM(b.actual_pay_price) actual_pay_price, SUM(b.total_shop_money) total_shop_money, SUM(IFNULL(c.desired_fee, 0)) desired_fee
|
||
FROM store a
|
||
LEFT JOIN goods_order b ON a.id = IF(b.jx_store_id = 0, b.store_id, b.jx_store_id)
|
||
LEFT JOIN waybill c ON IF(b.waybill_vendor_id = -1,b.vendor_order_id,b.vendor_waybill_id) = c.vendor_waybill_id
|
||
WHERE a.deleted_at = ? AND a.status <> ?
|
||
AND b.order_created_at < ? AND b.order_created_at > ?
|
||
`
|
||
sqlParams = append(sqlParams, utils.DefaultTimeValue, model.StoreStatusDisabled, time.Now(), endTime)
|
||
if len(cityCodes) > 0 {
|
||
sql += " AND a.city_code IN (" + dao.GenQuestionMarks(len(cityCodes)) + ")"
|
||
sqlParams = append(sqlParams, cityCodes)
|
||
}
|
||
if vendorID != -1 {
|
||
sql += " AND b.vendor_id = ?"
|
||
sqlParams = append(sqlParams, vendorID)
|
||
}
|
||
if status != model.OrderStatusDelivering {
|
||
sql += " AND b.status = ?"
|
||
sqlParams = append(sqlParams, status)
|
||
} else {
|
||
sql += " AND b.status < ? AND b.status >= ?"
|
||
sqlParams = append(sqlParams, model.OrderStatusEndBegin, model.OrderStatusWait4Pay)
|
||
}
|
||
err = dao.GetRow(db, &getManageStateOrderInfo, sql, sqlParams)
|
||
getManageStateOrderInfo.Yhld = utils.Float64ToStr(math.Round((float64(getManageStateOrderInfo.ActualPayPrice-getManageStateOrderInfo.TotalShopMoney-getManageStateOrderInfo.DesiredFee) / float64(getManageStateOrderInfo.ActualPayPrice) * 100))) + "%"
|
||
return getManageStateOrderInfo, err
|
||
}
|
||
|
||
func GetManageState(ctx *jxcontext.Context, cityCodes []int, vendorID int) (getManageStateResult *GetManageStateResult, err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
)
|
||
getManageStateResult = &GetManageStateResult{}
|
||
if openCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusOpened); err == nil {
|
||
getManageStateResult.OpenStoreCount = openCount
|
||
}
|
||
if haveRestCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusHaveRest); err == nil {
|
||
getManageStateResult.HaveRestStoreCount = haveRestCount
|
||
}
|
||
if restCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusClosed); err == nil {
|
||
getManageStateResult.RestStoreCount = restCount
|
||
}
|
||
if finishCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusFinished); err == nil {
|
||
getManageStateResult.FinishOrderState = finishCount
|
||
}
|
||
if ingCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusDelivering); err == nil {
|
||
getManageStateResult.IngOrderState = ingCount
|
||
}
|
||
if cancelCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusCanceled); err == nil {
|
||
getManageStateResult.CancelOrderState = cancelCount
|
||
}
|
||
return getManageStateResult, err
|
||
}
|
||
|
||
func RefreshStoreManageState(ctx *jxcontext.Context) {
|
||
var (
|
||
db = dao.GetDB()
|
||
vendorIDs = []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}
|
||
messageFlag = time.Now().Hour() == 10 && time.Now().Minute() > 0 && time.Now().Minute() < 12
|
||
)
|
||
task := tasksch.NewParallelTask("RefreshStoreManageState", tasksch.NewParallelConfig().SetParallelCount(3).SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
vendorID := batchItemList[0].(int)
|
||
storeMaps, err := dao.GetStoresMapList(db, []int{vendorID}, nil, []int{model.StoreStatusOpened, model.StoreStatusClosed, model.StoreStatusHaveRest}, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
|
||
storeManageStates, err := dao.GetStoreManageStateSimple(db, nil, nil, vendorID)
|
||
var (
|
||
storeMapsMap = make(map[int]*model.StoreMap)
|
||
storeManagesMap = make(map[int]*model.StoreManageState)
|
||
deleteList []int
|
||
createList, updateList []*model.StoreMap
|
||
)
|
||
for _, v := range storeMaps {
|
||
storeMapsMap[v.StoreID] = v
|
||
}
|
||
for _, v := range storeManageStates {
|
||
storeManagesMap[v.StoreID] = v
|
||
if storeMapsMap[v.StoreID] != nil {
|
||
updateList = append(updateList, storeMapsMap[v.StoreID])
|
||
} else {
|
||
deleteList = append(deleteList, v.StoreID)
|
||
}
|
||
}
|
||
for _, v := range storeMapsMap {
|
||
if storeManagesMap[v.StoreID] == nil {
|
||
createList = append(createList, v)
|
||
}
|
||
}
|
||
task2 := tasksch.NewParallelTask("deleteList", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
storeID := batchItemList[0].(int)
|
||
storeManage := &model.StoreManageState{
|
||
StoreID: storeID,
|
||
VendorID: vendorID,
|
||
}
|
||
dao.DeleteEntity(db, storeManage, "StoreID", "VendorID")
|
||
return retVal, err
|
||
}, deleteList)
|
||
tasksch.HandleTask(task2, task, true).Run()
|
||
task2.GetResult(0)
|
||
task3 := tasksch.NewParallelTask("createList", tasksch.NewParallelConfig().SetParallelCount(20).SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
storeMap := batchItemList[0].(*model.StoreMap)
|
||
if storeMap.VendorOrgCode == "" || storeMap.VendorStoreID == "" {
|
||
return retVal, err
|
||
}
|
||
storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, vendorID, storeMap.VendorOrgCode)
|
||
storeManage := buildStoreManageState(ctx, db, storeMap, storeDetail, messageFlag)
|
||
if storeManage == nil {
|
||
return retVal, err
|
||
}
|
||
dao.CreateEntity(db, storeManage)
|
||
return retVal, err
|
||
}, createList)
|
||
tasksch.HandleTask(task3, task, true).Run()
|
||
task3.GetResult(0)
|
||
task4 := tasksch.NewParallelTask("updateList", tasksch.NewParallelConfig().SetParallelCount(20).SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
storeMap := batchItemList[0].(*model.StoreMap)
|
||
if storeMap.VendorOrgCode == "" || storeMap.VendorStoreID == "" {
|
||
return retVal, err
|
||
}
|
||
storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, vendorID, storeMap.VendorOrgCode)
|
||
storeManage := buildStoreManageState(ctx, db, storeMap, storeDetail, messageFlag)
|
||
if storeManage == nil {
|
||
return retVal, err
|
||
}
|
||
if storeManageStates, err := dao.GetStoreManageStateSimple(db, []int{storeDetail.ID}, nil, vendorID); err == nil && len(storeManageStates) > 0 {
|
||
storeManage.ID = storeManageStates[0].ID
|
||
dao.UpdateEntity(db, storeManage)
|
||
}
|
||
return retVal, err
|
||
}, updateList)
|
||
tasksch.HandleTask(task4, task, true).Run()
|
||
task4.GetResult(0)
|
||
return retVal, err
|
||
}, vendorIDs)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
task.GetID()
|
||
}
|
||
|
||
func buildStoreManageState(ctx *jxcontext.Context, db *dao.DaoDB, storeMap *model.StoreMap, storeDetail *dao.StoreDetail, messageFlag bool) *model.StoreManageState {
|
||
var (
|
||
dayTimeBegin, dayTimeEnd = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + "00:00:00"), utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + "23:59:59")
|
||
)
|
||
storeManage := &model.StoreManageState{
|
||
StoreID: storeMap.StoreID,
|
||
VendorID: storeMap.VendorID,
|
||
}
|
||
dao.WrapAddIDCULEntity(storeManage, ctx.GetUserName())
|
||
handler := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID)
|
||
store, err := handler.ReadStore(ctx, storeDetail.VendorOrgCode, storeDetail.VendorStoreID)
|
||
if err != nil || store == nil {
|
||
return nil
|
||
}
|
||
// if coverAreaFlag {
|
||
if storeMap.VendorID == model.VendorIDJD && store.DeliveryRangeType != model.DeliveryRangeTypePolygon {
|
||
storeManage.CoverArea = utils.Str2Float64(fmt.Sprintf("%.2f", math.Pi*utils.Str2Float64WithDefault(store.DeliveryRange, 0)/float64(1000)*utils.Str2Float64WithDefault(store.DeliveryRange, 0)/float64(1000)))
|
||
} else {
|
||
storeManage.CoverArea = utils.Str2Float64(fmt.Sprintf("%.2f", CalculateCoverArea(strings.Split(store.DeliveryRange, ";"), storeMap.VendorID)))
|
||
}
|
||
// }
|
||
//营业状态
|
||
storeManage.VendorStatus = store.Status
|
||
//不一致发消息
|
||
if messageFlag {
|
||
vendorStatus, status := -1, -1
|
||
if store.Status == model.StoreStatusOpened {
|
||
vendorStatus = 1
|
||
}
|
||
if storeDetail.Status == model.StoreStatusOpened {
|
||
status = 1
|
||
}
|
||
statusMap := map[int]string{
|
||
1: "营业",
|
||
-1: "休息",
|
||
}
|
||
if vendorStatus != status {
|
||
content := "您的门店 [" + storeDetail.Name + "],ID:[" + utils.Int2Str(storeDetail.ID) + "],在[" + model.VendorChineseNames[storeMap.VendorID] + "] 平台上营业状态和京西不一致!平台状态:【" + statusMap[vendorStatus] + "】,京西状态:【" + statusMap[status] + "】"
|
||
if user, err := dao.GetUserByID(db, "mobile", storeDetail.MarketManPhone); err == nil {
|
||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "平台门店状态变化", content)
|
||
}
|
||
}
|
||
}
|
||
//营业时长
|
||
optime := jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime1, time.Now()).Sub(jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime1, time.Now())).Hours()
|
||
if storeDetail.CloseTime2 != 0 && storeDetail.OpenTime2 != 0 {
|
||
optime += jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime2, time.Now()).Sub(jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime2, time.Now())).Hours()
|
||
}
|
||
storeManage.OpenTime = utils.Str2Float64(fmt.Sprintf("%.2f", optime))
|
||
//商品数
|
||
highSkuCount := 0
|
||
storeSkus, _ := dao.GetStoresSkusForManageState(db, storeMap.StoreID, model.StoreSkuBindStatusNormal)
|
||
for _, v := range storeSkus {
|
||
if v.UnitPrice > v.MidUnitPrice {
|
||
highSkuCount++
|
||
}
|
||
}
|
||
storeManage.SkuCount, storeManage.HighSkuCount = len(storeSkus), highSkuCount
|
||
//活动丰富度
|
||
ample, _ := handler.GetActAmple(ctx, storeDetail.VendorStoreID, storeDetail.VendorStoreID)
|
||
storeManage.ActAmple = ample
|
||
//订单
|
||
refuseOrderCount := 0
|
||
orderList, _ := dao.QueryOrdersForManageState(db, storeMap.StoreID, storeMap.VendorID, model.OrderStatusCanceled, dayTimeBegin, dayTimeEnd)
|
||
for _, v := range orderList {
|
||
if v.BindID == 0 {
|
||
refuseOrderCount++
|
||
}
|
||
}
|
||
storeManage.NullOrderCount, storeManage.RefuseOrderCount = len(orderList), refuseOrderCount
|
||
//评分(美团)
|
||
if storeMap.VendorID == model.VendorIDMTWM {
|
||
mtapi := partner.CurAPIManager.GetAPI(model.VendorIDMTWM, storeDetail.VendorOrgCode).(*mtwmapi.API)
|
||
if scoreResult, err := mtapi.CommentScore(storeDetail.VendorStoreID); err == nil {
|
||
storeManage.StoreScore = scoreResult.AvgPoiScore
|
||
}
|
||
}
|
||
return storeManage
|
||
}
|
||
|
||
func GetStoreManageState(ctx *jxcontext.Context, storeIDs, brandIDs []int, vendorID, sortType, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
)
|
||
//权限
|
||
if permission.IsRoled(ctx) {
|
||
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
|
||
var storeIDs2 []int
|
||
if len(storeIDs) > 0 {
|
||
for _, v := range storeIDs {
|
||
if storeIDsMap[v] != 0 {
|
||
storeIDs2 = append(storeIDs2, v)
|
||
}
|
||
}
|
||
if len(storeIDs2) == 0 {
|
||
storeIDs2 = append(storeIDs2, -1)
|
||
}
|
||
} else {
|
||
for k, _ := range storeIDsMap {
|
||
storeIDs2 = append(storeIDs2, k)
|
||
}
|
||
}
|
||
storeIDs = nil
|
||
storeIDs = storeIDs2
|
||
}
|
||
}
|
||
return dao.GetStoreManageState(db, storeIDs, brandIDs, vendorID, sortType, offset, pageSize)
|
||
}
|
||
|
||
func CalculateCoverArea(coordinate []string, vendorID int) (area float64) {
|
||
//我先把地理坐标转成了平面坐标(百度的方法)
|
||
//然后按多个坐标求面积公式求的面积(百度的方法)
|
||
if len(coordinate) == 0 {
|
||
return 0
|
||
}
|
||
var xyList [][2]float64
|
||
for _, v := range coordinate {
|
||
cell := strings.Split(v, ",")
|
||
if len(cell) == 0 || len(cell) == 1 {
|
||
continue
|
||
}
|
||
var lat, lng float64
|
||
if vendorID == model.VendorIDJD || vendorID == model.VendorIDEBAI {
|
||
lng = utils.Str2Float64WithDefault(cell[0], 0)
|
||
lat = utils.Str2Float64WithDefault(cell[1], 0)
|
||
} else {
|
||
lat = utils.Str2Float64WithDefault(cell[0], 0)
|
||
lng = utils.Str2Float64WithDefault(cell[1], 0)
|
||
}
|
||
xys := jxutils.MillierConvertion(lat, lng)
|
||
xyList = append(xyList, xys)
|
||
}
|
||
var sum float64 = 0
|
||
if len(xyList) == 0 {
|
||
return 0
|
||
}
|
||
for i := 0; i < len(xyList)-1; i++ {
|
||
// sum += (xyList[i+1][0] - xyList[i][0]) * (xyList[i+1][1] + xyList[i][1])
|
||
sum += (xyList[i][0]*xyList[i+1][1] - xyList[i+1][0]*xyList[i][1])
|
||
}
|
||
// sum += (xyList[0][0] - xyList[len(xyList)-1][0]) * (xyList[0][1] + xyList[len(xyList)-1][1])
|
||
sum += (xyList[len(xyList)-1][0]*xyList[0][1] - xyList[0][0]*xyList[len(xyList)-1][1])
|
||
sum /= float64(2)
|
||
sum = math.Abs(sum)
|
||
sum = utils.Str2Float64(fmt.Sprintf("%.2f", sum))
|
||
return sum
|
||
}
|
||
|
||
func RefreshJDMembers(ctx *jxcontext.Context) (err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
pageSize = 50
|
||
page int
|
||
pages []int
|
||
memberMap = make(map[string]*model.UserMember)
|
||
)
|
||
userMemebers, _ := dao.GetUserMemberWithoutDeleted(db, model.VendorIDJD)
|
||
for _, v := range userMemebers {
|
||
memberMap[v.Mobile] = v
|
||
}
|
||
pageResult, err := api.JdAPI.QueryMemberTransListByCondition("", "", page, pageSize)
|
||
if err != nil {
|
||
if strings.Contains(err.Error(), "cookie") {
|
||
globals.SugarLogger.Warnf("京东cookie过期了!")
|
||
}
|
||
}
|
||
if pageResult.Total%pageSize == 0 {
|
||
page = pageResult.Total / pageSize
|
||
} else {
|
||
page = pageResult.Total/pageSize + 1
|
||
}
|
||
for ; page > 0; page-- {
|
||
pages = append(pages, page)
|
||
}
|
||
task := tasksch.NewParallelTask2("RefreshJDMembers", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, successCount int, err error) {
|
||
pageNo := batchItemList[0].(int)
|
||
pageResult2, err := api.JdAPI.QueryMemberTransListByCondition("", "", pageNo, pageSize)
|
||
if pageResult2 != nil {
|
||
for _, v := range pageResult2.Rows {
|
||
if utils.Str2Time(v.Endtimestr+" 23:59:59").Sub(time.Now()) >= 0 && v.Dealstatus == 0 {
|
||
if memberMap[v.Merchantcardno] != nil { //库里有这个人的会员信息了
|
||
if utils.Time2Str(memberMap[v.Merchantcardno].EndAt) != v.Endtimestr+" 23:59:59" { //可能这个人续费了,续存了
|
||
memberMap[v.Merchantcardno].EndAt = utils.Str2Time(v.Endtimestr + " 23:59:59")
|
||
memberMap[v.Merchantcardno].DeletedAt = utils.DefaultTimeValue
|
||
dao.UpdateEntity(db, memberMap[v.Merchantcardno], "EndAt", "DeletedAt")
|
||
}
|
||
} else {
|
||
userMember := &model.UserMember{
|
||
VendorOrderID: v.Orderid,
|
||
VendorID: model.VendorIDJD,
|
||
Mobile: v.Merchantcardno,
|
||
MemberType: 1,
|
||
EndAt: utils.Str2Time(v.Endtimestr + " 23:59:59"),
|
||
}
|
||
dao.WrapAddIDCULDEntity(userMember, "jxadmin")
|
||
if v.Createtime != "" {
|
||
userMember.CreatedAt = utils.Str2Time(v.Createtime)
|
||
} else {
|
||
userMember.CreatedAt = utils.Str2Time(v.Cardcreatetime)
|
||
}
|
||
if userMember.EndAt.Sub(time.Now()) <= 0 {
|
||
userMember.DeletedAt = time.Now()
|
||
}
|
||
dao.CreateEntity(db, userMember)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return retVal, successCount, err
|
||
}, pages)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
task.GetID()
|
||
return err
|
||
}
|
||
|
||
func UserMemberReport(ctx *jxcontext.Context, vendorID int, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
|
||
var (
|
||
db = dao.GetDB()
|
||
)
|
||
var list []*dao.UserMemberReportResult
|
||
sql := `
|
||
SELECT SQL_CALC_FOUND_ROWS a.mobile, IF(a.vendor_id = ?, b.name, t1.consignee_name) name, IF(a.deleted_at = ?, ?, ?) status, a.vendor_id, t1.buy_count, t1.buy_price,
|
||
t1.good_comment_count, t1.bad_comment_count, t2.finished_count, t2.finished_price
|
||
FROM user_member a
|
||
LEFT JOIN user b ON a.mobile = b.mobile
|
||
LEFT JOIN (
|
||
SELECT a.mobile, MAX(b.consignee_name) consignee_name, COUNT(b.vendor_store_id) buy_count, SUM(b.actual_pay_price) buy_price, COUNT(c.score > 3) good_comment_count, COUNT(c.score < 3) bad_comment_count
|
||
FROM user_member a
|
||
LEFT JOIN goods_order b ON a.mobile = b.consignee_mobile2 AND a.vendor_id = b.vendor_id AND b.order_type = ? AND b.store_id <> ?
|
||
LEFT JOIN jx_bad_comments c ON c.order_id = b.vendor_order_id
|
||
GROUP BY 1
|
||
) t1 ON t1.mobile = a.mobile
|
||
LEFT JOIN (
|
||
SELECT a.mobile, COUNT(b.vendor_store_id) finished_count, SUM(b.actual_pay_price) finished_price
|
||
FROM user_member a
|
||
LEFT JOIN goods_order b ON a.mobile = b.consignee_mobile2 AND a.vendor_id = b.vendor_id AND b.order_type = ? AND status = ? AND b.store_id <> ?
|
||
GROUP BY 1
|
||
)t2 ON t2.mobile = a.mobile
|
||
WHERE 1 = 1
|
||
`
|
||
sqlParams := []interface{}{
|
||
model.VendorIDJX, utils.DefaultTimeValue, model.YES, model.NO,
|
||
model.OrderTypeNormal, model.MatterStoreID,
|
||
model.OrderTypeNormal, model.OrderStatusFinished, model.MatterStoreID,
|
||
}
|
||
if vendorID != -1 {
|
||
sql += " AND a.vendor_id = ?"
|
||
sqlParams = append(sqlParams, vendorID)
|
||
}
|
||
if keyword != "" {
|
||
keywordLike := "%" + keyword + "%"
|
||
sql += " AND (a.mobile LIKE ? OR name LIKE ?)"
|
||
sqlParams = append(sqlParams, keywordLike, keywordLike)
|
||
}
|
||
sql += `
|
||
LIMIT ? OFFSET ?
|
||
`
|
||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||
sqlParams = append(sqlParams, pageSize, offset)
|
||
txDB, _ := dao.Begin(db)
|
||
defer dao.Commit(db, txDB)
|
||
if err = dao.GetRowsTx(txDB, &list, sql, sqlParams...); err == nil {
|
||
page = &model.PagedInfo{
|
||
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
|
||
//Data: page,
|
||
}
|
||
task := tasksch.NewParallelTask("", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
|
||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||
v := batchItemList[0].(*dao.UserMemberReportResult)
|
||
var good *model.GoodsOrder
|
||
sql := `
|
||
SELECT * FROM goods_order WHERE consignee_mobile2 = ? AND vendor_id = ? AND order_type = ? AND store_id <> ? LIMIT 1 OFFSET 0
|
||
`
|
||
sqlParams := []interface{}{v.Mobile, v.VendorID, model.OrderTypeNormal, model.MatterStoreID}
|
||
dao.GetRow(db, &good, sql, sqlParams)
|
||
if good != nil {
|
||
v.NewPrice = good.ActualPayPrice
|
||
}
|
||
var place *model.Place
|
||
sql2 := `
|
||
SELECT a.* FROM place a,(
|
||
SELECT b.city_code, COUNT(*) count
|
||
FROM goods_order a
|
||
LEFT JOIN store b ON b.id = IF(a.jx_store_id = 0, store_id, jx_store_id)
|
||
WHERE consignee_mobile2 = ? AND vendor_id = ?
|
||
GROUP BY 1
|
||
ORDER BY COUNT(*)
|
||
LIMIT 1 OFFSET 0)b
|
||
WHERE a.code = b.city_code
|
||
`
|
||
dao.GetRow(db, &place, sql2, sqlParams)
|
||
if place != nil {
|
||
v.CityName = place.Name
|
||
v.CityCode = place.Code
|
||
}
|
||
return retVal, err
|
||
}, list)
|
||
tasksch.HandleTask(task, nil, true).Run()
|
||
task.GetResult(0)
|
||
page.Data = list
|
||
}
|
||
return page, err
|
||
}
|