Browse Source

add 供应链加入商品库

three
DengBiao 11 months ago
parent
commit
ac816c5272
34 changed files with 3770 additions and 3 deletions
  1. +21
    -3
      app/db/dbs_map.go
  2. +18
    -0
      app/db/model/supply_db_mapping.go
  3. +1
    -0
      consume/init.go
  4. +10
    -0
      consume/md/consume_key.go
  5. +190
    -0
      consume/supply_cloud_chain_fenxiao_new_change.go
  6. +1
    -0
      go.mod
  7. +1108
    -0
      supply/1688/utils/aliApi.go
  8. +123
    -0
      supply/db/db_category.go
  9. +137
    -0
      supply/db/db_merchant.go
  10. +85
    -0
      supply/db/db_shipping_template.go
  11. +54
    -0
      supply/db/dbs_sys_cfg.go
  12. +33
    -0
      supply/db/model/goods_category.go
  13. +45
    -0
      supply/db/model/mall_goods.go
  14. +18
    -0
      supply/db/model/mall_goods_func.go
  15. +16
    -0
      supply/db/model/mall_shipping_template.go
  16. +19
    -0
      supply/db/model/mall_shipping_template_func.go
  17. +23
    -0
      supply/db/model/mall_sku.go
  18. +28
    -0
      supply/db/model/merchant.go
  19. +27
    -0
      supply/db/model/merchant_profile.go
  20. +26
    -0
      supply/db/model/supply_basic_setting.go
  21. +7
    -0
      supply/db/model/sys_cfg.go
  22. +166
    -0
      supply/enum/goods.go
  23. +19
    -0
      supply/enum/shipping_template.go
  24. +85
    -0
      supply/md/goods.go
  25. +20
    -0
      supply/md/goods_add_price.go
  26. +41
    -0
      supply/md/goods_list.go
  27. +79
    -0
      supply/md/shipping_template.go
  28. +16
    -0
      supply/svc/svc_comm.go
  29. +67
    -0
      supply/svc/svc_file_img_format.go
  30. +692
    -0
      supply/svc/svc_goods.go
  31. +128
    -0
      supply/svc/svc_goods_list.go
  32. +246
    -0
      supply/svc/svc_shipping_template.go
  33. +31
    -0
      supply/svc/svc_supply_basic_setting.go
  34. +190
    -0
      supply/svc/svc_sys_cfg_get.go

+ 21
- 3
app/db/dbs_map.go View File

@@ -3,7 +3,6 @@ package db
import (
"errors"
"fmt"

"xorm.io/xorm"

"applet/app/cfg"
@@ -82,6 +81,25 @@ func GetAllDatabasePrd() *[]model.DbMapping {
logx.Warn(err)
return nil
}
var mm []model.SupplyDbMapping
if err := Db.Where("deleted_at != ? AND is_dev = '0' ", 1).Find(&mm); err != nil || len(mm) == 0 {
logx.Warn(err)
return nil
}
for _, v := range mm {
m = append(m, model.DbMapping{
DbMasterId: v.DbMasterId,
DbHost: v.DbHost,
DbUsername: v.DbUsername,
DbPassword: v.DbPassword,
DbName: v.DbName,
ExternalMysql: v.ExternalMysql,
IsDev: v.IsDev,
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
DeletedAt: v.DeletedAt,
})
}
return &m
}

@@ -91,8 +109,8 @@ func GetAllDatabaseDev() *[]model.DbMapping {
var err error
fmt.Println("cfg.Local is: ", cfg.Local)
if cfg.Local { // 本地调试 加快速度
fmt.Println("notice:LOCAL TEST, only masterId:** 123456 ** available!")
err = Db.Where("deleted_at != ? AND is_dev = '1' AND db_master_id=?", 1, 123456).Find(&m)
fmt.Println("notice:LOCAL TEST, only masterId:** 99813608 ** available!")
err = Db.Where("deleted_at != ? AND db_master_id=?", 1, 68823769).Find(&m)
} else {
err = Db.Where("deleted_at != ? AND is_dev = '1' ", 1).Find(&m)
}


+ 18
- 0
app/db/model/supply_db_mapping.go View File

@@ -0,0 +1,18 @@
package model

import (
"time"
)

type SupplyDbMapping struct {
DbMasterId string `json:"db_master_id" xorm:"not null pk comment('站长id') VARCHAR(16)"`
DbHost string `json:"db_host" xorm:"not null default '' comment('数据库连接(带port)') VARCHAR(255)"`
DbUsername string `json:"db_username" xorm:"not null default '' comment('数据库用户名') VARCHAR(255)"`
DbPassword string `json:"db_password" xorm:"not null default '' comment('数据库用户名密码') VARCHAR(255)"`
DbName string `json:"db_name" xorm:"not null comment('数据库名') VARCHAR(255)"`
ExternalMysql string `json:"external_mysql" xorm:"not null default '0' comment('是否外部mysql(0是内部,1是外部)') VARCHAR(255)"`
IsDev int `json:"is_dev" xorm:"not null default 0 comment('开发库是1,0是生产库') TINYINT(1)"`
CreatedAt time.Time `json:"created_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') TIMESTAMP"`
UpdatedAt time.Time `json:"updated_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
DeletedAt int `json:"deleted_at" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"`
}

+ 1
- 0
consume/init.go View File

@@ -66,6 +66,7 @@ func initConsumes() {
//jobs[consumeMd.ZhiosRechargeOrderFailDevFunName] = ZhiosRechargeOrderFailDev

jobs[consumeMd.CloudIssuanceMsgCallBackFunName] = CloudIssuanceMsgCallBackConsume
jobs[consumeMd.SupplyCloudChainFenxiaoNewChangeFunName] = SupplyCloudChainFenxiaoNewChangeConsume

}



+ 10
- 0
consume/md/consume_key.go View File

@@ -29,6 +29,15 @@ var RabbitMqQueueKeyList = []*MqQueue{
BindKey: "",
ConsumeFunName: "CloudIssuanceMsgCallBackConsume",
},
{
ExchangeName: "zhios.cloud.issuance.msg.callback.exchange",
Name: "cloud_chain_fenxiao_newChange",
Type: FanOutQueueType,
IsPersistent: false,
RoutKey: "",
BindKey: "",
ConsumeFunName: "SupplyCloudChainFenxiaoNewChangeConsume",
},
{
ExchangeName: "canal.topic",
Name: "canal_order",
@@ -373,4 +382,5 @@ const (
ZhiosAppreciationDevFunName = "ZhiosAppreciationDev"
ZhiosGuideStoreOrderFunName = "ZhiosGuideStoreOrder"
ZhiosAcquisitionConditionDevFunName = "ZhiosAcquisitionConditionDev"
SupplyCloudChainFenxiaoNewChangeFunName = "SupplyCloudChainFenxiaoNewChangeConsume"
)

+ 190
- 0
consume/supply_cloud_chain_fenxiao_new_change.go View File

@@ -0,0 +1,190 @@
package consume

import (
"applet/app/e"
svc2 "applet/app/svc"
"applet/app/utils"
"applet/app/utils/logx"
"applet/consume/md"
utils1688 "applet/supply/1688/utils"
"applet/supply/db"
"applet/supply/db/model"
"applet/supply/enum"
md2 "applet/supply/md"
"applet/supply/svc"
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/streadway/amqp"
"time"
)

func SupplyCloudChainFenxiaoNewChangeConsume(queue md.MqQueue) {
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>")
ch, err := rabbit.Cfg.Pool.GetChannel()
if err != nil {
logx.Error(err)
return
}
defer ch.Release()
//2、取出数据进行消费
ch.Qos(1)
delivery := ch.Consume(queue.Name, false)

var res amqp.Delivery
var ok bool
for {
res, ok = <-delivery
if ok == true {
fmt.Println(">>>>>>>>>>>>>>>>SupplyCloudChainFenxiaoNewChangeConsume<<<<<<<<<<<<<<<<<<<<<<<<<")
//解析mq中queue的数据结构体
var pushStuct struct {
Args struct {
md2.GoodsAddPriceConditions
} `json:"args"`
Mid string `json:"mid"`
}
err = json.Unmarshal(res.Body, &pushStuct)
if err != nil {
panic(err)
}

//设置masterId
var c = &gin.Context{}
c.Set("mid", pushStuct.Mid)
var t struct {
md2.GoodsAddPriceConditions
}
t = pushStuct.Args
var idsMap = map[string]string{}
for _, v := range t.Ids {
idsMap[v] = v
}
var idsArray []string
for _, v := range idsMap {
idsArray = append(idsArray, v)
}
t.Ids = idsArray

basicSetting, _ := svc.GetSupplyBasicSetting(c)
if basicSetting == nil {
fmt.Println("!!!!!功能开发中!!!!!")
return
}
if basicSetting.AliCloudChainFenXiaoAppkey == "" || basicSetting.AliCloudChainFenXiaoAppsecret == "" || basicSetting.AliCloudChainFenXiaoAccesstoken == "" {
fmt.Println("!!!!!必要参数没有填写,功能已暂停!!!!!")
return
}
get, systemMerchant, err1 := db.GetSystemMerchant(svc2.MasterDb(c))
if err1 != nil {
fmt.Println(err1.Error(), "!!!!!!!!!!!!!!!!!!!!")
return
}
if !get {
fmt.Println("!!!!!请先去设置官方商家信息!!!!!")
return
}
ids := RemoveRepeatedElement(t.Ids)
for _, id := range ids {
var goods model.MallGoods
goods.CloudChainGoodsId = id
goods.MerchantId = systemMerchant.Id
getV2, err := goods.GetV2(svc2.MasterDb(c))
if err != nil {
e.OutErr(c, e.ERR, err.Error())
return
}
if getV2 {
continue
}

goodsFrom1688, err := utils1688.GetFenXiaoProductInfoFrom1688(basicSetting.AliCloudChainFenXiaoAppkey, basicSetting.AliCloudChainFenXiaoAppsecret, basicSetting.AliCloudChainFenXiaoAccesstoken, id)
if err != nil {
logx.Error(err)
continue
}
var req md2.AddGoodsReq
req.Base.GoodsType = 1
req.Base.CloudChainGoodsId = id
req.Base.SaleState = enum.MallGoodsSaleStateOnShelf
req.Base.CategoryId = utils.StrToInt(t.CategoryId)
req.Base.MerchantId = systemMerchant.Id
result, ok := goodsFrom1688["result"].(map[string]interface{})
if !ok {
e.OutErr(c, e.ERR, logx.Error("错误的数据").Error())
return
}
if message, ok := result["message"]; ok {
e.OutErr(c, e.ERR, message)
return
}
resultList, ok := result["result"].([]interface{})
if !ok {
e.OutErr(c, e.ERR, logx.Error("错误的数据2").Error())
return
}
if len(resultList) == 0 {
e.OutErr(c, e.ERR, logx.Error("错误的数据3").Error())
return
}
cloudChainGoods, ok := resultList[0].(map[string]interface{})
if !ok {
e.OutErr(c, e.ERR, logx.Error("错误的数据4").Error())
return
}
utils.FilePutContents("cloudChainGoods", utils.SerializeStr(cloudChainGoods))
err = svc.CloudChainFenXiaoGoodsChangeMallGoods(c, cloudChainGoods, &req)
if err != nil {
switch err.(type) {
case e.E:
err1 := err.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
default:
e.OutErr(c, e.ERR, err.Error())
return
}
}

err1 := svc.AddMallGoods(c, &req)
if err1 != nil {
switch err1.(type) {
case e.E:
err1 := err1.(e.E)
e.OutErr(c, err1.Code, err1.Error())
return
default:
e.OutErr(c, e.ERR, err1.Error())
return
}
}

time.Sleep(10 * time.Millisecond)
}

_ = res.Ack(true)
} else {
panic(errors.New("error getting message"))
}
}
fmt.Println("get msg done")
}

func RemoveRepeatedElement(arr []string) (newArr []string) {
newArr = make([]string, 0)
for i := 0; i < len(arr); i++ {
repeat := false
for j := i + 1; j < len(arr); j++ {
if arr[i] == arr[j] {
repeat = true
break
}
}
if !repeat {
newArr = append(newArr, arr[i])
}
}
return
}

+ 1
- 0
go.mod View File

@@ -63,6 +63,7 @@ require (
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mingrammer/commonregex v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mvdan/xurls v1.1.0 // indirect


+ 1108
- 0
supply/1688/utils/aliApi.go
File diff suppressed because it is too large
View File


+ 123
- 0
supply/db/db_category.go View File

@@ -0,0 +1,123 @@
package db

import (
"applet/app/utils"
"applet/app/utils/logx"
"applet/supply/db/model"
"errors"
"fmt"
"reflect"
"time"
"xorm.io/xorm"
)

// 获取所有类目原始数据
func GetAllCategory(Db *xorm.Engine) (GoodsCategoryList *[]model.GoodsCategory, err error) {
var categoryList []model.GoodsCategory
err = Db.Find(&categoryList)
GoodsCategoryList = &categoryList
return
}

func GetCategoryListByMcId(Db *xorm.Engine, mcId string, level string) (GoodsCategoryList *[]model.GoodsCategory, err error) {
var categoryList []model.GoodsCategory
if mcId == "0" {
if level == "" {
err = Db.Find(&categoryList)
} else {
err = Db.Where("level = ?", level).Find(&categoryList)
}
} else {
if level == "" {
err = Db.Where("mc_id = ?", mcId).Find(&categoryList)
} else {
err = Db.Where("mc_id = ?", mcId).And("level = ?", level).Find(&categoryList)
}
}
GoodsCategoryList = &categoryList
return
}

// CategoryListFindByParams 通过传入的参数查询数据(多条)
func CategoryListFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.GoodsCategory, error) {
var m []model.GoodsCategory
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, logx.Error(err)
}
return &m, nil
}

}
}

