Merge branch 'develop' of https://gitee.com/fusenpack/fusenapi into develop

This commit is contained in:
eson
2023-06-28 19:33:00 +08:00
14 changed files with 507 additions and 41 deletions

View File

@@ -22,6 +22,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/inventory/list",
Handler: GetCloudListHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/inventory/supplement",
Handler: SupplementHandler(serverCtx),
},
},
)
}

View File

@@ -0,0 +1,78 @@
package handler
import (
"errors"
"net/http"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/rest/httpx"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/server/inventory/internal/logic"
"fusenapi/server/inventory/internal/svc"
"fusenapi/server/inventory/internal/types"
)
func SupplementHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var (
// 定义错误变量
err error
// 定义用户信息变量
userinfo *auth.UserInfo
)
// 解析JWT token,并对空用户进行判断
claims, err := svcCtx.ParseJwtToken(r)
// 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息
if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 401, // 返回401状态码,表示未授权
Message: "unauthorized", // 返回未授权信息
})
logx.Info("unauthorized:", err.Error()) // 记录错误日志
return
}
if claims != nil {
// 从token中获取对应的用户信息
userinfo, err = auth.GetUserInfoFormMapClaims(claims)
// 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息
if err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 401,
Message: "unauthorized",
})
logx.Info("unauthorized:", err.Error())
return
}
} else {
// 如果claims为nil,则认为用户身份为白板用户
userinfo = &auth.UserInfo{UserId: 0, GuestId: 0}
}
var req types.SupplementReq
// 如果端点有请求结构体则使用httpx.Parse方法从HTTP请求体中解析请求数据
if err := httpx.Parse(r, &req); err != nil {
httpx.OkJsonCtx(r.Context(), w, &basic.Response{
Code: 510,
Message: "parameter error",
})
logx.Info(err)
return
}
// 创建一个业务逻辑层实例
l := logic.NewSupplementLogic(r.Context(), svcCtx)
resp := l.Supplement(&req, userinfo)
// 如果响应不为nil则使用httpx.OkJsonCtx方法返回JSON响应;
if resp != nil {
httpx.OkJsonCtx(r.Context(), w, resp)
} else {
err := errors.New("server logic is error, resp must not be nil")
httpx.ErrorCtx(r.Context(), w, err)
logx.Error(err)
}
}
}

View File