func GetCategoryById(Db *xorm.Engine, pid string) (GoodsCategoryList *model.GoodsCategory, err error) {
var m model.GoodsCategory
has, err := Db.Where("id=?", pid).Get(&m)
if has == false || err != nil {
return nil, err
}
return &m, nil
}

func UpdateCategoryById(eg *xorm.Engine, m *model.GoodsCategory, columns ...string) error {
var (
affected int64
err error
)
if columns == nil || len(columns) == 0 {
affected, err = eg.Where("id = ?", m.Id).AllCols().Update(m)
} else {
affected, err = eg.Where("id = ?", m.Id).Cols(columns...).Update(m)
}
if err != nil {
return err
}
if affected == 0 {
return errors.New("更新类目数据失败,稍后再试")
}
return nil
}

func CategoryInsert(Db *xorm.Engine, m *model.GoodsCategory) (int, error) {
_, err := Db.InsertOne(m)
if err != nil {
return 0, err
}
return m.Id, nil
}

func UpdateOrInsert(Db *xorm.Engine, m *model.GoodsCategory) error {
if m.Id != 0 {
err := UpdateCategoryById(Db, m)
if err != nil {
return err
}
} else {
m.CreateAt = time.Now()
_, err := CategoryInsert(Db, m)
if err != nil {
return err
}
}
return nil
}

+ 137
- 0
supply/db/db_merchant.go View File

@@ -0,0 +1,137 @@
package db

import (
"applet/app/e"
"applet/app/utils"
"applet/app/utils/logx"
"applet/supply/db/model"
"errors"
"fmt"
"reflect"
"xorm.io/xorm"
)

// MerchantFindByParams 通过传入的参数查询数据(多条)
func MerchantFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.Merchant, error) {
var m []model.Merchant
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, logx.Error(err)
}
return &m, nil
}

}
}

// MerchantProfileFindByParams 通过传入的参数查询数据(多条)
func MerchantProfileFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.MerchantProfile, error) {
var m []model.MerchantProfile
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, logx.Error(err)
}
return &m, nil
}

}
}

func GetMerchantById(eg *xorm.Engine, id int) (*model.Merchant, error) {
var m model.Merchant
get, err := eg.ID(id).Get(&m)
if err != nil {
return nil, err
}
if !get {
return nil, errors.New("账号不存在")
}
return &m, nil
}

func GetSystemMerchant(eg *xorm.Engine) (bool, *model.Merchant, error) {
var m model.Merchant
get, err := eg.Where("is_system = 1").Get(&m)
if err != nil {
return get, nil, err
}
return get, &m, nil
}

func GetMerchantByIdWithSession(session *xorm.Session, id int) (*model.Merchant, error) {
var m model.Merchant
get, err := session.ID(id).Get(&m)
if err != nil {
return nil, err
}
if !get {
return nil, errors.New("账号不存在")
}
return &m, nil
}

func GetMerchantByPhone(eg *xorm.Engine, phone string) (*model.Merchant, error) {
var m model.Merchant
get, err := eg.Where("phone=?", phone).Get(&m)
if err != nil {
return nil, err
}
if !get {
return nil, e.NewErr(e.ERR_ITEM_NOT_FOUND, "手机号不存在")
}
return &m, nil
}

func CheckMerchantPhoneExists(eg *xorm.Engine, phone string) (bool, error) {
exist, err := eg.Where("phone=?", phone).Exist(&model.Merchant{})
if err != nil {
return false, err
}

return exist, nil
}

func GetMerchantApplyById(eg *xorm.Engine, id interface{}) (*model.MerchantProfile, error) {
var m model.MerchantProfile
get, err := eg.ID(id).Get(&m)
if err != nil {
return nil, err
}
if !get {
return nil, e.NewErr(e.ERR_ITEM_NOT_FOUND, "该申请不存在")
}

return &m, nil
}

+ 85
- 0
supply/db/db_shipping_template.go View File

@@ -0,0 +1,85 @@
package db

import (
"applet/supply/db/model"
"applet/supply/md"
"errors"
"xorm.io/xorm"
)

func GetMallShippingTemplateList(eg *xorm.Engine, req md.MallShippingTemplateListReq) ([]*model.MallShippingTemplate, int64, error) {
var list []*model.MallShippingTemplate
sess := eg.NewSession()
if req.MerchantId != 0 {
sess.Where("merchant_id = ?", req.MerchantId)
}
if req.Name != "" {
sess.Where("name LIKE ?", "'%"+req.Name+"%'")
}
if req.CalculateType != 0 {
sess.Where("calculate_type = ?", req.CalculateType)
}
if req.P == 0 || req.PSize == 0 {
req.P = 1
req.PSize = 10
}
count, err := sess.Limit(req.PSize, (req.P-1)*req.PSize).FindAndCount(&list)
if err != nil {
return nil, 0, err
}
return list, count, nil
}

func GetMallShippingTemplateById(eg *xorm.Engine, templateId int) (*model.MallShippingTemplate, error) {
var m model.MallShippingTemplate
has, err := eg.Where("id = ?", templateId).Get(&m)
if err != nil {
return nil, err
}
if !has {
return nil, errors.New("没有找到相应的运费模板")
}
return &m, nil
}
func GetMallShippingTemplateByColumn(eg *xorm.Engine, column string, value interface{}) (*model.MallShippingTemplate, error) {
var m model.MallShippingTemplate
sql := "\"" + column + " = ?\""
has, err := eg.Where(sql, value).Get(&m)
if err != nil {
return nil, err
}
if !has {
return nil, errors.New("没有找到相应的运费模板")
}
return &m, nil
}

func InsertOneMallShippingTemplate(eg *xorm.Engine, m *model.MallShippingTemplate) error {
affected, err := eg.InsertOne(m)
if err != nil {
return err
}
if affected == 0 {
return errors.New("插入运费模板数据失败,稍后再试")
}
return nil
}

func UpdateMallShippingTemplateById(eg *xorm.Engine, m *model.MallShippingTemplate, columns ...string) error {
var (
affected int64
err error
)
if columns == nil || len(columns) == 0 {
affected, err = eg.Where("id = ?", m.Id).AllCols().Update(m)
} else {
affected, err = eg.Where("id = ?", m.Id).Cols(columns...).Update(m)
}
if err != nil {
return err
}
if affected == 0 {
return errors.New("插入运费模板数据失败,稍后再试")
}
return nil
}

+ 54
- 0
supply/db/dbs_sys_cfg.go View File

@@ -0,0 +1,54 @@
package db

import (
"applet/app/utils/logx"
"applet/supply/db/model"
"xorm.io/xorm"
)

// 系统配置get
func DbsSysCfgGetAll(eg *xorm.Engine) (*[]model.SysCfg, error) {
var cfgList []model.SysCfg
if err := eg.Cols("`key`,`val`").Find(&cfgList); err != nil {
return nil, logx.Error(err)
}
return &cfgList, nil
}

// 获取一条记录
func DbsSysCfgGet(eg *xorm.Engine, key string) (*model.SysCfg, error) {
var cfgList model.SysCfg
if has, err := eg.Where("`key`=?", key).Get(&cfgList); err != nil || has == false {
return nil, logx.Error(err)
}
return &cfgList, nil
}

func DbsSysCfgInsert(eg *xorm.Engine, key, val string) bool {
cfg := model.SysCfg{Key: key, Val: val}
_, err := eg.Where("`key`=?", key).Cols("val,memo").Update(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}
func DbsSysCfgInserts(eg *xorm.Engine, key, val string) bool {
cfg := model.SysCfg{Key: key, Val: val}
_, err := eg.InsertOne(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}

func DbsSysCfgUpdate(eg *xorm.Engine, key, val string) bool {
cfg := model.SysCfg{Key: key, Val: val}
_, err := eg.Where("`key`=?", key).Cols("val").Update(&cfg)
if err != nil {
logx.Error(err)
return false
}
return true
}

+ 33
- 0
supply/db/model/goods_category.go View File

@@ -0,0 +1,33 @@
package model

import (
"time"
)

type GoodsCategory struct {
Id int `json:"id" xorm:"not null pk INT(11)"`
Pid int `json:"pid" xorm:"comment('上级id') index INT(11)"`
Name string `json:"name" xorm:"comment('类目名称') VARCHAR(255)"`
Level int `json:"level" xorm:"comment('类目级别') index INT(3)"`
Sort int `json:"sort" xorm:"comment('序号') index INT(5)"`
McId int `json:"mc_id" xorm:"comment('主营类目id') index INT(11)"`
CreateAt time.Time `json:"create_at" xorm:"default 'CURRENT_TIMESTAMP' comment('创建时间') TIMESTAMP"`
UpdateAt time.Time `json:"update_at" xorm:"default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
}

type GoodsCategorySliceDecrement []GoodsCategory

func (mc GoodsCategorySliceDecrement) Len() int {
return len(mc)
}

func (mc GoodsCategorySliceDecrement) Swap(i, j int) {
mc[i], mc[j] = mc[j], mc[i]
}

func (mc GoodsCategorySliceDecrement) Less(i, j int) bool {
if mc[i].Id < mc[j].Id {
return true
}
return false
}

+ 45
- 0
supply/db/model/mall_goods.go View File

@@ -0,0 +1,45 @@
package model

import (
"time"
)

type MallGoods struct {
GoodsId int64 `json:"goods_id" xorm:"not null BIGINT(20)"`
GoodsCode string `json:"goods_code" xorm:"not null default '' comment('商品編碼') VARCHAR(255)"`
GoodsType int `json:"goods_type" xorm:"not null default 1 comment('商品类型:1实物商品') TINYINT(1)"`
Title string `json:"title" xorm:"not null default '' comment('商品标题') VARCHAR(1024)"`
CategoryId int `json:"category_id" xorm:"not null default 0 comment('类目ID') INT(11)"`
ImageList string `json:"image_list" xorm:"comment('商品图json') TEXT"`
Stock int `json:"stock" xorm:"not null default 0 comment('库存') INT(255)"`
ShippingType int `json:"shipping_type" xorm:"not null default 1 comment('配送方式:1快递') TINYINT(1)"`
ShippingFeeType int `json:"shipping_fee_type" xorm:"not null default 1 comment('运费计费方式:1统一运费 2运费模板') TINYINT(1)"`
ShippingTplId int `json:"shipping_tpl_id" xorm:"not null default 0 comment('运费模板id') INT(11)"`
ShippingFee string `json:"shipping_fee" xorm:"not null default 0.00 comment('统一运费的值') DECIMAL(12,2)"`
SaleState int `json:"sale_state" xorm:"not null default 0 comment('销售状态:-1审核拒绝 0审核中 1销售中 2已售罄 3放入仓库 4下架') TINYINT(1)"`
SaleStartTime time.Time `json:"sale_start_time" xorm:"comment('定时开售时间') DATETIME"`
CreateTime time.Time `json:"create_time" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"`
UpdateTime time.Time `json:"update_time" xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') DATETIME"`
CustomProperty string `json:"custom_property" xorm:"not null comment('自定义参数json') TEXT"`
Spe string `json:"spe" xorm:"not null default '' comment('所有规格属性json') VARCHAR(5012)"`
SpeImages string `json:"spe_images" xorm:"not null default '' comment('第一组规格值对应的图片json') VARCHAR(1024)"`
Detail string `json:"detail" xorm:"comment('商品详情') TEXT"`
SaleCount int `json:"sale_count" xorm:"not null default 0 comment('销量') INT(11)"`
IsSpeImageOn int `json:"is_spe_image_on" xorm:"not null default 0 comment('是否开启规格图片:0否 1是') TINYINT(1)"`
IsSpeImageInDetail int `json:"is_spe_image_in_detail" xorm:"not null default 0 comment('规格图是否显示在详情页') TINYINT(1)"`
DeleteAt time.Time `json:"delete_at" xorm:"comment('商品删除字段,不为null时,表示删除') DATETIME"`
Service string `json:"service" xorm:"comment('支持的服务json,id数组') VARCHAR(512)"`
MerchantId int `json:"merchant_id" xorm:"comment('商家id') INT(11)"`
ShippingTimeType int `json:"shipping_time_type" xorm:"not null default 3 comment('配送时间类型:1.当日发货 2.24小时内发货 3.48小时内发货 4自定义') TINYINT(1)"`
ShippingTimeCustom string `json:"shipping_time_custom" xorm:"comment('自定义发货时间的值(shipping_time_type=4时)') VARCHAR(50)"`
ProfitRate string `json:"profit_rate" xorm:"default 0.00 comment('预计利润空间') DECIMAL(8,2)"`
Price string `json:"price" xorm:"comment('sku中最小价') DECIMAL(10,2)"`
AuditReason string `json:"audit_reason" xorm:"comment('审核失败原因') VARCHAR(255)"`
PriceAddType int `json:"price_add_type" xorm:"not null default 1 comment('加价方式(1:按金额加 2:按比例加)') TINYINT(1)"`
RatioBaseType int `json:"ratio_base_type" xorm:"not null default 1 comment('比例基数方式(1:按进货价 2:按市场指导价 3:按利润空间)') TINYINT(1)"`
AddPriceValue string `json:"add_price_value" xorm:"not null default '0' comment('调整值(百分比或具体金额数值)') VARCHAR(50)"`
PriceValueType int `json:"price_value_type" xorm:"not null default 1 comment('价格数值设置(1:整数 2:小数点后两位)') TINYINT(1)"`
IsOpenAddPrice int `json:"is_open_add_price" xorm:"not null default 1 comment('是否开启商品加价') TINYINT(1)"`
CloudChainGoodsId string `json:"cloud_chain_goods_id" xorm:"comment('云链产品id') VARCHAR(255)"`
MinOrderQuantity string `json:"min_order_quantity" xorm:"comment('最小购买数') VARCHAR(255)"`
}

+ 18
- 0
supply/db/model/mall_goods_func.go View File

@@ -0,0 +1,18 @@
package model

import (
"applet/app/utils/logx"
"xorm.io/xorm"
)

func (g *MallGoods) Get(engine *xorm.Engine) error {
get, err := engine.Get(g)
if err != nil || !get {
return logx.Error("获取数据失败")
}
return nil
}
func (g *MallGoods) GetV2(engine *xorm.Engine) (bool, error) {
get, err := engine.Get(g)
return get, err
}

+ 16
- 0
supply/db/model/mall_shipping_template.go View File

@@ -0,0 +1,16 @@
package model

import (
"time"
)

type MallShippingTemplate struct {
Id int `json:"id" xorm:"not null pk autoincr INT(11)"`
Name string `json:"name" xorm:"comment('模板名称') VARCHAR(255)"`
CreateTime time.Time `json:"create_time" xorm:"created default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"`
UpdateTime time.Time `json:"update_time" xorm:"updated default 'CURRENT_TIMESTAMP' comment('更新时间') DATETIME"`
Data string `json:"data" xorm:"comment('运费数据') TEXT"`
CalculateType int `json:"calculate_type" xorm:"comment('计费方式:1按重量 2按件数') TINYINT(1)"`
MerchantId int `json:"merchant_id" xorm:"comment('商家id')"`
CloudChainTemId string `json:"cloud_chain_tem_id" xorm:"comment('云链额外字段 1688的运费模版id') VARCHAR(255)"`
}

+ 19
- 0
supply/db/model/mall_shipping_template_func.go View File

@@ -0,0 +1,19 @@
package model

import (
"applet/app/utils/logx"
"xorm.io/xorm"
)

func (t *MallShippingTemplate) Get(engine *xorm.Engine) error {
get, err := engine.Get(t)
if err != nil || !get {
return logx.Error("获取数据失败")
}
return nil
}

func (t *MallShippingTemplate) GetV2(engine *xorm.Engine) (bool, error) {
get, err := engine.Get(t)
return get, err
}

+ 23
- 0
supply/db/model/mall_sku.go View File

@@ -0,0 +1,23 @@
package model

import (
"time"
)

type MallSku struct {
SkuId int64 `json:"sku_id" xorm:"not null pk unique BIGINT(30)"`
GoodsId int64 `json:"goods_id" xorm:"not null comment('商品id') BIGINT(20)"`
Price string `json:"price" xorm:"not null default 0.00 comment('价格') DECIMAL(12,2)"`
CreateTime time.Time `json:"create_time" xorm:"default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"`
UpdateTime time.Time `json:"update_time" xorm:"default 'CURRENT_TIMESTAMP' comment('更新时间') DATETIME"`
Weight string `json:"weight" xorm:"not null default 0.0000 comment('重量') DECIMAL(12,4)"`
Stock int `json:"stock" xorm:"not null default 0 comment('库存') INT(11)"`
Indexes string `json:"indexes" xorm:"not null default '' comment('规格值组合的下标') VARCHAR(100)"`
Sku string `json:"sku" xorm:"not null comment('规格组合json') VARCHAR(2048)"`
SaleCount int `json:"sale_count" xorm:"not null default 0 comment('销量') INT(11)"`
LinePrice string `json:"line_price" xorm:"comment('市场价') DECIMAL(10,2)"`
SkuCode string `json:"sku_code" xorm:"VARCHAR(255)"`
SpecId string `json:"spec_id" xorm:"comment('云链的产品spec') VARCHAR(255)"`
CloudChainSkuId string `json:"cloud_chain_sku_id" xorm:"comment('云链的产品SKUid') VARCHAR(255)"`
CloudChainSkuImgUrl string `json:"cloud_chain_sku_img_url" xorm:"comment('云链的产品SKU图片url') VARCHAR(255)"`
}

+ 28
- 0
supply/db/model/merchant.go View File

@@ -0,0 +1,28 @@
package model

import (
"time"
)

type Merchant struct {
Id int `json:"id" xorm:"not null pk autoincr INT(11)"`
Account string `json:"account" xorm:"not null default '' comment('账号;目前使用手机号登陆,手机号即账号') VARCHAR(32)"`
Phone string `json:"phone" xorm:"not null default '' comment('手机号码') VARCHAR(11)"`
Name string `json:"name" xorm:"not null default '' comment('名称') VARCHAR(32)"`
Ip string `json:"ip" xorm:"not null default '' comment('最后登陆IP') VARCHAR(15)"`
IsSystem int `json:"is_system" xorm:"not null default 0 comment('是否是站长') TINYINT(1)"`
Pwd string `json:"pwd" xorm:"not null default '' VARCHAR(64)"`
HeadImg string `json:"head_img" xorm:"not null default '' comment('头像') VARCHAR(64)"`
State int `json:"state" xorm:"not null default 1 comment('0停用,1启用') TINYINT(1)"`
RoleId int `json:"role_id" xorm:"not null default 0 comment('角色ID') INT(11)"`
Permission string `json:"permission" xorm:"comment('权限') TEXT"`
Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(128)"`
LoginTime time.Time `json:"login_time" xorm:"comment('登陆时间') TIMESTAMP"`
CreateAt time.Time `json:"create_at" xorm:"default 'CURRENT_TIMESTAMP' TIMESTAMP"`
UpdateAt time.Time `json:"update_at" xorm:"default 'CURRENT_TIMESTAMP' TIMESTAMP"`
IsDelete int `json:"is_delete" xorm:"not null default 0 TINYINT(1)"`
TotalAmount string `json:"total_amount" xorm:"default 0.00 comment('总金额') DECIMAL(16,4)"`
ValidAmount string `json:"valid_amount" xorm:"default 0.00 comment('可用余额') DECIMAL(16,4)"`
FrozenAmount string `json:"frozen_amount" xorm:"default 0.00 comment('冻结金额') DECIMAL(16,4)"`
IsOpenAuditGoods int `json:"is_open_audit_goods" xorm:"not null default 0 comment('是否开启审核商品(0:不审核 1:审核)') TINYINT(1)"`
}

+ 27
- 0
supply/db/model/merchant_profile.go View File

@@ -0,0 +1,27 @@
package model

type MerchantProfile struct {
Id int `json:"id" xorm:"not null pk autoincr INT(11)"`
MerchantId int `json:"merchant_id" xorm:"comment('商家id') index INT(11)"`
McId string `json:"mc_id" xorm:"not null default '' comment('主营类目id') VARCHAR(255)"`
CompanyName string `json:"company_name" xorm:"not null default '' comment('公司名') VARCHAR(255)"`
LicenseNo string `json:"license_no" xorm:"not null default '' comment('营业执照号') VARCHAR(255)"`
LegalPerson string `json:"legal_person" xorm:"not null default '' comment('法人') VARCHAR(255)"`
LegalPersonNo string `json:"legal_person_no" xorm:"not null default '' comment('法人身份证号') VARCHAR(255)"`
BusinessLicenseImg string `json:"business_license_img" xorm:"not null default '' comment('营业执照') VARCHAR(1024)"`
LegalPersonFrontImg string `json:"legal_person_front_img" xorm:"not null default '' comment('法人身份证(正面)') VARCHAR(1024)"`
LegalPersonBackImg string `json:"legal_person_back_img" xorm:"not null default '' comment('法人身份证(背面)') VARCHAR(1024)"`
QualityCertificateImg string `json:"quality_certificate_img" xorm:"not null default '' comment('资质证书(json 字段存储)') VARCHAR(1024)"`
ContactName string `json:"contact_name" xorm:"not null default '' comment('业务联系人') VARCHAR(255)"`
ContactPhone string `json:"contact_phone" xorm:"not null default '' comment('业务联系人手机号') VARCHAR(255)"`
State int `json:"state" xorm:"not null default 1 comment('状态:1正常 2停用') TINYINT(1)"`
AuditState int `json:"audit_state" xorm:"not null default 0 comment('申请状态:0待提交 1待审核 2待签订协议 3完成审核 4审核拒绝') TINYINT(1)"`
Reason string `json:"reason" xorm:"comment('拒绝原因') VARCHAR(2048)"`
BrandId int `json:"brand_id" xorm:"not null default 0 comment('品牌id, 0为无品牌') INT(11)"`
QualityCertificateType int `json:"quality_certificate_type" xorm:"not null default 1 comment('资质证书类型:1品牌授权书2商品采购凭证3其他有效合同') TINYINT(1)"`
PriceAddType int `json:"price_add_type" xorm:"not null default 1 comment('加价方式(1:按金额加 2:按比例加)') TINYINT(1)"`
RatioBaseType int `json:"ratio_base_type" xorm:"not null default 1 comment('比例基数方式(1:按进货价 2:按市场指导价 3:按利润空间)') TINYINT(1)"`
AddPriceValue string `json:"add_price_value" xorm:"not null default '0' comment('调整值(百分比或具体金额数值)') VARCHAR(50)"`
PriceValueType int `json:"price_value_type" xorm:"not null default 1 comment('价格数值设置(1:整数 2:小数点后两位)') TINYINT(1)"`
IsOpenAddPrice int `json:"is_open_add_price" xorm:"not null default 1 comment('是否开启店铺加价') TINYINT(1)"`
}

+ 26
- 0
supply/db/model/supply_basic_setting.go View File

@@ -0,0 +1,26 @@
package model

import (
"time"
)

type SupplyBasicSetting struct {
Id int `json:"id" xorm:"not null pk autoincr INT(11)"`
AliCloudChainAppkey string `json:"ali_cloud_chain_appkey" xorm:"not null default '' comment('阿里巴巴云链appkey') VARCHAR(255)"`
AliCloudChainAppsecret string `json:"ali_cloud_chain_appSecret" xorm:"default '' comment('阿里巴巴云链appSecret') VARCHAR(255)"`
AliCloudChainAccesstoken string `json:"ali_cloud_chain_accessToken" xorm:"default '' comment('阿里巴巴云链AccessToken') VARCHAR(255)"`
AliCloudChainRefreshtoken string `json:"ali_cloud_chain_refreshToken" xorm:"default '' comment('阿里巴巴云链RefreshToken') VARCHAR(255)"`
AliCloudChainFenXiaoAppkey string `json:"ali_cloud_chain_fen_xiao_appkey" xorm:"not null default '' comment('阿里巴巴云链精选分销appkey') VARCHAR(255)"`
AliCloudChainFenXiaoAppsecret string `json:"ali_cloud_chain_fen_xiao_appSecret" xorm:"default '' comment('阿里巴巴云链精选分销appSecret') VARCHAR(255)"`
AliCloudChainFenXiaoAccesstoken string `json:"ali_cloud_chain_fen_xiao_accessToken" xorm:"default '' comment('阿里巴巴云链精选分销AccessToken') VARCHAR(255)"`
AliCloudChainFenXiaoRefreshtoken string `json:"ali_cloud_chain_fen_xiao_refreshToken" xorm:"default '' comment('阿里巴巴云链精选分销RefreshToken') VARCHAR(255)"`
DepositSysFeeRate string `json:"deposit_sys_fee_rate" xorm:"not null default '0' comment('预存金手续费比例') VARCHAR(255)"`
SupplierGoodsCommissionRate string `json:"supplier_goods_commission_rate" xorm:"not null default '0' comment('供应商商品抽佣比例') VARCHAR(255)"`
CloudSupplyChainGoodsCommissionRate string `json:"cloud_supply_chain_goods_commission_rate" xorm:"not null default '0' comment('云供应链商品抽佣比例') VARCHAR(255)"`
CloudSupplyChainGoodsAddPriceRate string `json:"cloud_supply_chain_goods_add_price_rate" xorm:"not null default '0' comment('云供应链商品加价比例') VARCHAR(255)"`
PriceAdjustType int `json:"price_adjust_type" xorm:"not null default 1 comment('价格调整方式(1:按金额加 2:按比例加)') TINYINT(1)"`
PriceAdjustBaseType int `json:"price_adjust_base_type" xorm:"not null default 1 comment('价格调整基数(1:利润空间为基数 2:进货价为基数)') TINYINT(1)"`
PriceAdjustValue string `json:"price_adjust_value" xorm:"not null default '0' comment('价格调整值') VARCHAR(255)"`
CreatedAt time.Time `json:"created_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') TIMESTAMP"`
UpdatedAt time.Time `json:"updated_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
}

+ 7
- 0
supply/db/model/sys_cfg.go View File

@@ -0,0 +1,7 @@
package model

type SysCfg struct {
Key string `json:"key" xorm:"not null pk comment('键') VARCHAR(127)"`
Val string `json:"val" xorm:"comment('值') TEXT"`
Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(255)"`
}

+ 166
- 0
supply/enum/goods.go View File

@@ -0,0 +1,166 @@
package enum

// MallGoodsType 商品类型
type MallGoodsType int

const MallGoodsReal MallGoodsType = 1

func (em MallGoodsType) String() struct {
Name string
Desc string
} {
switch em {
case MallGoodsReal:
return struct {
Name string
Desc string
}{Name: "实物商品", Desc: "物流发货"}
default:
return struct {
Name string
Desc string
}{Name: "未知类型", Desc: ""}
}
}

// MallVipDiscountType 商品VIP折扣类型
type MallVipDiscountType int

const (
MallDiscountTypeDiscount MallVipDiscountType = iota + 1
MallDiscountTypeMinus
MallDiscountTypeSpecify
)

func (em MallVipDiscountType) String() string {
switch em {
case MallDiscountTypeDiscount:
return "打折"
case MallDiscountTypeMinus:
return "减价"
case MallDiscountTypeSpecify:
return "指定价格"
default:
return "未知类型"
}
}

// MallShippingType 配送方式
type MallShippingType int

const MallShippingTypeExpress = 1

func (em MallShippingType) String() string {
switch em {
case MallShippingTypeExpress:
return "快递"
default:
return "未知类型"
}
}

type MallShippingFeeType int

const (
MallShippingFeeTypeUnify MallShippingFeeType = iota + 1
MallShippingFeeTypeTpl
)

func (em MallShippingFeeType) String() string {
switch em {
case MallShippingFeeTypeUnify:
return "统一运费"
case MallShippingFeeTypeTpl:
return "运费模板"
default:
return "未知类型"
}
}

type ShippingTemplateCalculateType int

const (
ShippingTemplateCalculateWeight ShippingTemplateCalculateType = iota + 1 // 重量计算
ShippingTemplateCalculatePiece // 件计算
)

func (st ShippingTemplateCalculateType) String() string {
switch st {
case ShippingTemplateCalculatePiece:
return "按件计算"
case ShippingTemplateCalculateWeight:
return "按重量计算"
default:
return "unkonwn"
}
}

// MallGoodsSaleState 商品上架状态
type MallGoodsSaleState int

const (
MallGoodsSaleStateOnShelf MallGoodsSaleState = iota + 1
MallGoodsSaleStateTiming
MallGoodsSaleStateOffShelf
)

func (em MallGoodsSaleState) String() string {
switch em {
case MallGoodsSaleStateOnShelf:
return "立即开售"
case MallGoodsSaleStateTiming:
return "定时开售"
case MallGoodsSaleStateOffShelf:
return "放入仓库"
default:
return "未知类型"
}
}

type MallGoodsActivityType int

const (
MallGoodsActivityGroup MallGoodsActivityType = iota + 1
MallGoodsActivitySecKill
MallGoodsActivityBargain
MallGoodsActivitySuperGroup
MallGoodsActivityUpdateLv
)

func (em MallGoodsActivityType) String() string {
switch em {
case MallGoodsActivityGroup:
return "拼团活动"
case MallGoodsActivitySecKill:
return "秒杀活动"
case MallGoodsActivityBargain:
return "砍价活动"
case MallGoodsActivitySuperGroup:
return "超级拼团"
case MallGoodsActivityUpdateLv:
return "升级礼包"
default:
return "未参加活动"
}
}

type MallGoodsServiceType int

const (
MallGoodsServiceShippingByManufacturer MallGoodsServiceType = iota + 1
MallGoodsServiceSevenDayReturn
MallGoodsServiceOfficialReal
)

func (em MallGoodsServiceType) String() string {
switch em {
case MallGoodsServiceShippingByManufacturer:
return "厂家配送"
case MallGoodsServiceSevenDayReturn:
return "七天无理由退换"
case MallGoodsServiceOfficialReal:
return "官方保真"
default:
return "其他服务"
}
}

+ 19
- 0
supply/enum/shipping_template.go View File

@@ -0,0 +1,19 @@
package enum

type MallShippingTemplateCalculateType int

const (
MallShippingTemplateCalculateTypeByWeight MallShippingTemplateCalculateType = iota + 1 // 重量
MallShippingTemplateCalculateTypeByNum // 件数
)

func (e MallShippingTemplateCalculateType) String() string {
switch e {
case MallShippingTemplateCalculateTypeByWeight:
return "按重量"
case MallShippingTemplateCalculateTypeByNum:
return "按件数"
default:
return ""
}
}

+ 85
- 0
supply/md/goods.go View File

@@ -0,0 +1,85 @@
package md

import "applet/supply/enum"

type AddGoodsReq struct {
Base MallBaseGoods `json:"base" binding:"required" label:"商品基本信息"` // 基本信息
SkuList []*MallGoodsSku `json:"sku_list" binding:"required,gt=0" label:"商品规格"` // sku列表
IsCopy bool `json:"is_copy,omitempty"` // 是否是复制商品
}

type MallBaseGoods struct {
GoodsId string `json:"goods_id,omitempty" label:"商品ID"` // 商品id,0或不传为新建
GoodsCode string `json:"goods_code,omitempty" label:"商品編碼"`
GoodsType enum.MallGoodsType `json:"goods_type" default:"1" label:"商品类型"` // 商品类型:1实体商品
Title string `json:"title" binding:"required,lte=200" label:"标题"` // 商品标题
CategoryId int `json:"category_id" binding:"required" label:"商品类目"` // 商品类目id
ImageList []string `json:"image_list" binding:"required,gt=0" label:"商品主图"` // 主图列表
ImageListUrl []string `json:"image_list_url" ` // 主图列表
Service []int `json:"service,omitempty" label:"支持服务"`
ShippingType enum.MallShippingType `json:"shipping_type" default:"1" label:"配送方式"` // 配送方式
ShippingFeeType enum.MallShippingFeeType `json:"shipping_fee_type" binding:"required,oneof=1 2" label:"运费计费方式"` // 运费计费方式
ShippingTplID int `json:"shipping_tpl_id" binding:"required_if=ShippingFeeType 2" label:"运费模板"` //运费模板id
ShippingFee string `json:"shipping_fee" binding:"required_if=ShippingFeeType 1" label:"统一运费"` // 统一运费的值(计费方式为)
SaleState enum.MallGoodsSaleState `json:"sale_state" label:"开售时间"` // 销售状态
SaleStartTime string `json:"sale_start_time" label:"定时开售"` // 定时上架时间
CustomProperty []struct {
GroupName string `json:"group_name" label:"属性组别名称"`
Index int `json:"index" label:"属性值索引"`
Name string `json:"name" label:"属性值"`
} `json:"custom_property" label:"自定义参数"` // 自定义参数
Spe []Spe `json:"spe" binding:"required,gt=0" label:"商品规格"` // 规格
SpeImages []string `json:"spe_images" binding:"required_if=IsSpeImageOn 1" label:"规格图片"` // 规格图片,与第一组规格名对应
SpeImagesUrl []string `json:"spe_images_url" label:"规格图片"` // 规格图片,与第一组规格名对应
Detail []string `json:"detail" label:"商品详情"` // 商品详情
DetailUrl []string `json:"detail_url" ` // 商品详情
MerchantId int `json:"merchant_id" ` // 商品详情
IsSpeImageOn int `json:"is_spe_image_on" default:"0" label:"是否开启规格图片"` // 是否要规格图
IsSpeImageInDetail int `json:"is_spe_image_in_detail" default:"0" label:"规格图片是否显示在详情中"` // 规格图是否要显示在详情页
ShippingTimeType int `json:"shipping_time_type" default:"3" label:"承诺发货时间"` // 配送时间类型:1.当日发货 2.24小时内发货 3.48小时内发货 4自定义
ShippingTimeCustom string `json:"shipping_time_custom" label:"自动义发货时间"`
PriceAddType int `json:"price_add_type" label:"加价方式(1:按金额加 2:按比例加)"`
RatioBaseType int `json:"ratio_base_type" label:"比例基数方式(1:按进货价 2:按市场指导价 3:按利润空间"`
AddPriceValue string `json:"add_price_value" label:"调整值(百分比或具体金额数值)"`
PriceValueType int `json:"price_value_type" label:"价格数值设置(1:整数 2:小数点后两位)"`
IsOpenAddPrice int `json:"is_open_add_price" label:"是否开启商品加价"`
//云链的产品id(1688)
CloudChainGoodsId string `json:"cloud_chain_goods_id"` //云链产品id
MinOrderQuantity string `json:"min_order_quantity"` //最小购买数

}
type Spe struct {
Name string `json:"name" label:"规格名"` // 规格名
Values []string `json:"values" label:"规格值"` // 规格值
}

type MallGoodsSku struct {
SkuID int `json:"sku_id,omitempty" label:"skuID" copier:"-"` // sku_id 0或不传为新建
GoodsID int `json:"goods_id,omitempty" label:"商品ID"` // 0或不传为新建
SkuCode string `json:"sku_code,omitempty" label:"sku編碼"`
Price string `json:"price" binding:"required" label:"价格"` // 价格
LinePrice string `json:"line_price" binding:"required" label:"市场价"`
Weight string `json:"weight" binding:"required" label:"重量"` // 重量
Stock int `json:"stock" default:"0" label:"库存"` // 库存
Sku []MallGoodsSkuSku `json:"sku" label:"规格组合"` // 规格组合

//云链的产品属性
SpecID string `json:"spec_id"`
CloudChainSkuId string `json:"cloud_chain_sku_id"`
CloudChainSkuImgUrl string `json:"cloud_chain_sku_img_url"`
}
type MallGoodsSkuSku struct {
Name string `json:"name" binding:"required" label:"规格名"` // 规格名
Value string `json:"value" binding:"required" label:"规格值"` // 规格值
}

type AddAdminGoodsWarehouse struct {
Kind string `json:"kind" binding:"required"` //1、指定商品 2、全部商品 3、指定主營类目 4、指定供貨商
GoodsId []string `json:"goods_id"`
MainCategoryIds []string `json:"main_category_ids"`
MerchantIds []string `json:"merchant_ids"`
PriceAddType string `json:"price_add_type"`
RatioBaseType string `json:"ratio_base_type"`
PriceValueType string `json:"price_value_type"`
AddPriceValue string `json:"add_price_value"`
}

+ 20
- 0
supply/md/goods_add_price.go View File

@@ -0,0 +1,20 @@
package md

type GoodsAddPriceConditions struct {
CategoryId string `json:"category_id"`
AddPriceType string `json:"add_price_type"` //1按金额增加2按比例增加
AddPriceBase string `json:"add_price_base"` //加价基数 1按进货价2按利润空间
AddPriceNum string `json:"add_price_num"` //类型是1就是直接加值,如果是2则是百分比
NumType string `json:"num_type"` //价格数值设置 1小数点后两位2整数
Ids []string `json:"ids"` //编辑商品id组
IsSkuAddPrice string `json:"is_sku_add_price"`
SkusConditions []*SkuAddPriceConditions `json:"skus_conditions"`
}

type SkuAddPriceConditions struct {
AddPriceType string `json:"add_price_type"` //1按金额增加2按比例增加
AddPriceBase string `json:"add_price_base"` //加价基数 1按进货价2按利润空间
AddPriceNum string `json:"add_price_num"` //类型是1就是直接加值,如果是2则是百分比
NumType string `json:"num_type"` //价格数值设置 1小数点后两位2整数
SkuCode string `json:"sku_code"`
}

+ 41
- 0
supply/md/goods_list.go View File

@@ -0,0 +1,41 @@
package md

// MallGoodsListReq
// Title 标题
// CategoryId 类目id
// SaleState 销售状态
// GoodsId 销售状态
// ActivityType 参加的活动类型
// PageId 页数
// PageSize 每页显示记录数
type MallGoodsListReq struct {
Title string `json:"title"`
CategoryId string `json:"category_id"`
GoodsCode string `json:"goods_code"`
SkuCode string `json:"sku_code"`
SaleState string `json:"sale_state"`
MerchantId string `json:"merchant_id"`
PageId string `json:"pageId"`
PageSize string `json:"pageSize"`
OrderBy string `json:"order_by"`
MerchantName string `json:"merchant_name"`
OrderBySate string `json:"order_by_sate"`
PriceMin string `json:"price_min"`
PriceMax string `json:"price_max"`
ProfitMin string `json:"profit_min"`
ProfitMax string `json:"profit_max"`
}

type GoodsRangeData struct {
PriceRange string `json:"price_range"`
LinePriceRange string `json:"line_price_range"`
ProfitRange string `json:"profit_range"`
WeightRange string `json:"weight_range"`
}

type GoodsListReq struct {
Title string `form:"title"`
MerchantName string `form:"merchant_name"`
PageId string `form:"page"`
PageSize string `form:"limit"`
}

+ 79
- 0
supply/md/shipping_template.go View File

@@ -0,0 +1,79 @@
package md

//
type MallShippingTemplateReq struct {
MerchantId int `json:"merchant_id" label:"商家id"`
Id int `json:"id" label:"not null pk autoincr INT(11)"`
Name string `json:"name" label:"模板名称" binding:"required"`
Data []MallShippingTemplateData `json:"data" label:"运费数据" binding:"required"`
CalculateType int `json:"calculateType" label:"计费方式:1按重量 2按件数" binding:"required"`
//云链额外字段
CloudChainTemId string `json:"cloud_chain_tem_id"`
}

type MallShippingTemplateData struct {
Regions []string `json:"region" label:"省/市/区(县)" label:"省市区的id"`
AdditionalAmount string `json:"additionalAmount" label:"续件/续重"`
AdditionalFee string `json:"additionalFee" label:"续费"`
FirstAmount string `json:"firstAmount" label:"首件/首重"`
FirstFee string `json:"firstFee" label:"运费"`
}

//
type MallShippingTemplateListResp struct {
Id int `json:"id" label:"not null pk autoincr INT(11)"`
Name string `json:"name" label:"模板名称" binding:"required"`
RegionRules RegionRule `json:"regionRules"`
Data []MallShippingTemplateData `json:"data" label:"运费数据" binding:"required"`
CalculateType int `json:"calculateType" label:"计费方式:1按重量 2按件数" binding:"required"`
CreateTime string `json:"createTime"`
}

type RegionRule struct {
City map[string]int `json:"city"`
County map[string]int `json:"county"`
Provice map[string]int `json:"provice"`
}

// 复制模板请求
type CopyOrDelMallShippingTemplateReq struct {
Id int `json:"id" binding:"required"`
}

// list
type MallShippingTemplateListReq struct {
MerchantId int `json:"merchantId"`
Name string `json:"name"`
CalculateType int `json:"calculateType"`
P int `json:"page"`
PSize int `json:"pSize"`
}

// 地区
type Region struct {
Index int `json:"index"`
Part string `json:"part"`
Provinces []*Province `json:"provinces"`
}

type Province struct {
Cities []*City `json:"cities"`
Name string `json:"name"`
RegionID string `json:"regionId"`
}

type City struct {
Counties []*County `json:"counties"`
Name string `json:"name"`
RegionID string `json:"regionId"`
}

type County struct {
Name string `json:"name"`
RegionID string `json:"regionId"`
}

type ShippingTemplateForGoodsList struct {
ShippingTemplateId int `json:"shipping_template_id" label:"模板id"`
Name string `json:"name" label:"模板名称"`
}

+ 16
- 0
supply/svc/svc_comm.go View File

@@ -0,0 +1,16 @@
package svc

import (
"github.com/gin-gonic/gin"
)

// JudgeFenXiaoChannel 判断分销渠道
func JudgeFenXiaoChannel(c *gin.Context) (aliCloudChainFenXiaoAccessToken, aliCloudChainFenXiaoAppkey, aliCloudChainFenXiaoAppSecret, aliCloudChainAppkey, aliCloudChainAppSecret, aliCloudChainAccessToken string) {
aliCloudChainFenXiaoAccessToken = SysCfgGet(c, "ali_cloud_chain_fen_xiao_accessToken")
aliCloudChainFenXiaoAppkey = SysCfgGet(c, "ali_cloud_chain_fen_xiao_appkey")
aliCloudChainFenXiaoAppSecret = SysCfgGet(c, "ali_cloud_chain_fen_xiao_appSecret")
aliCloudChainAppkey = SysCfgGet(c, "ali_cloud_chain_appkey")
aliCloudChainAppSecret = SysCfgGet(c, "ali_cloud_chain_appSecret")
aliCloudChainAccessToken = SysCfgGet(c, "ali_cloud_chain_accessToken")
return
}

+ 67
- 0
supply/svc/svc_file_img_format.go View File

@@ -0,0 +1,67 @@
package svc

import (
"applet/app/utils"
"fmt"
"github.com/gin-gonic/gin"
"strings"
)

//ImageFormat is 格式化 图片
func ImageFormat(c *gin.Context, name string) string {
if strings.Contains(name, "https:") || strings.Contains(name, "http:") {
return name
}
scheme := SysCfgGet(c, "file_bucket_scheme")
domain := SysCfgGet(c, "file_bucket_host")
return fmt.Sprintf("%s://%s/%s", scheme, domain, name)
}

//OffImageFormat is 格式化官方 图片
func OffImageFormat(c *gin.Context, name string) string {
if strings.Contains(name, "https:") || strings.Contains(name, "http:") {
return name
}
return fmt.Sprintf("%s://%s/%s", "http", "ossq.izhyin.cn", name)
}

// ImageBucket is 获取域名
func ImageBucket(c *gin.Context) (string, string) {
return SysCfgGet(c, "file_bucket_scheme"), SysCfgGet(c, "file_bucket_host")
}

// ImageFormatWithBucket is 格式化成oss 域名
func ImageFormatWithBucket(scheme, domain, name string) string {
return fmt.Sprintf("%s://%s/%s", scheme, domain, name)
}

// ImageBucketNew is 获取域名
func ImageBucketNew(c *gin.Context) (string, string, string, map[string]string) {
var list = make(map[string]string, 0)
for i := 1; i < 10; i++ {
keys := "file_bucket_sub_host" + utils.IntToStr(i)
list[keys] = SysCfgGet(c, keys)
}
return SysCfgGet(c, "file_bucket_scheme"), SysCfgGet(c, "file_bucket_host"), SysCfgGet(c, "file_bucket_sub_host"), list
}

// ImageFormatWithBucket is 格式化成oss 域名
func ImageFormatWithBucketNew(scheme, domain, subDomain string, moreSubDomain map[string]string, name string) string {
if strings.Contains(name, "http") {
return name
}
if strings.Contains(name, "{{subhost}}") && subDomain != "" { //读副域名 有可能是其他平台的
domain = subDomain
}
//为了兼容一些客户自营商城导到不同系统 并且七牛云不一样
for i := 1; i < 10; i++ {
keys := "file_bucket_sub_host" + utils.IntToStr(i)
if strings.Contains(name, "{{subhost"+utils.IntToStr(i)+"}}") && moreSubDomain[keys] != "" {
domain = moreSubDomain[keys]
}
name = strings.ReplaceAll(name, "{{subhost"+utils.IntToStr(i)+"}}", "")
}
name = strings.ReplaceAll(name, "{{host}}", "")
name = strings.ReplaceAll(name, "{{subhost}}", "")
return fmt.Sprintf("%s://%s/%s", scheme, domain, name)
}

+ 692
- 0
supply/svc/svc_goods.go View File

@@ -0,0 +1,692 @@
package svc

import (
"applet/app/db"
"applet/app/e"
svc2 "applet/app/svc"
"applet/app/utils"
"applet/app/utils/cache"
"applet/app/utils/logx"
db2 "applet/supply/db"
"applet/supply/db/model"
"applet/supply/enum"
"applet/supply/md"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/copier"
cregex "github.com/mingrammer/commonregex"
"github.com/shopspring/decimal"
"regexp"
"strings"
"time"
)

//处理图片
func DealImg(c *gin.Context, imageListUrl []string) []string {
//七牛云配置
scheme, host, subDomain, moreSubDomain := ImageBucketNew(c)
domain := fmt.Sprintf("%s://%s/", scheme, host)
secondDomain := fmt.Sprintf("%s://%s/", scheme, subDomain)
fmt.Println("")
//处理图片链接
for k, v := range imageListUrl {
imageListUrl[k] = strings.ReplaceAll(v, domain, "{{host}}")
imageListUrl[k] = strings.ReplaceAll(imageListUrl[k], secondDomain, "{{subhost}}")
//兼容商品是迁移过来的
for moreK, moreV := range moreSubDomain {
keys := strings.ReplaceAll(moreK, "file_bucket_sub_host", "")
moreDomain := fmt.Sprintf("%s://%s/", scheme, moreV)
imageListUrl[k] = strings.ReplaceAll(imageListUrl[k], moreDomain, "{{subhost"+keys+"}}")
}
}
return imageListUrl
}

func CloudChainFenXiaoGoodsChangeMallGoods(c *gin.Context, cloudChainGoods map[string]interface{}, mallGoods *md.AddGoodsReq) error {
defer func() {
if err := recover(); err != nil {
logx.Error(err)
}
}()
productInfo, ok := cloudChainGoods["productInfo"].(map[string]interface{})
if !ok {
return logx.Error("错误的数据")
}
shippingInfo, ok := productInfo["shippingInfo"].(map[string]interface{})
if !ok {
return logx.Error("错误的数据")
}
tem, err := CloudChainGoodsShippingTemChangeMallShippingTem(c, shippingInfo, mallGoods.Base.CloudChainGoodsId, mallGoods.Base.MerchantId)
if err != nil {
return err
}
key := fmt.Sprintf("%s:merchant_1688_line_price_rete", c.GetString("mid"))
rate, _ := cache.GetString(key)
if rate == "" {
rate = "50"
}
rateD, _ := decimal.NewFromString(rate)
rateD = rateD.Div(decimal.NewFromInt(100))
rate = rateD.String()
rateF := utils.AnyToFloat64(rate)
mallGoods.Base.GoodsCode = "f1x688" + mallGoods.Base.CloudChainGoodsId
mallGoods.Base.ShippingType = enum.MallShippingTypeExpress
if tem.Id == 1 && tem.CloudChainTemId == "1" {
mallGoods.Base.ShippingFeeType = enum.MallShippingFeeTypeUnify
mallGoods.Base.ShippingTplID = 0
mallGoods.Base.ShippingFee = "0"
} else if tem.Id == 0 && tem.CloudChainTemId == "1" {
mallGoods.Base.ShippingFeeType = enum.MallShippingFeeTypeUnify
mallGoods.Base.ShippingTplID = 0
mallGoods.Base.ShippingFee = "0"
} else if tem.Id == 0 && tem.CloudChainTemId != "" {
mallGoods.Base.ShippingFeeType = enum.MallShippingFeeTypeUnify
mallGoods.Base.ShippingTplID = 0
mallGoods.Base.ShippingFee = "0"
} else {
mallGoods.Base.ShippingFeeType = enum.MallShippingFeeTypeTpl
mallGoods.Base.ShippingTplID = tem.Id
}
//将1688的商品属性转换成custom_property
var cloudChainGoodsSpeMap []struct {
GroupName string `json:"group_name" label:"属性组别名称"`
Index int `json:"index" label:"属性值索引"`
Name string `json:"name" label:"属性值"`
} // 自定义参数
type Attribute struct {
AttributeID int64 `json:"attributeID"`
AttributeName string `json:"attributeName"`
IsCustom bool `json:"isCustom"`
Value string `json:"value"`
}
var attributes []*Attribute
utils.Unserialize([]byte(utils.SerializeStr(productInfo["attributes"])), &attributes)
for index, attribute := range attributes {
cloudChainGoodsSpeMap = append(cloudChainGoodsSpeMap, struct {
GroupName string `json:"group_name" label:"属性组别名称"`
Index int `json:"index" label:"属性值索引"`
Name string `json:"name" label:"属性值"`
}{
attribute.AttributeName,
index,
attribute.Value,
})
}
//标题
mallGoods.Base.Title = utils.AnyToString(productInfo["subject"])
mallGoods.Base.CustomProperty = cloudChainGoodsSpeMap
//最低限购
mallGoods.Base.MinOrderQuantity = utils.AnyToString(productInfo["saleInfo"].(map[string]interface{})["minOrderQuantity"])
//商品主图
utils.Unserialize([]byte(utils.SerializeStr(productInfo["image"].(map[string]interface{})["images"])),
&mallGoods.Base.ImageList)
for i, image := range mallGoods.Base.ImageList {
//https://cbu01.alicdn.com/
if !strings.Contains(image, "https") || !strings.Contains(image, "http") {
if !strings.Contains(image, "https://cbu01.alicdn.com") {
mallGoods.Base.ImageList[i] = "https://cbu01.alicdn.com/" + image
}
}
}
//商品详情图
if _, ok := productInfo["description"]; ok {
compile := regexp.MustCompile("src=\"https://.*?\"")
tmpsLinks := compile.FindAllString(utils.AnyToString(productInfo["description"]), -1)
Links := cregex.Links(utils.AnyToString(tmpsLinks))
mallGoods.Base.Detail = Links
if len(mallGoods.Base.Detail) == 0 {
mallGoods.Base.Detail = mallGoods.Base.ImageList
}
} else {
if _, ok := productInfo["intelligentInfo"]; ok {
utils.Unserialize([]byte(utils.SerializeStr(productInfo["intelligentInfo"].(map[string]interface{})["descriptionImages"])),
&mallGoods.Base.Detail)
if len(mallGoods.Base.Detail) == 0 {
mallGoods.Base.Detail = mallGoods.Base.ImageList
}
} else {
mallGoods.Base.Detail = mallGoods.Base.ImageList
}
}
//处理sku
type skuAttribute struct {
AttributeID int64 `json:"attributeID"`
AttributeName string `json:"attributeName"`
AttributeValue string `json:"attributeValue"`
SkuImageURL string `json:"skuImageUrl,omitempty"`
}
type skuInfo struct {
RetailPrice float64 `json:"retailPrice"` //建议零售价
AmountOnSale int `json:"amountOnSale"` //可销售数量
Attributes []skuAttribute `json:"attributes"` //SKU属性值,可填多组信息
CargoNumber string `json:"cargoNumber"` //指定规格的货号
ConsignPrice float64 `json:"consignPrice"` //分销基准价。代销场景均使用该价格。无SKU商品查看saleInfo中的consignPrice
Price float64 `json:"price"` // 报价时该规格的单价
ChannelPrice float64 `json:"channelPrice"` // 厂货通渠道专享价(单位:元)
CpsSuggestPrice float64 `json:"cpsSuggestPrice"` //CPS建议价(单位:元)
SkuID int64 `json:"skuId"` //skuId,该规格在所有商品中的唯一标记
SpecID string `json:"specId"` //specId,该规格在本商品内的唯一标记
}
var skuInfos []*skuInfo
utils.Unserialize([]byte(utils.SerializeStr(productInfo["skuInfos"])), &skuInfos)
BaseSpe := make(map[string]map[string]string)
for _, info := range skuInfos {
for _, attribute := range info.Attributes {
valuesMap := BaseSpe[attribute.AttributeName]
if valuesMap == nil {
valuesMap = make(map[string]string)
}
valuesMap[attribute.AttributeValue] = ""
BaseSpe[attribute.AttributeName] = valuesMap
}
}
for name, valueMap := range BaseSpe {
var spe md.Spe
spe.Name = name
values := make([]string, 0)
for value, _ := range valueMap {
values = append(values, value)
}
spe.Values = values
mallGoods.Base.Spe = append(mallGoods.Base.Spe, spe)
}
for _, info := range skuInfos {
var skuMd md.MallGoodsSku
consignPrice := info.ConsignPrice
if info.RetailPrice > 0 {
consignPrice = info.RetailPrice
} else {
if consignPrice < info.ChannelPrice {
consignPrice = info.ChannelPrice
}
}
skuMd.LinePrice = utils.AnyToString(consignPrice + consignPrice*rateF)
skuMd.Price = utils.AnyToString(consignPrice)
skuMd.Stock = info.AmountOnSale
skuMd.CloudChainSkuId = utils.AnyToString(info.SkuID)
skuMd.SpecID = info.SpecID
skuMd.Weight = utils.AnyToString(shippingInfo["unitWeight"])
skuMd.SkuCode = "f1x688" + skuMd.CloudChainSkuId
if len(info.Attributes) > 0 {
skuMd.CloudChainSkuImgUrl = info.Attributes[0].SkuImageURL
//https://cbu01.alicdn.com/
if !strings.Contains(skuMd.CloudChainSkuImgUrl, "https") || !strings.Contains(skuMd.CloudChainSkuImgUrl, "http") {
if !strings.Contains(skuMd.CloudChainSkuImgUrl, "https://cbu01.alicdn.com") {
skuMd.CloudChainSkuImgUrl = "https://cbu01.alicdn.com/" + skuMd.CloudChainSkuImgUrl
}
}
}
skuSkuMap := make(map[string]*md.MallGoodsSkuSku)
for _, attribute := range info.Attributes {
var skuSkuMd md.MallGoodsSkuSku
skuSkuMd.Name = attribute.AttributeName
skuSkuMd.Value = attribute.AttributeValue
_, ok := skuSkuMap[attribute.AttributeName]
if !ok {
skuMd.Sku = append(skuMd.Sku, skuSkuMd)
skuSkuMap[attribute.AttributeName] = &skuSkuMd
} else {
break
}
}
mallGoods.SkuList = append(mallGoods.SkuList, &skuMd)
}
if len(mallGoods.SkuList) == 0 {
type PriceRange struct {
Price float64 `json:"price"`
StartQuantity int `json:"startQuantity"`
}
type saleInfo struct {
AmountOnSale int `json:"amountOnSale"`
MinOrderQuantity int `json:"minOrderQuantity"`
MixWholeSale bool `json:"mixWholeSale"`
PriceAuth bool `json:"priceAuth"`
PriceRanges []PriceRange `json:"priceRanges"`
QuoteType int `json:"quoteType"`
SupportOnlineTrade bool `json:"supportOnlineTrade"`
Unit string `json:"unit"`
BatchNumber int `json:"batchNumber"`
RetailPrice float64 `json:"retailprice"`
Sellunit string `json:"sellunit"`
ConsignPrice float64 `json:"consignPrice"`
CpsSuggestPrice float64 `json:"cpsSuggestPrice"`
ChannelPrice float64 `json:"channelPrice"`
}
var saleInfoMd saleInfo
utils.Unserialize([]byte(utils.SerializeStr(productInfo["saleInfo"])), &saleInfoMd)
consignPrice := saleInfoMd.ConsignPrice
if consignPrice < saleInfoMd.ChannelPrice {
consignPrice = saleInfoMd.ChannelPrice
}
for _, priceRange := range saleInfoMd.PriceRanges {
if consignPrice < priceRange.Price {
consignPrice = priceRange.Price
}
}
var skuMd md.MallGoodsSku
skuMd.LinePrice = utils.AnyToString(consignPrice + consignPrice*rateF)
skuMd.Price = utils.AnyToString(consignPrice)
skuMd.Stock = saleInfoMd.AmountOnSale
skuMd.CloudChainSkuId = utils.AnyToString(mallGoods.Base.CloudChainGoodsId)
skuMd.SpecID = ""
skuMd.Weight = utils.AnyToString(shippingInfo["unitWeight"])
skuMd.Sku = make([]md.MallGoodsSkuSku, 0)
mallGoods.SkuList = append(mallGoods.SkuList, &skuMd)
}
return nil
}

func CalculateFirstAddPriceNumByMainSystem(price float64) float64 {
var basicSetting model.SupplyBasicSetting
get, _ := db.Db.Get(&basicSetting)
if get {
if basicSetting.PriceAdjustBaseType == 2 {
if basicSetting.PriceAdjustType == 1 {
afterPrice := price + utils.StrToFloat64(basicSetting.PriceAdjustValue)
return afterPrice
} else if basicSetting.PriceAdjustType == 2 {
afterPrice := price + (price * (utils.StrToFloat64(basicSetting.PriceAdjustValue) / 100))
return afterPrice
}
}
return price
}
return price
}

func CloudChainGoodsChangeMallGoodsV2(c *gin.Context, cloudChainGoods map[string]interface{}, mallGoods *md.AddGoodsReq) error {
defer func() {
if err := recover(); err != nil {
logx.Error(err)
}
}()
productInfo, ok := cloudChainGoods["productInfo"].(map[string]interface{})
if !ok {
return logx.Error("错误的数据")
}
shippingInfo, ok := productInfo["shippingInfo"].(map[string]interface{})
if !ok {
return logx.Error("错误的数据")
}
key := fmt.Sprintf("%s:merchant_1688_line_price_rete", c.GetString("mid"))
rate, _ := cache.GetString(key)
if rate == "" {
rate = "50"
}
rateD, _ := decimal.NewFromString(rate)
rateD = rateD.Div(decimal.NewFromInt(100))
rate = rateD.String()
rateF := utils.AnyToFloat64(rate)
mallGoods.Base.ShippingType = enum.MallShippingTypeExpress
//将1688的商品属性转换成spe
cloudChainGoodsSpeMap := make(map[string][]string)
type Attribute struct {
AttributeID int64 `json:"attributeID"`
AttributeName string `json:"attributeName"`
IsCustom bool `json:"isCustom"`
Value string `json:"value"`
}
var attributes []*Attribute
utils.Unserialize([]byte(utils.SerializeStr(productInfo["attributes"])), &attributes)
for _, attribute := range attributes {
cloudChainGoodsSpeMap[attribute.AttributeName] = append(cloudChainGoodsSpeMap[attribute.AttributeName], attribute.Value)
}
//标题
mallGoods.Base.Title = utils.AnyToString(productInfo["subject"])
//最低限购
mallGoods.Base.MinOrderQuantity = utils.AnyToString(productInfo["saleInfo"].(map[string]interface{})["minOrderQuantity"])
//商品主图
utils.Unserialize([]byte(utils.SerializeStr(productInfo["image"].(map[string]interface{})["images"])),
&mallGoods.Base.ImageList)
for i, image := range mallGoods.Base.ImageList {
//https://cbu01.alicdn.com/
if !strings.Contains(image, "https") || !strings.Contains(image, "http") {
if !strings.Contains(image, "https://cbu01.alicdn.com") {
mallGoods.Base.ImageList[i] = "https://cbu01.alicdn.com/" + image
}
}
}
//商品详情图
if _, ok := productInfo["description"]; ok {
Links := cregex.Links(utils.AnyToString(productInfo["description"]))
mallGoods.Base.Detail = Links
if len(mallGoods.Base.Detail) == 0 {
mallGoods.Base.Detail = mallGoods.Base.ImageList
}
} else {
if _, ok := productInfo["intelligentInfo"]; ok {
utils.Unserialize([]byte(utils.SerializeStr(productInfo["intelligentInfo"].(map[string]interface{})["descriptionImages"])),
&mallGoods.Base.Detail)
if len(mallGoods.Base.Detail) == 0 {
mallGoods.Base.Detail = mallGoods.Base.ImageList
}
for i, img := range mallGoods.Base.Detail {
if strings.Contains("\\", img) {
mallGoods.Base.Detail[i] = strings.ReplaceAll(img, "\\", "")
}
}
} else {
mallGoods.Base.Detail = mallGoods.Base.ImageList
}
}
//处理sku
type skuAttribute struct {
AttributeID int64 `json:"attributeID"`
AttributeName string `json:"attributeName"`
AttributeValue string `json:"attributeValue"`
SkuImageURL string `json:"skuImageUrl,omitempty"`
}
type skuInfo struct {
RetailPrice float64 `json:"retailPrice"` //建议零售价
AmountOnSale int `json:"amountOnSale"` //可销售数量
Attributes []skuAttribute `json:"attributes"` //SKU属性值,可填多组信息
CargoNumber string `json:"cargoNumber"` //指定规格的货号
ConsignPrice float64 `json:"consignPrice"` //分销基准价。代销场景均使用该价格。无SKU商品查看saleInfo中的consignPrice
Price float64 `json:"price"` // 报价时该规格的单价
ChannelPrice float64 `json:"channelPrice"` // 厂货通渠道专享价(单位:元)
CpsSuggestPrice float64 `json:"cpsSuggestPrice"` //CPS建议价(单位:元)
SkuID int64 `json:"skuId"` //skuId,该规格在所有商品中的唯一标记
SpecID string `json:"specId"` //specId,该规格在本商品内的唯一标记
}
var skuInfos []*skuInfo
utils.Unserialize([]byte(utils.SerializeStr(productInfo["skuInfos"])), &skuInfos)
BaseSpe := make(map[string]map[string]string)
for _, info := range skuInfos {
for _, attribute := range info.Attributes {
valuesMap := BaseSpe[attribute.AttributeName]
if valuesMap == nil {
valuesMap = make(map[string]string)
}
valuesMap[attribute.AttributeValue] = ""
BaseSpe[attribute.AttributeName] = valuesMap
}
}
for name, valueMap := range BaseSpe {
var spe md.Spe
spe.Name = name
values := make([]string, 0)
for value, _ := range valueMap {
values = append(values, value)
}
spe.Values = values
mallGoods.Base.Spe = append(mallGoods.Base.Spe, spe)
}
for _, info := range skuInfos {
var skuMd md.MallGoodsSku
consignPrice := info.ConsignPrice
if info.RetailPrice > 0 {
consignPrice = info.RetailPrice
} else {
if consignPrice < info.ChannelPrice {
consignPrice = info.ChannelPrice
}
}
skuMd.LinePrice = utils.AnyToString(consignPrice + consignPrice*rateF)
skuMd.Price = utils.AnyToString(consignPrice)
skuMd.Stock = info.AmountOnSale
skuMd.CloudChainSkuId = utils.AnyToString(info.SkuID)
skuMd.SpecID = info.SpecID
skuMd.Weight = utils.AnyToString(shippingInfo["unitWeight"])
if len(info.Attributes) > 0 {
skuMd.CloudChainSkuImgUrl = info.Attributes[0].SkuImageURL
//https://cbu01.alicdn.com/
if skuMd.CloudChainSkuImgUrl != "" {
if !strings.Contains(skuMd.CloudChainSkuImgUrl, "https") || !strings.Contains(skuMd.CloudChainSkuImgUrl, "http") {
if !strings.Contains(skuMd.CloudChainSkuImgUrl, "https://cbu01.alicdn.com") {
skuMd.CloudChainSkuImgUrl = "https://cbu01.alicdn.com/" + skuMd.CloudChainSkuImgUrl
}
}
}
}
skuSkuMap := make(map[string]*md.MallGoodsSkuSku)
for _, attribute := range info.Attributes {
var skuSkuMd md.MallGoodsSkuSku
skuSkuMd.Name = attribute.AttributeName
skuSkuMd.Value = attribute.AttributeValue
_, ok := skuSkuMap[attribute.AttributeName]
if !ok {
skuMd.Sku = append(skuMd.Sku, skuSkuMd)
skuSkuMap[attribute.AttributeName] = &skuSkuMd
} else {
break
}
}
mallGoods.SkuList = append(mallGoods.SkuList, &skuMd)
}
if len(mallGoods.SkuList) == 0 {
type PriceRange struct {
Price float64 `json:"price"`
StartQuantity int `json:"startQuantity"`
}
type saleInfo struct {
AmountOnSale int `json:"amountOnSale"`
MinOrderQuantity int `json:"minOrderQuantity"`
MixWholeSale bool `json:"mixWholeSale"`
PriceAuth bool `json:"priceAuth"`
PriceRanges []PriceRange `json:"priceRanges"`
QuoteType int `json:"quoteType"`
SupportOnlineTrade bool `json:"supportOnlineTrade"`
Unit string `json:"unit"`
BatchNumber int `json:"batchNumber"`
RetailPrice float64 `json:"retailprice"`
Sellunit string `json:"sellunit"`
ConsignPrice float64 `json:"consignPrice"`
CpsSuggestPrice float64 `json:"cpsSuggestPrice"`
ChannelPrice float64 `json:"channelPrice"`
}
var saleInfoMd saleInfo
utils.Unserialize([]byte(utils.SerializeStr(productInfo["saleInfo"])), &saleInfoMd)
consignPrice := saleInfoMd.ConsignPrice
if saleInfoMd.RetailPrice > 0 {
consignPrice = saleInfoMd.RetailPrice
} else {
if consignPrice < saleInfoMd.ChannelPrice {
consignPrice = saleInfoMd.ChannelPrice
}
for _, priceRange := range saleInfoMd.PriceRanges {
if consignPrice < priceRange.Price {
consignPrice = priceRange.Price
}
}
}
var skuMd md.MallGoodsSku
skuMd.LinePrice = utils.AnyToString(consignPrice + consignPrice*rateF)
skuMd.Price = utils.AnyToString(consignPrice)
skuMd.Stock = saleInfoMd.AmountOnSale
skuMd.CloudChainSkuId = utils.AnyToString(mallGoods.Base.CloudChainGoodsId)
skuMd.SpecID = ""
skuMd.Weight = utils.AnyToString(shippingInfo["unitWeight"])
skuMd.Sku = make([]md.MallGoodsSkuSku, 0)
mallGoods.SkuList = append(mallGoods.SkuList, &skuMd)
}
return nil
}

// AddMallGoods 添加、编辑商品
func AddMallGoods(c *gin.Context, req *md.AddGoodsReq) error {
if req.Base.GoodsId != "" {
_, has, err := db.GetComm(svc2.MasterDb(c), &model.MallGoods{GoodsId: utils.StrToInt64(req.Base.GoodsId)})
if err != nil {
return e.NewErr(e.ERR_DB_ORM, err.Error())
}
if !has {
return e.NewErr(e.ERR_INVALID_ARGS, "编辑的商品ID不存在")
}
}

sess := svc2.MasterDb(c).NewSession()
defer func() {
_ = sess.Close()
}()
err := sess.Begin()
if err != nil {
return e.NewErr(e.ERR_DB_ORM, err.Error())
}
// 基本信息保存
var goodsModel model.MallGoods
err = copier.Copy(&goodsModel, req.Base)
goodsModel.GoodsId = utils.StrToInt64(req.Base.GoodsId)
if err != nil {
return e.NewErr(e.ERR_DB_ORM, err.Error())
}
now := time.Now()
goodsModel.CloudChainGoodsId = req.Base.CloudChainGoodsId
goodsModel.MinOrderQuantity = req.Base.MinOrderQuantity
goodsModel.SaleState = 0 //TODO::所有商家端编辑的产品,都需要重新审核
goodsModel.MerchantId = req.Base.MerchantId

goodsModel.GoodsCode = req.Base.GoodsCode
goodsModel.CreateTime = now
goodsModel.UpdateTime = now
goodsModel.CustomProperty = utils.SerializeStr(req.Base.CustomProperty)
SaleStartTime, _ := utils.TimeParse("2006-01-02 15:04:05", req.Base.SaleStartTime)
goodsModel.SaleStartTime = SaleStartTime
//处理图片链接
req.Base.ImageListUrl = DealImg(c, req.Base.ImageList)
goodsModel.ImageList = utils.SerializeStr(req.Base.ImageListUrl)
goodsModel.Spe = utils.SerializeStr(req.Base.Spe)
//处理图片链接
req.Base.SpeImagesUrl = DealImg(c, req.Base.SpeImages)
goodsModel.SpeImages = utils.SerializeStr(req.Base.SpeImagesUrl)
//处理图片链接
req.Base.DetailUrl = DealImg(c, req.Base.Detail)
goodsModel.Detail = utils.SerializeStr(req.Base.DetailUrl) // detail为详情图列表
if req.Base.Service != nil {
goodsModel.Service = utils.SerializeStr(req.Base.Service) // 支持的服务
}
goodsModel.IsSpeImageInDetail = req.Base.IsSpeImageInDetail
goodsModel.IsSpeImageOn = req.Base.IsSpeImageOn

goodsModel.ShippingFeeType = int(req.Base.ShippingFeeType)
goodsModel.ShippingFee = req.Base.ShippingFee
goodsModel.ShippingTplId = req.Base.ShippingTplID
if req.Base.GoodsId == "" {
category, err := db2.GetCategoryById(svc2.MasterDb(c), utils.AnyToString(req.Base.CategoryId))
if err != nil {
_ = sess.Rollback()
return err
}
goodsId, err := MakeGoodsId(c, utils.AnyToString(category.McId), utils.AnyToString(req.Base.CategoryId), utils.AnyToString(goodsModel.MerchantId))
if err != nil {
_ = sess.Rollback()
return err
}
goodsModel.GoodsId = utils.StrToInt64(goodsId)
merchant, err := db2.GetMerchantById(svc2.MasterDb(c), goodsModel.MerchantId)
if err != nil {
_ = sess.Rollback()
return err
}
if merchant == nil {
_ = sess.Rollback()
return errors.New("未查询到对应供应商商家记录")
}

goodsModel.SaleState = 1
if merchant.IsOpenAuditGoods == 1 {
goodsModel.SaleState = 0
}
affect, err := sess.Insert(&goodsModel)
if err != nil || affect != 1 {
_ = sess.Rollback()
return e.NewErr(e.ERR_DB_ORM, "插入商品失败")
}
} else {
affect, err := sess.Where("goods_id=?", req.Base.GoodsId).AllCols().Update(&goodsModel)
if err != nil || affect != 1 {
return e.NewErr(e.ERR_DB_ORM, "更新商品失败")
}
}

// 统计总库存
var stockAll int

// sku保存
// 创建商品,则全部为插入
skuModelList := make([]*model.MallSku, 0, len(req.SkuList))
for key, item := range req.SkuList {
stockAll += item.Stock
skuModelList = append(skuModelList, &model.MallSku{
SkuId: utils.StrToInt64(utils.AnyToString(goodsModel.GoodsId) + utils.AnyToString(key)),
GoodsId: goodsModel.GoodsId,
SkuCode: item.SkuCode,
Price: item.Price,
LinePrice: item.LinePrice,
Weight: item.Weight,
Stock: item.Stock,
Indexes: GetIndexesStr(&req.Base, item),
Sku: utils.SerializeStr(&item.Sku),
CreateTime: now,
UpdateTime: now,
SpecId: item.SpecID,
CloudChainSkuId: item.CloudChainSkuId,
CloudChainSkuImgUrl: item.CloudChainSkuImgUrl,
})
}
if req.Base.GoodsId != "" {
// 如果是更新 先删除旧的再插入
_, err = sess.Delete(&model.MallSku{GoodsId: goodsModel.GoodsId})
if err != nil {
return e.NewErr(e.ERR_DB_ORM, "规格更新失败")
}
}

// 插入sku
insert, err := sess.Insert(skuModelList)
if err != nil {
fmt.Println(err)
logx.Warn(err)
return err
}
if insert < 1 {
return e.NewErr(e.ERR_DB_ORM, "插入商品规格失败")
}

minProfit := GetMinProfitRate(skuModelList)
minPrice := GetMinPrice(skuModelList)

// 更新总库存
_, err = sess.Where("goods_id=?", goodsModel.GoodsId).Update(&model.MallGoods{
Stock: stockAll,
ProfitRate: utils.AnyToString(minProfit),
Price: utils.AnyToString(minPrice),
})
if err != nil {
return e.NewErr(e.ERR_DB_ORM, "更新总库存失败")
}

err = sess.Commit()
if err != nil {
return e.NewErr(e.ERR_DB_ORM, "更新商品失败")
}
return nil
}

func MakeGoodsId(c *gin.Context, mcId, categoryId, merchantId string) (string, error) {

var goodsId = mcId + utils.AnyToString(time.Now().UnixNano()/1e6)

return goodsId, nil
}

func GetIndexesStr(baseGoods *md.MallBaseGoods, goodsSku *md.MallGoodsSku) string {
spe := baseGoods.Spe
sku := goodsSku.Sku

result := ""

for index, item := range sku {
for _, itm := range spe {
if item.Name == itm.Name {
for i, v := range spe[index].Values {
if v == item.Value {
result = result + utils.IntToStr(i) + "-"
}
}
}
}
}

return strings.Trim(result, "-")
}

+ 128
- 0
supply/svc/svc_goods_list.go View File

@@ -0,0 +1,128 @@
package svc

import (
"applet/app/utils"
"applet/supply/db/model"
"applet/supply/md"
)

func GetMinProfitRate(skus []*model.MallSku) float64 {
var (
minProfit float64
)
for i, sku := range skus {
priceF := utils.AnyToFloat64(sku.Price)
linePriceF := utils.AnyToFloat64(sku.LinePrice)
profitF := (linePriceF - priceF) / priceF
if i == 0 {
minProfit = profitF
} else {
if profitF < minProfit {
minProfit = profitF
}
}
}

return minProfit
}

func GetMinPrice(skus []*model.MallSku) float64 {
var (
minPrice float64
)
for i, sku := range skus {
priceF := utils.AnyToFloat64(sku.Price)
if i == 0 {
minPrice = priceF
} else {
if priceF < minPrice {
minPrice = priceF
}
}
}

return minPrice
}

func GetGoodsRangeData(skus []model.MallSku) md.GoodsRangeData {
var (
result md.GoodsRangeData
minPrice float64
maxPrice float64
minLinePrice float64
maxLinePrice float64
minProfit float64
maxProfit float64
minWeight float64
maxWeight float64
)
for i, sku := range skus {
priceF := utils.AnyToFloat64(sku.Price)
linePriceF := utils.AnyToFloat64(sku.LinePrice)
weightF := utils.AnyToFloat64(sku.Weight)
profitF := (linePriceF - priceF) / priceF * 100 // 利润空间
if i == 0 {
minPrice = priceF
maxPrice = minPrice
minLinePrice = linePriceF
maxLinePrice = minLinePrice
minProfit = profitF
maxProfit = minProfit
minWeight = weightF
maxWeight = minWeight
} else {
if priceF < minPrice {
minPrice = priceF
}
if priceF > maxPrice {
maxPrice = priceF
}

if linePriceF < minLinePrice {
minLinePrice = linePriceF
}
if linePriceF > maxLinePrice {
maxLinePrice = linePriceF
}

if weightF < minWeight {
minWeight = weightF
}
if weightF > maxWeight {
maxWeight = weightF
}

if profitF < minProfit {
minProfit = profitF
}
if profitF > maxProfit {
maxProfit = profitF
}
}
}
if minPrice == maxPrice {
result.PriceRange = utils.AnyToString(minPrice)
} else {
result.PriceRange = utils.AnyToString(minPrice) + "-" + utils.AnyToString(maxPrice)
}

if minLinePrice == maxLinePrice {
result.LinePriceRange = utils.AnyToString(minLinePrice)
} else {
result.LinePriceRange = utils.AnyToString(minLinePrice) + "-" + utils.AnyToString(maxLinePrice)
}

if minProfit == maxProfit {
result.ProfitRange = utils.AnyToString(minProfit) + "%"
} else {
result.ProfitRange = utils.AnyToString(minProfit) + "%-" + utils.AnyToString(maxProfit) + "%"
}

if minWeight == maxWeight {
result.WeightRange = utils.AnyToString(minWeight)
} else {
result.WeightRange = utils.AnyToString(minWeight) + "-" + utils.AnyToString(maxWeight)
}

return result
}

+ 246
- 0
supply/svc/svc_shipping_template.go View File

@@ -0,0 +1,246 @@
package svc

import (
commDb "applet/app/db"
"applet/app/svc"
"applet/app/utils"
"applet/app/utils/logx"
"applet/supply/db"
"applet/supply/db/model"
"applet/supply/md"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/jinzhu/copier"
"github.com/shopspring/decimal"
"strings"
)

func SaveMallShippingTemplate(c *gin.Context, args md.MallShippingTemplateReq) (*model.MallShippingTemplate, error) {
decimal.DivisionPrecision = 2
var (
shippingTemplate model.MallShippingTemplate
err error
)
eg := svc.MasterDb(c)
copier.Copy(&shippingTemplate, &args)
// 区域校验是否出现重复区域
if args.Data != nil && len(args.Data) > 0 {
var regions = make(map[string]string)
var provinces = make(map[string]string)
var city = make(map[string]string)
for _, item := range args.Data {
// 判断首件/首重不能为0
if item.FirstAmount == "" || item.FirstAmount == "0" {
return nil, errors.New("首件/重不能小于0")
}
// 判断价格是否合法
_, err := decimal.NewFromString(item.AdditionalFee)
if err != nil {
return nil, err
}
_, err = decimal.NewFromString(item.FirstFee)
if err != nil {
return nil, err
}
for _, itm := range item.Regions {
// 判断是否重复出现
if itm == "110000000000" {
fmt.Println(itm)
}
if _, ok := regions[itm]; ok {
return nil, errors.New("不能重复选择区域")
} else {
regions[itm] = "1"
}
// 判断是否是省,如果选择省的话表示省下的所有城市及区都应为使用同一条运费价格计算
if len(itm) < 2 {
continue
}
if itm[2:] == "0000000000" {
if _, ok := provinces[itm[:2]]; ok {
return nil, errors.New("不能重复选择区域")
} else {
provinces[itm[:2]] = "1"
}
}
// 判断是否是市,如果选择市的话表示省下的所有城市及区都应为使用同一条运费价格计算
if itm[2:4] != "00" && itm[4:] == "00000000" {
if _, ok := city[itm[:4]]; ok {
return nil, errors.New("不能重复选择区域")
} else {
city[itm[:4]] = "1"
}
}
}
}
regions = nil
provinces = nil
city = nil
}
shippingTemplate.Data = utils.SerializeStr(args.Data)
if args.Id == 0 {
err = db.InsertOneMallShippingTemplate(eg, &shippingTemplate)
} else {
err = db.UpdateMallShippingTemplateById(eg, &shippingTemplate, "name", "data", "calculate_type")
}
if err != nil {
return nil, err
}
return &shippingTemplate, nil
}

func CloudChainGoodsShippingTemChangeMallShippingTem(c *gin.Context, shippingInfo map[string]interface{}, id string, merchantId int) (*model.MallShippingTemplate, error) {
if shippingInfo == nil {
return nil, logx.Error("错误的数据")
}
var mallShippingTem model.MallShippingTemplate
type RateDTO struct {
FirstUnit int `json:"firstUnit" label:"首重(单位:克)或首件(单位:件)"` //首重(单位:克)或首件(单位:件)
FirstUnitFee int `json:"firstUnitFee" label:"首重或首件的价格(单位:分)"` // 首重或首件的价格(单位:分)
NextUnit int `json:"nextUnit" label:"续重件单位"` //续重件单位
NextUnitFee int `json:"nextUnitFee" label:"重件价格(单位:分)"` //重件价格(单位:分)
}
type SubTemplateDTO struct {
ChargeType int `json:"chargeType" label:"计件类型。0:重量 1:件数 2:体积"` //计件类型。0:重量 1:件数 2:体积
IsSysTemplate bool `json:"isSysTemplate" label:"是否系统模板"` //是否系统模板
ServiceType int `json:"serviceType" label:"服务类型。0:快递 1:货运 2:货到付款"` //服务类型。0:快递 1:货运 2:货到付款
Type int `json:"type" label:"子模板类型 0基准 1增值。默认0。"` //子模板类型 0基准 1增值。默认0。
}
type Rate struct {
IsSysRate bool `json:"isSysRate" label:"是否系统模板"` //是否系统模板
RateDTO RateDTO `json:"rateDTO" label:"普通子模板费率"` //普通子模板费率
ToAreaCodeText string `json:"toAreaCodeText" label:"地址编码文本,用顿号隔开。例如:上海、福建省、广东省"` //地址编码文本,用顿号隔开。例如:上海、福建省、广东省
}
type ExpressSubTemplate struct {
RateList []Rate `json:"rateList" label:"费率"` //费率
SubTemplateDTO SubTemplateDTO `json:"subTemplateDTO" label:"子模板"` //子模板
}
type FreightTemplate struct {
AddressCodeText string `json:"addressCodeText" label:"地址区域编码对应的文本(包括省市区,用空格隔开)"` //地址区域编码对应的文本(包括省市区,用空格隔开)
ExpressSubTemplate ExpressSubTemplate `json:"expressSubTemplate" label:"快递子模版"` //快递子模版
FromAreaCode string `json:"fromAreaCode" label:"发货地址地区码"` //发货地址地区码
ID int `json:"id" label:"运费模板ID"` //运费模板ID
}
type ShippingInfo struct {
FreightTemplate []FreightTemplate `json:"freightTemplate" label:"商品运费费率"` //商品运费费率
FreightTemplateID int `json:"freightTemplateID" label:"运费模板ID,0表示运费说明,1表示卖家承担运费,其他值表示使用运费模版。此参数可调用运费模板相关API获取"` //运费模板ID,0表示运费说明,1表示卖家承担运费,其他值表示使用运费模版。此参数可调用运费模板相关API获取
SendGoodsAddressID int `json:"sendGoodsAddressId" label:"发货地址ID"` //发货地址ID
SendGoodsAddressText string `json:"sendGoodsAddressText" label:"发货地描述"` //发货地描述
UnitWeight float64 `json:"unitWeight" label:"重量/毛重"` //重量/毛重
}
var ShippingInfoStruct ShippingInfo
utils.Unserialize([]byte(utils.SerializeStr(shippingInfo)), &ShippingInfoStruct)
if ShippingInfoStruct.FreightTemplateID > 1 {
mallShippingTem.CloudChainTemId = utils.AnyToString(ShippingInfoStruct.FreightTemplateID)
mallShippingTem.MerchantId = merchantId
get, err := mallShippingTem.GetV2(svc.MasterDb(c))
if err != nil {
return nil, err
}
if get {
return &mallShippingTem, nil
}
for _, template1688 := range ShippingInfoStruct.FreightTemplate {
var (
req md.MallShippingTemplateReq
unitRate int
)
if template1688.ExpressSubTemplate.SubTemplateDTO.ChargeType == 0 {
req.CalculateType = 1
unitRate = 1000
} else if template1688.ExpressSubTemplate.SubTemplateDTO.ChargeType == 1 {
req.CalculateType = 2
unitRate = 1
}
req.Name = utils.AnyToString(req.MerchantId) + "云链产品" + id + "运费模版" + utils.AnyToString(template1688.ID)
req.CloudChainTemId = utils.AnyToString(template1688.ID)
req.MerchantId = merchantId
toAreaCode := make(map[string]string)
for _, rate := range template1688.ExpressSubTemplate.RateList {
var mallShippingTemplateData md.MallShippingTemplateData
mallShippingTemplateData.FirstAmount = utils.AnyToString(utils.AnyToFloat64(rate.RateDTO.FirstUnit) / utils.AnyToFloat64(unitRate))
mallShippingTemplateData.FirstFee = utils.AnyToString(utils.AnyToFloat64(rate.RateDTO.FirstUnitFee) / 100)
mallShippingTemplateData.AdditionalAmount = utils.AnyToString(utils.AnyToFloat64(rate.RateDTO.NextUnit) / utils.AnyToFloat64(unitRate))
mallShippingTemplateData.AdditionalFee = utils.AnyToString(utils.AnyToFloat64(rate.RateDTO.NextUnitFee) / 100)
if rate.ToAreaCodeText == "" || rate.ToAreaCodeText == " " {
continue
}
ToAreaCodes := strings.Split(rate.ToAreaCodeText, "、")
for _, code := range ToAreaCodes {
if code == "" || code == " " {
continue
}
if _, ok := toAreaCode[code]; ok {
continue
} else {
toAreaCode[code] = "1"
}
provinceId, err := GetProvinceByName(code)
if err != nil {
logx.Error(err)
continue
}
mallShippingTemplateData.Regions = append(mallShippingTemplateData.Regions, provinceId)
//市
cities, err := GetCitiesByProvinceId(provinceId)
if err != nil {
logx.Error(err)
continue
}
mallShippingTemplateData.Regions = append(mallShippingTemplateData.Regions, cities...)
//县
counties, err := GetCountyByCitiesIds(cities)
if err != nil {
logx.Error(err)
continue
}
mallShippingTemplateData.Regions = append(mallShippingTemplateData.Regions, counties...)
}
if len(mallShippingTemplateData.Regions) == 0 {
continue
}
req.Data = append(req.Data, mallShippingTemplateData)
}
template, err := SaveMallShippingTemplate(c, req)
if err != nil || template == nil {
logx.Error("同步1688运费模版保存出错", err)
return nil, err
}
if ShippingInfoStruct.FreightTemplateID == template1688.ID {
mallShippingTem = *template
}
}
} else if ShippingInfoStruct.FreightTemplateID == 1 {
mallShippingTem.Id = 1
mallShippingTem.CloudChainTemId = "1"
} else if ShippingInfoStruct.FreightTemplateID == 0 {
mallShippingTem.Id = 0
mallShippingTem.CloudChainTemId = "1"
}
return &mallShippingTem, nil
}

func GetProvinceByName(name string) (string, error) {
id := make([]string, 0)
err := commDb.Db.Table("province").Select("id").Where("name LIKE ?", name+"%").Find(&id)
if len(id) > 0 {
if id[0] == "110000000000" {
fmt.Println(name)
}
return id[0], err
}

return "", err
}

func GetCitiesByProvinceId(provinceId string) ([]string, error) {
id := make([]string, 0)
err := commDb.Db.Table("city").Select("id").Where("province_id = ?", provinceId).Find(&id)
return id, err
}
func GetCountyByCitiesIds(citiesIds []string) ([]string, error) {
id := make([]string, 0)
err := commDb.Db.Table("county").Select("id").In("city_id", citiesIds).Find(&id)
return id, err
}

+ 31
- 0
supply/svc/svc_supply_basic_setting.go View File

@@ -0,0 +1,31 @@
package svc

import (
"applet/supply/db/model"
"errors"
"github.com/gin-gonic/gin"
)

func GetSupplyBasicSetting(c *gin.Context) (setting *model.SupplyBasicSetting, err error) {
setting = &model.SupplyBasicSetting{}
//get, _ := db.Db.Get(&setting)
//if get {
aliCloudChainFenXiaoAccessToken, aliCloudChainFenXiaoAppkey, aliCloudChainFenXiaoAppSecret, aliCloudChainAppkey, aliCloudChainAppSecret, aliCloudChainAccessToken := JudgeFenXiaoChannel(c)
if aliCloudChainFenXiaoAccessToken != "" {
setting.AliCloudChainFenXiaoAppkey = aliCloudChainFenXiaoAppkey
setting.AliCloudChainFenXiaoAppsecret = aliCloudChainFenXiaoAppSecret
setting.AliCloudChainFenXiaoAccesstoken = aliCloudChainFenXiaoAccessToken
} else {
err = errors.New("暂未配置《阿里巴巴云链精选》")
return nil, err
}
if aliCloudChainAccessToken != "" {
setting.AliCloudChainAppkey = aliCloudChainAppkey
setting.AliCloudChainAppsecret = aliCloudChainAppSecret
setting.AliCloudChainAccesstoken = aliCloudChainAccessToken
} else {
err = errors.New("暂未配置《阿里巴巴云链》")
return nil, err
}
return
}

+ 190
- 0
supply/svc/svc_sys_cfg_get.go View File

@@ -0,0 +1,190 @@
package svc

import (
"applet/app/cfg"
"applet/app/db"
"applet/app/utils"
"applet/app/utils/cache"
db2 "applet/supply/db"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/md"
"fmt"
"github.com/gin-gonic/gin"
"xorm.io/xorm"
)

// 单挑记录获取
func SysCfgGet(c *gin.Context, key string) string {
mid := c.GetString("mid")
eg := db.DBs[mid]
return db.SysCfgGetWithDb(eg, mid, key)
}

// 多条记录获取
func SysCfgFind(c *gin.Context, keys ...string) map[string]string {
var masterId string
if c == nil {
masterId = ""
} else {
masterId = c.GetString("mid")
}
tmp := SysCfgFindComm(masterId, keys...)
return tmp
}

// SysCfgGetByMasterId get one config by master id
func SysCfgGetByMasterId(masterId, key string) string {
res := SysCfgFindComm(masterId, key)
if _, ok := res[key]; !ok {
return ""
}
return res[key]
}

// SysCfgFindComm get cfg by master id
func SysCfgFindComm(masterId string, keys ...string) map[string]string {
var eg *xorm.Engine
if masterId == "" {
eg = db.Db
} else {
eg = db.DBs[masterId]
}
res := map[string]string{}

cfgKey := fmt.Sprintf("%s:cfg_cache", masterId)
err := cache.GetJson(cfgKey, &res)
if err != nil || len(res) == 0 {
cfgList, _ := db.SysCfgGetAll(eg)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
cache.SetJson(cfgKey, res, 1800)
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 多条记录获取
func EgSysCfgFind(keys ...string) map[string]string {
var e *xorm.Engine
res := map[string]string{}
if len(res) == 0 {
cfgList, _ := db.SysCfgGetAll(e)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
// 先不设置缓存
// cache.SetJson(md.KEY_SYS_CFG_CACHE, res, 60)
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 清理系统配置信息
func SysCfgCleanCache(c *gin.Context) {
var tmp = []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
for _, v := range tmp {
cacheKey := fmt.Sprintf(md.AppCfgCacheKey, c.GetString("mid"), v)
cache.Del(cacheKey)
}
}

// 写入系统设置
func SysCfgSet(c *gin.Context, key, val, memo string) bool {
cfg, err := db.SysCfgGetOne(db.DBs[c.GetString("mid")], key)
if err != nil || cfg == nil {
return db.SysCfgInsert(db.DBs[c.GetString("mid")], key, val, memo)
}
if memo != "" && cfg.Memo != memo {
cfg.Memo = memo
}
SysCfgCleanCache(c)
return db.SysCfgUpdate(db.DBs[c.GetString("mid")], key, val, cfg.Memo)
}

// 多条记录获取
func SysCfgFindByIds(eg *xorm.Engine, keys ...string) map[string]string {
key := utils.Md5(eg.DataSourceName() + md.KEY_SYS_CFG_CACHE)
res := map[string]string{}
c, ok := cfg.MemCache.Get(key).(map[string]string)
if !ok || len(c) == 0 {
cfgList, _ := db2.DbsSysCfgGetAll(eg)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
cfg.MemCache.Put(key, res, 10)
} else {
res = c
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

// 多条记录获取
func SysCfgFindByIdsToCache(eg *xorm.Engine, dbName string, keys ...string) map[string]string {
key := utils.Md5(dbName + md.KEY_SYS_CFG_CACHE)
res := map[string]string{}
c, ok := cfg.MemCache.Get(key).(map[string]string)
if !ok || len(c) == 0 {
cfgList, _ := db2.DbsSysCfgGetAll(eg)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
cfg.MemCache.Put(key, res, 1800)
} else {
res = c
}
if len(keys) == 0 {
return res
}
tmp := map[string]string{}
for _, v := range keys {
if val, ok := res[v]; ok {
tmp[v] = val
} else {
tmp[v] = ""
}
}
return tmp
}

Loading…
Cancel
Save