@@ -1,11 +1,15 @@
package logic
import (
"fmt"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/image"
"fusenapi/utils/step_price"
"math"
"strings"
"context"
@@ -38,13 +42,20 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
req.Page = constants.DEFAULT_PAGE
}
if req.PageSize <= 0 || req.PageSize > 200 {
req.Page = constants.DEFAULT_PAGE_SIZE
req.PageSize = constants.DEFAULT_PAGE_SIZE
}
sizeFlag := false
if req.Size >= 200 {
sizeFlag = true
req.Size = int64(image.GetCurrentSize(uint32(req.Size)))
}
//获取个人云仓列表
getStockListStatus := int64(1)
stockList, total, err := l.svcCtx.AllModels.FsUserStock.GetStockList(l.ctx, gmodel.GetStockListReq{
UserId: userinfo.UserId,
Page: int(req.Page),
Limit: int(req.PageSize),
Status: &getStockListStatus,
})
if err != nil {
logx.Error(err)
@@ -60,7 +71,7 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
designIds = append(designIds, *v.DesignId)
}
//获取设计数据
productDesignList, err := l.svcCtx.AllModels.FsProductDesign.GetAllByIds(l.ctx, designIds)
productDesignList, err := l.svcCtx.AllModels.FsProductDesign.GetAllByIdsWithoutStatus(l.ctx, designIds)
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product design list")
@@ -73,23 +84,23 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
templateIds := make([]int64, 0, len(productDesignList))
//配件ids
optionalIds := make([]int64, 0, len(productDesignList))
mapProductDesign := make(map[int64]int)
for k, v := range productDesignList {
mapProductDesign := make(map[int64]gmodel.FsProductDesign)
for _, v := range productDesignList {
sizeIds = append(sizeIds, *v.SizeId)
productIds = append(productIds, *v.ProductId)
templateIds = append(templateIds, *v.TemplateId)
optionalIds = append(optionalIds, *v.OptionalId)
mapProductDesign[v.Id] = k
mapProductDesign[v.Id] = v
}
//获取尺寸信息
sizeList, err := l.svcCtx.AllModels.FsProductSize.GetAllByProductIdsWithoutStatus(l.ctx, sizeIds, "")
sizeList, err := l.svcCtx.AllModels.FsProductSize.GetAllByIdsWithoutStatus(l.ctx, sizeIds, "")
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product size list")
}
mapSize := make(map[int64]int)
for k, v := range sizeList {
mapSize[v.Id] = k
mapSize := make(map[int64]gmodel.FsProductSize)
for _, v := range sizeList {
mapSize[v.Id] = v
}
//获取产品信息
productList, err := l.svcCtx.AllModels.FsProduct.GetProductListByIdsWithoutStatus(l.ctx, productIds, "")
@@ -97,9 +108,9 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product list")
}
mapProduct := make(map[int64]int)
for k, v := range productList {
mapProduct[v.Id] = k
mapProduct := make(map[int64]gmodel.FsProduct)
for _, v := range productList {
mapProduct[v.Id] = v
}
//获取模板信息
productTemplateList, err := l.svcCtx.AllModels.FsProductTemplateV2.FindAllByIdsWithoutStatus(l.ctx, templateIds)
@@ -107,9 +118,9 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product template list")
}
mapTemplate := make(map[int64]int)
for k, v := range productTemplateList {
mapTemplate[v.Id] = k
mapTemplate := make(map[int64]gmodel.FsProductTemplateV2)
for _, v := range productTemplateList {
mapTemplate[v.Id] = v
}
//获取配件列表
productModel3dList, err := l.svcCtx.AllModels.FsProductModel3d.GetAllByIdsWithoutStatus(l.ctx, optionalIds)
@@ -117,9 +128,9 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product 3d model list")
}
mapProductModel := make(map[int64]int)
for k, v := range productModel3dList {
mapProductModel[v.Id] = k
mapProductModel := make(map[int64]gmodel.FsProductModel3d)
for _, v := range productModel3dList {
mapProductModel[v.Id] = v
}
//根据产品ids获取产品价格
priceList, err := l.svcCtx.AllModels.FsProductPrice.GetPriceListByProductIds(l.ctx, productIds)
@@ -127,6 +138,8 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product price list")
}
//根据产品id,材质,尺寸存储价格
mapProductMaterialSizePrice := make(map[string][]types.PriceItem)
for _, v := range priceList {
if *v.StepNum == "" || *v.StepPrice == "" {
return resp.SetStatusWithMessage(basic.CodeServiceErr, "price data`s step num or step price is empty")
@@ -136,19 +149,122 @@ func (l *GetCloudListLogic) GetCloudList(req *types.GetCloudListReq, userinfo *a
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "parse step num err")
}
lenStepNum := len(stepNum)
stepPrice, err := format.StrSlicToIntSlice(strings.Split(*v.StepPrice, ","))
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "parse step price err")
}
lenStepPrice := len(stepPrice)
//不确定长度给20
for *v.MinBuyNum < int64(stepPrice[lenStepPrice-1]+5) {
//根据材质,尺寸,价格计算阶梯价
mapKey := l.getMapProductMaterialSizePriceKey(*v.ProductId, *v.MaterialId, *v.SizeId)
mapProductMaterialSizePrice[mapKey] = append(mapProductMaterialSizePrice[mapKey], types.PriceItem{
Num: *v.MinBuyNum,
TotalNum: *v.MinBuyNum * (*v.EachBoxNum),
Price: step_price.GetCentStepPrice(int(*v.MinBuyNum), stepNum, stepPrice),
})
*v.MinBuyNum++
}
}
return resp.SetStatus(basic.CodeOK)
warehouseBoxes := int64(0)
transitBoxes := int64(0)
listDataRsp := make([]types.ListDataItem, 0, len(stockList))
for _, v := range stockList {
dataItem := types.ListDataItem{
Id: v.Id,
Production: *v.Production,
EachBoxNum: *v.EachBoxNum,
Stick: *v.Stick,
Type: 1,
TakeNum: 1, // 步数
}
//设计详情
designInfo, designOk := mapProductDesign[*v.DesignId]
sizeId := int64(0)
optionalId := int64(0)
if designOk {
mapKey := l.getMapProductMaterialSizePriceKey(*v.ProductId, *designInfo.MaterialId, *designInfo.SizeId)
dataItem.DesignSn = *designInfo.Sn
dataItem.Cover = *designInfo.Cover
sizeId = *designInfo.SizeId
optionalId = *designInfo.OptionalId
dataItem.PriceList = mapProductMaterialSizePrice[mapKey]
}
//模型信息
productModel3dInfo, model3dOk := mapProductModel[optionalId]
if model3dOk {
dataItem.Fitting = *productModel3dInfo.Title
//配件下架
if *productModel3dInfo.Status == 0 {
dataItem.IsStop = 3
}
}
//模板信息
templateInfo, templateOk := mapTemplate[*designInfo.TemplateId]
if templateOk {
//模板下架
if *templateInfo.IsDel == 1 || *templateInfo.Status == 0 {
dataItem.IsStop = 1
}
}
//尺寸信息
sizeInfo, sizeOk := mapSize[sizeId]
if sizeOk {
dataItem.Size = *sizeInfo.Capacity
//尺寸下架
if *sizeInfo.Status == 0 {
dataItem.IsStop = 1
}
}
//产品信息
productInfo, productOk := mapProduct[*v.ProductId]
if productOk {
dataItem.Sn = *productInfo.Sn
dataItem.Name = *productInfo.Title
if *productInfo.IsShelf == 0 || *productInfo.IsDel == 1 {
dataItem.IsStop = 2
}
}
if sizeFlag {
coverArr := strings.Split(*designInfo.Cover, ".")
if len(coverArr) < 2 {
return resp.SetStatusWithMessage(basic.CodeServiceErr, "cover split slice item count is less than 2")
}
dataItem.Cover = fmt.Sprintf("%s_%d.%s", coverArr[0], req.Size, coverArr[1])
}
//生产中的箱数
if *v.EachBoxNum > 0 {
dataItem.ProductionBox = *v.Production / *v.EachBoxNum
dataItem.StickBox = *v.Stick / *v.EachBoxNum
}
//判断提示类型1 2告急 3没有了
if *v.Stick <= 0 && *v.Production <= 0 {
dataItem.Type = 3
}
if (*v.Stick+*v.Production) / *v.EachBoxNum <= 3 {
dataItem.Type = 2
}
listDataRsp = append(listDataRsp, dataItem)
//累加在库数量和运输数量
if *v.EachBoxNum != 0 {
warehouseBoxes += *v.Stick / *v.EachBoxNum
transitBoxes += *v.TransNum / *v.EachBoxNum
}
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetCloudListRsp{
WarehouseBoxes: warehouseBoxes,
TransitBoxes: transitBoxes,
MinTakeNum: 3,
ListData: listDataRsp,
Pagnation: types.Pagnation{
TotalCount: total,
TotalPage: int64(math.Ceil(float64(total) / float64(req.PageSize))),
CurPage: req.Page,
PageSize: req.PageSize,
},
})
}
func (l *GetCloudListLogic) getMapProductMaterialSizePriceKey(productId int64, materialId int64, sizeId int64) string {
return fmt.Sprintf("%d-%d-%d", productId, materialId, sizeId)
}

View File

@@ -0,0 +1,185 @@
package logic
import (
"errors"
"fusenapi/constants"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/format"
"fusenapi/utils/id_generator"
"fusenapi/utils/step_price"
"gorm.io/gorm"
"math"
"strings"
"time"
"context"
"fusenapi/server/inventory/internal/svc"
"fusenapi/server/inventory/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type SupplementLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewSupplementLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SupplementLogic {
return &SupplementLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *SupplementLogic) Supplement(req *types.SupplementReq, userinfo *auth.UserInfo) (resp *basic.Response) {
if userinfo.GetIdType() != auth.IDTYPE_User {
return resp.SetStatusWithMessage(basic.CodeServiceErr, "please login first")
}
if req.Id <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "param id must greater than 0")
}
if req.Num <= 0 {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "param num must greater than 0")
}
//获取云仓数据
stockInfo, err := l.svcCtx.AllModels.FsUserStock.FindOne(l.ctx, req.Id, userinfo.UserId, true)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "your stock info is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get stock info")
}
//获取订单详细模板数据
orderDetailTemplateInfo, err := l.svcCtx.AllModels.FsOrderDetailTemplate.FindOneBySn(l.ctx, *stockInfo.OrderDetailTemplateSn)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order detail template info is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get order detail template info")
}
//获取订单详细数据
orderDetailInfo, err := l.svcCtx.AllModels.FsOrderDetail.FindOneByOrderDetailTemplateId(l.ctx, orderDetailTemplateInfo.Id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order detail info is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get order detail info")
}
//产品价格
productPriceByParamsReq := gmodel.FindOneProductPriceByParamsReq{
ProductId: orderDetailTemplateInfo.ProductId,
}
productPriceInfo, err := l.svcCtx.AllModels.FsProductPrice.FindOneProductPriceByParams(l.ctx, productPriceByParamsReq)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "product price info is not exists")
}
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product price info")
}
//获取阶梯价格和阶梯数量
stepNum, err := format.StrSlicToIntSlice(strings.Split(*productPriceInfo.StepNum, ","))
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "invalid step num format: "+*productPriceInfo.StepNum)
}
stepPrice, err := format.StrSlicToIntSlice(strings.Split(*productPriceInfo.StepPrice, ","))
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "invalid step price format: "+*productPriceInfo.StepPrice)
}
//附件价格信息
optionalPrice := int64(0)
if *orderDetailInfo.OptionPrice > 0 {
optionalPrice = *orderDetailInfo.OptionPrice
}
//获取总价
minByNum := math.Ceil(float64(req.Num) / float64(*productPriceInfo.EachBoxNum))
amount := step_price.GetCentStepPrice(int(minByNum), stepNum, stepPrice) + optionalPrice
totalAmount := amount * req.Num
newOrderSn := id_generator.GenPickUpTrackNum()
now := time.Now().Unix()
deliveryMethod := int64(constants.DELIVERY_METHOD_CLOUD)
isSup := int64(1)
//生成雪花id
newOrderDetailTemplateSn, err := id_generator.GenSnowFlakeId()
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "gen order detail template sn err")
}
newOrderDetailSn, err := id_generator.GenSnowFlakeId()
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "gen order detail sn err")
}
//事务处理数据
err = l.svcCtx.MysqlConn.Transaction(func(tx *gorm.DB) error {
orderModel := gmodel.NewFsOrderModel(tx)
orderDetailModel := gmodel.NewFsOrderDetailModel(tx)
orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(tx)
//订单创建数据
orderAddData := gmodel.FsOrder{
Sn: &newOrderSn,
UserId: &userinfo.UserId,
TotalAmount: &totalAmount,
Ctime: &now,
Utime: &now,
DeliveryMethod: &deliveryMethod,
IsSup: &isSup,
}
if err = orderModel.Create(l.ctx, &orderAddData); err != nil {
return err
}
//添加订单详情模板数据
orderDetailTemplateAddData := gmodel.FsOrderDetailTemplate{
Sn: &newOrderDetailTemplateSn,
ProductId: orderDetailTemplateInfo.ProductId,
ModelId: orderDetailTemplateInfo.ModelId,
TemplateId: orderDetailTemplateInfo.TemplateId,
MaterialId: orderDetailTemplateInfo.MaterialId,
SizeId: orderDetailTemplateInfo.SizeId,
EachBoxNum: orderDetailTemplateInfo.EachBoxNum,
EachBoxWeight: orderDetailTemplateInfo.EachBoxWeight,
DesignId: orderDetailTemplateInfo.DesignId,
Ctime: &now,
}
if err = orderDetailTemplateModel.Create(l.ctx, &orderDetailTemplateAddData); err != nil {
return err
}
//添加订单详细数据
factoryId := int64(1)
isCloud := int64(1)
orderDetailAddData := gmodel.FsOrderDetail{
Sn: &newOrderDetailSn,
OrderId: &orderAddData.Id,
UserId: &userinfo.UserId,
FactoryId: &factoryId,
OrderDetailTemplateId: &orderDetailTemplateAddData.Id,
ProductId: orderDetailTemplateInfo.ProductId,
BuyNum: &req.Num,
Amount: &amount,
Cover: orderDetailInfo.Cover,
Ctime: &now,
OptionalId: orderDetailInfo.OptionalId,
OptionalTitle: orderDetailInfo.OptionalTitle,
OptionPrice: orderDetailInfo.OptionPrice,
IsCloud: &isCloud,
}
return orderDetailModel.Create(l.ctx, &orderDetailAddData)
})
if err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to supplement your stock")
}
return resp.SetStatusWithMessage(basic.CodeOK, "success", types.SupplementRsp{
Sn: newOrderSn,
})
}

View File

@@ -16,9 +16,9 @@ type TakeForm struct {
}
type GetCloudListReq struct {
Page int64 `json:"page"`
PageSize int64 `json:"page_size"`
Size int64 `json:"size"`
Page int64 `form:"page"`
PageSize int64 `form:"page_size"`
Size int64 `form:"size"`
}
type GetCloudListRsp struct {
@@ -49,9 +49,18 @@ type ListDataItem struct {
}
type PriceItem struct {
Num int `json:"num"`
TotalNum int `json:"total_num"`
Price int `json:"price"`
Num int64 `json:"num"`
TotalNum int64 `json:"total_num"`
Price int64 `json:"price"`
}
type SupplementReq struct {
Id int64 `json:"id"`
Num int64 `json:"num"`
}
type SupplementRsp struct {
Sn string `json:"sn"`
}
type Request struct {