1.格式化代码;2.修复库存导入缺陷;3.修改库存列表接口,调整逻辑;4.修改获取IP地址接口;5.优化操作日志记录逻辑;
This commit is contained in:
parent
df19d305b8
commit
aa3329c25e
|
@ -1,6 +1 @@
|
||||||
package admincron
|
package admincron
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
|
|
||||||
type DeliveryCargoReq struct {
|
type DeliveryCargoReq struct {
|
||||||
Id uint32 `json:"id" binding:"required"` // 商品库存列表id
|
Id uint32 `json:"id" binding:"required"` // 商品库存列表id
|
||||||
State uint32 `json:"state" binding:"required"` // 库存状态:4-出库
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddRemarkReq struct {
|
type AddRemarkReq struct {
|
||||||
|
@ -21,6 +20,27 @@ type AddRemarkReq struct {
|
||||||
Remark string `json:"remark"` // 备注
|
Remark string `json:"remark"` // 备注
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInventoryListOld 该函数只遍历了库存列表,和产品需求不符合
|
||||||
|
// 产品需要库存列表接口返回所有商品资料数据,以及每个商品的库存情况
|
||||||
|
func GetInventoryListOld(c *gin.Context) {
|
||||||
|
req := &models.ErpStockListReq{}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
//logger.Error(err)
|
||||||
|
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := req.List()
|
||||||
|
if err != nil {
|
||||||
|
//logger.Error("erp commodity list err:", err)
|
||||||
|
app.Error(c, http.StatusInternalServerError, err, "获取失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
app.OK(c, resp, "OK")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// GetInventoryList 查询库存列表
|
// GetInventoryList 查询库存列表
|
||||||
// @Summary 查询库存列表
|
// @Summary 查询库存列表
|
||||||
// @Tags 库存管理
|
// @Tags 库存管理
|
||||||
|
@ -36,8 +56,14 @@ func GetInventoryList(c *gin.Context) {
|
||||||
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
|
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 如果筛选条件有:库存情况筛选;则以库存表为准,查库存表即可
|
||||||
|
// (1)没门店,则查所有库存情况并排序
|
||||||
|
// (2)有门店,则查门店对应的库存情况并排序
|
||||||
|
|
||||||
resp, err := req.List()
|
// 如果筛选条件没有库存情况,则先查询商品资料,并排序;支持筛选条件:商品编号、商品分类、商品名称
|
||||||
|
// 然后查询每个商品资料的库存情况,没传门店id,则查所有库存;否则查当前门店的库存情况
|
||||||
|
|
||||||
|
resp, err := req.StockList()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//logger.Error("erp commodity list err:", err)
|
//logger.Error("erp commodity list err:", err)
|
||||||
app.Error(c, http.StatusInternalServerError, err, "获取失败")
|
app.Error(c, http.StatusInternalServerError, err, "获取失败")
|
||||||
|
@ -96,7 +122,7 @@ func DeliveryCargo(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.SetStockCommodityState(req.Id, req.State)
|
err := models.SetStockCommodityState(req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//logger.Error("erp stock err:", err)
|
//logger.Error("erp stock err:", err)
|
||||||
app.Error(c, http.StatusInternalServerError, err, "获取失败")
|
app.Error(c, http.StatusInternalServerError, err, "获取失败")
|
||||||
|
|
|
@ -98,7 +98,15 @@ func RequestOutLog(c *gin.Context) {
|
||||||
_, ok := global.WHILTE[resultUrl]
|
_, ok := global.WHILTE[resultUrl]
|
||||||
|
|
||||||
if c.Request.Method != "GET" && c.Request.Method != "OPTIONS" && config2.LoggerConfig.EnabledDB && ok {
|
if c.Request.Method != "GET" && c.Request.Method != "OPTIONS" && config2.LoggerConfig.EnabledDB && ok {
|
||||||
SetDBOperLog(c, clientIP, statusCode, reqUri, reqMethod, latencyTime, req.(string), response.(string))
|
reqParam, respParam := "", ""
|
||||||
|
if req != nil {
|
||||||
|
reqParam = req.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if response != nil {
|
||||||
|
respParam = response.(string)
|
||||||
|
}
|
||||||
|
SetDBOperLog(c, clientIP, statusCode, reqUri, reqMethod, latencyTime, reqParam, respParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +138,9 @@ func SetDBOperLog(c *gin.Context, clientIP string, statusCode int, reqUri string
|
||||||
|
|
||||||
sysOperLog.Method = reqMethod
|
sysOperLog.Method = reqMethod
|
||||||
if len(menuList) > 0 {
|
if len(menuList) > 0 {
|
||||||
sysOperLog.Title = menuList[0].Title
|
sysOperLog.Title = menuList[0].Title //事件
|
||||||
menu.Title = menuList[0].Title
|
menu.Title = menuList[0].Title
|
||||||
sysOperLog.MenuTitle, _ = menu.GetParentTitle()
|
sysOperLog.MenuTitle, _ = menu.GetParentTitle() //操作模块
|
||||||
}
|
}
|
||||||
|
|
||||||
sysOperLog.CreateBy = tools.GetUserName(c)
|
sysOperLog.CreateBy = tools.GetUserName(c)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
//sys_casbin_rule
|
// sys_casbin_rule
|
||||||
type CasbinRule struct {
|
type CasbinRule struct {
|
||||||
PType string `json:"p_type" gorm:"size:100;"`
|
PType string `json:"p_type" gorm:"size:100;"`
|
||||||
V0 string `json:"v0" gorm:"size:100;"`
|
V0 string `json:"v0" gorm:"size:100;"`
|
||||||
|
|
|
@ -631,7 +631,7 @@ func (m *StockImporter) ImportStockData(colsMap []map[string]interface{}) error
|
||||||
StoreName: list[i].StoreName,
|
StoreName: list[i].StoreName,
|
||||||
ErpCommodityId: v2.ID,
|
ErpCommodityId: v2.ID,
|
||||||
ErpCommodityName: v2.Name,
|
ErpCommodityName: v2.Name,
|
||||||
CommoditySerialNumber: list[i].SerialNum,
|
CommoditySerialNumber: v2.SerialNumber,
|
||||||
ErpCategoryId: v2.ErpCategoryId,
|
ErpCategoryId: v2.ErpCategoryId,
|
||||||
ErpCategoryName: v2.ErpCategoryName,
|
ErpCategoryName: v2.ErpCategoryName,
|
||||||
ErpSupplierId: v3,
|
ErpSupplierId: v3,
|
||||||
|
@ -647,6 +647,12 @@ func (m *StockImporter) ImportStockData(colsMap []map[string]interface{}) error
|
||||||
IMEI: v2.IMEI,
|
IMEI: v2.IMEI,
|
||||||
Remark: "",
|
Remark: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if list[i].StockTime != "" { //导入时间不为空
|
||||||
|
parsedTime, _ := time.Parse("2006/1/2", list[i].StockTime)
|
||||||
|
stockCommodity.FirstStockTime = parsedTime
|
||||||
|
}
|
||||||
|
|
||||||
if list[i].SysGenerate != "" { //导入串码不为空,则默认为3手动添加
|
if list[i].SysGenerate != "" { //导入串码不为空,则默认为3手动添加
|
||||||
stockCommodity.IMEIType = 3
|
stockCommodity.IMEIType = 3
|
||||||
stockCommodity.IMEI = list[i].SysGenerate
|
stockCommodity.IMEI = list[i].SysGenerate
|
||||||
|
@ -686,11 +692,11 @@ func (m *StockImporter) processErpStocks(erpStocks []ErpStockCommodity) error {
|
||||||
|
|
||||||
stockList := erpStocks[start:end]
|
stockList := erpStocks[start:end]
|
||||||
errGroup.Go(func() error {
|
errGroup.Go(func() error {
|
||||||
return createStockList(begin, stockList)
|
return createStockList(begin, stockList) //插入库存商品详情
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
err := m.ErpStockCountUpdate(begin)
|
err := m.ErpStockCountUpdate(begin) //更新or插入库存表
|
||||||
if err != nil {
|
if err != nil {
|
||||||
begin.Rollback()
|
begin.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -780,7 +786,26 @@ func (m *StockImporter) ErpStockCountUpdate(gdb *gorm.DB) error {
|
||||||
fmt.Println("inventoryStock", inventoryStock.Count)
|
fmt.Println("inventoryStock", inventoryStock.Count)
|
||||||
m.Inventories = append(m.Inventories, inventoryStock)
|
m.Inventories = append(m.Inventories, inventoryStock)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询库存详情时同步库存id
|
||||||
|
func updateCommodityStock(id uint32) error {
|
||||||
|
var stock ErpStock
|
||||||
|
err := orm.Eloquent.Table("erp_stock").Raw("SELECT * FROM erp_stock WHERE id = ?", id).Scan(&stock).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if stock.ID != 0 {
|
||||||
|
err = orm.Eloquent.Debug().Exec(fmt.Sprintf(
|
||||||
|
"UPDATE erp_stock_commodity SET erp_stock_id = %d WHERE erp_commodity_name = '%s' AND erp_stock_id = 0;",
|
||||||
|
stock.ID, stock.ErpCommodityName)).Error
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,7 +1104,10 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
|
||||||
if m.PageSize == 0 {
|
if m.PageSize == 0 {
|
||||||
m.PageSize = 10
|
m.PageSize = 10
|
||||||
}
|
}
|
||||||
qs := orm.Eloquent.Table("erp_stock")
|
|
||||||
|
qs := orm.Eloquent.Table("erp_stock").
|
||||||
|
Joins("JOIN erp_category c ON erp_stock.erp_category_id = c.id")
|
||||||
|
|
||||||
if m.SerialNumber != "" {
|
if m.SerialNumber != "" {
|
||||||
qs = qs.Where("commodity_serial_number=?", m.SerialNumber)
|
qs = qs.Where("commodity_serial_number=?", m.SerialNumber)
|
||||||
}
|
}
|
||||||
|
@ -1099,6 +1127,12 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
|
||||||
qs = qs.Where("count = 0")
|
qs = qs.Where("count = 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SQL Order By Clause
|
||||||
|
qs = qs.Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) ELSE " +
|
||||||
|
"CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END").
|
||||||
|
Order("CAST(c.pid AS SIGNED)").
|
||||||
|
Order("CAST(SUBSTRING(erp_stock.commodity_serial_number, -4) AS SIGNED)")
|
||||||
|
|
||||||
var count int64
|
var count int64
|
||||||
if err := qs.Count(&count).Error; err != nil {
|
if err := qs.Count(&count).Error; err != nil {
|
||||||
//logger.Error("count err:", err)
|
//logger.Error("count err:", err)
|
||||||
|
@ -1106,7 +1140,7 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var commodities []ErpStock
|
var commodities []ErpStock
|
||||||
err := qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
|
err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
|
||||||
if err != nil && !errors.Is(err, RecordNotFound) {
|
if err != nil && !errors.Is(err, RecordNotFound) {
|
||||||
//logger.Error("erp commodity list err:", err)
|
//logger.Error("erp commodity list err:", err)
|
||||||
return resp, err
|
return resp, err
|
||||||
|
@ -1121,6 +1155,367 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StockList
|
||||||
|
// 1、如果筛选条件有:库存情况筛选;则以库存表为准,查库存表即可
|
||||||
|
// (1)没门店,则查所有库存情况并排序
|
||||||
|
// (2)有门店,则查门店对应的库存情况并排序
|
||||||
|
// 2、如果筛选条件没有库存情况,
|
||||||
|
// (1)先查询商品资料,并排序;支持筛选条件:商品编号、商品分类、商品名称
|
||||||
|
// (2)然后查询每个商品资料的库存情况,没传门店id,则查所有库存;否则查当前门店的库存情况
|
||||||
|
func (m *ErpStockListReq) StockList() (*ErpStockListResp, error) {
|
||||||
|
switch m.StockType {
|
||||||
|
case 2: // 有库存
|
||||||
|
return m.stockNoEmptyList()
|
||||||
|
case 3: // 无库存,连表查询商品明细和库存表
|
||||||
|
return m.stockIsEmptyList()
|
||||||
|
default: // 0和1,以及其他值,表示无库存情况筛选
|
||||||
|
return m.allCommodityList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stockIsEmptyList 库存列表-无库存查询
|
||||||
|
// 无库存,要连表查询(商品明细、库存表)
|
||||||
|
func (m *ErpStockListReq) stockIsEmptyList() (*ErpStockListResp, error) {
|
||||||
|
resp := &ErpStockListResp{
|
||||||
|
PageIndex: m.PageIndex,
|
||||||
|
PageSize: m.PageSize,
|
||||||
|
}
|
||||||
|
page := m.PageIndex - 1
|
||||||
|
if page < 0 {
|
||||||
|
page = 0
|
||||||
|
}
|
||||||
|
if m.PageSize == 0 {
|
||||||
|
m.PageSize = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
//以下代码组合了2个连表查询
|
||||||
|
//(1)查询无库存的商品资料
|
||||||
|
/***
|
||||||
|
SELECT erp_commodity.*,
|
||||||
|
COALESCE(erp_stock.count, 0) AS count
|
||||||
|
FROM erp_commodity
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT erp_commodity_id, SUM(count) AS count
|
||||||
|
FROM erp_stock
|
||||||
|
GROUP BY erp_commodity_id
|
||||||
|
) erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id
|
||||||
|
WHERE erp_stock.count IS NULL OR erp_stock.count = 0;
|
||||||
|
***/
|
||||||
|
|
||||||
|
//(2)按商品编号排序
|
||||||
|
/***
|
||||||
|
SELECT e.*
|
||||||
|
FROM erp_stock e
|
||||||
|
JOIN erp_category c ON e.erp_category_id = c.id
|
||||||
|
ORDER BY
|
||||||
|
CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END,
|
||||||
|
CAST(c.pid AS SIGNED),
|
||||||
|
CAST(SUBSTRING(e.commodity_serial_number, -4) AS SIGNED);
|
||||||
|
***/
|
||||||
|
|
||||||
|
qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||||||
|
if m.StoreId != 0 { // 传门店id
|
||||||
|
qs = qs.Select("erp_commodity.*, COALESCE(erp_stock.count, 0) AS count").
|
||||||
|
Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
|
||||||
|
Joins("JOIN erp_category c ON erp_commodity.erp_category_id = c.id").
|
||||||
|
Where("erp_stock.count = 0 AND erp_stock.store_id = ?", m.StoreId).
|
||||||
|
Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
|
||||||
|
"ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
|
||||||
|
"CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
|
||||||
|
} else { // 没传门店id,则子查询先求库存表中erp_commodity_id相同的count之和
|
||||||
|
qs = qs.Select("erp_commodity.*, COALESCE(erp_stock.count, 0) AS count").
|
||||||
|
Joins("LEFT JOIN (SELECT erp_commodity_id, SUM(count) AS count FROM erp_stock GROUP BY erp_commodity_id) " +
|
||||||
|
"erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
|
||||||
|
Joins("JOIN erp_category c ON erp_commodity.erp_category_id = c.id").
|
||||||
|
Where("erp_stock.count IS NULL OR erp_stock.count = 0").
|
||||||
|
Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
|
||||||
|
"ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
|
||||||
|
"CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.SerialNumber != "" {
|
||||||
|
qs = qs.Where("erp_commodity.serial_number=?", m.SerialNumber)
|
||||||
|
}
|
||||||
|
if m.CommodityName != "" {
|
||||||
|
qs = qs.Where("erp_commodity.name Like '%" + m.CommodityName + "%'")
|
||||||
|
//qs = qs.Where("name LIKE ?", m.Name)
|
||||||
|
}
|
||||||
|
if m.ErpCategoryId != 0 {
|
||||||
|
qs = qs.Where("erp_commodity.erp_category_id=?", m.ErpCategoryId)
|
||||||
|
}
|
||||||
|
|
||||||
|
var commodities []ErpCommodity
|
||||||
|
err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
|
||||||
|
if err != nil && err != RecordNotFound {
|
||||||
|
logger.Error("查询无库存列表失败", logger.Field("err", err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
err = qs.Count(&count).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("查询无库存列表数量失败", logger.Field("err", err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//遍历商品资料,转换为库存列表数据
|
||||||
|
var stockList []ErpStock
|
||||||
|
for _, commodity := range commodities {
|
||||||
|
var stock ErpStock
|
||||||
|
stock.ErpCommodityId = commodity.ID
|
||||||
|
stock.ErpCommodityName = commodity.Name
|
||||||
|
stock.ErpCategoryId = commodity.ErpCategoryId
|
||||||
|
stock.ErpCategoryName = commodity.ErpCategoryName
|
||||||
|
stock.CommoditySerialNumber = commodity.SerialNumber
|
||||||
|
stock.IMEIType = commodity.IsIMEI
|
||||||
|
stock.RetailPrice = commodity.RetailPrice
|
||||||
|
stock.MinRetailPrice = commodity.MinRetailPrice
|
||||||
|
stock.Count = 0
|
||||||
|
stock.DispatchCount = 0
|
||||||
|
|
||||||
|
stockList = append(stockList, stock)
|
||||||
|
}
|
||||||
|
|
||||||
|
//跟之前保持一致
|
||||||
|
resp.Total = int(count)
|
||||||
|
resp.PageIndex = page + 1
|
||||||
|
resp.PageSize = m.PageSize
|
||||||
|
resp.List = stockList
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ErpStockListReq) stockNoEmptyList() (*ErpStockListResp, error) {
|
||||||
|
resp := &ErpStockListResp{
|
||||||
|
PageIndex: m.PageIndex,
|
||||||
|
PageSize: m.PageSize,
|
||||||
|
}
|
||||||
|
page := m.PageIndex - 1
|
||||||
|
if page < 0 {
|
||||||
|
page = 0
|
||||||
|
}
|
||||||
|
if m.PageSize == 0 {
|
||||||
|
m.PageSize = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
//组合查询
|
||||||
|
SELECT
|
||||||
|
ec.*,
|
||||||
|
COALESCE(SUM(es.count), 0) AS total_count
|
||||||
|
FROM
|
||||||
|
erp_commodity ec
|
||||||
|
LEFT JOIN
|
||||||
|
erp_stock es ON ec.id = es.erp_commodity_id
|
||||||
|
GROUP BY
|
||||||
|
ec.id
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN ec.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) THEN CAST((SELECT number FROM erp_category WHERE id = ec.erp_category_id) AS SIGNED)
|
||||||
|
ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = ec.erp_category_id)), 1, 3) AS SIGNED)
|
||||||
|
END,
|
||||||
|
CAST((SELECT pid FROM erp_category WHERE id = ec.erp_category_id) AS SIGNED),
|
||||||
|
CAST(SUBSTRING(ec.serial_number, -4) AS SIGNED);
|
||||||
|
***/
|
||||||
|
|
||||||
|
qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||||||
|
if m.StoreId == 0 { // 没指定门店,连表查询并计算总数量
|
||||||
|
qs = qs.Select("erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, erp_stock.id AS erp_stock_id").
|
||||||
|
Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id AND erp_stock.count != 0").
|
||||||
|
Group("erp_commodity.id").
|
||||||
|
Order("CASE WHEN erp_commodity.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) " +
|
||||||
|
"THEN CAST((SELECT number FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED) " +
|
||||||
|
"ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id)), 1, 3) AS SIGNED) " +
|
||||||
|
"END, CAST((SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED), " +
|
||||||
|
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
|
||||||
|
} else { // 指定了门店,连表查询指定store_id的count
|
||||||
|
qs = qs.Select("erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, erp_stock.id AS erp_stock_id").
|
||||||
|
Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id "+
|
||||||
|
"AND erp_stock.count != 0 AND erp_stock.store_id = ?", m.StoreId).
|
||||||
|
Group("erp_commodity.id").
|
||||||
|
Order("CASE WHEN erp_category.pid = 0 THEN CAST(erp_category.number AS SIGNED) " +
|
||||||
|
"ELSE CAST(SUBSTRING(erp_category.number, 1, 3) AS SIGNED) END, " +
|
||||||
|
"CAST(erp_category.pid AS SIGNED), " +
|
||||||
|
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)").
|
||||||
|
Joins("JOIN erp_category ON erp_commodity.erp_category_id = erp_category.id")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.SerialNumber != "" {
|
||||||
|
qs = qs.Where("erp_commodity.serial_number=?", m.SerialNumber)
|
||||||
|
}
|
||||||
|
if m.CommodityName != "" {
|
||||||
|
qs = qs.Where("erp_commodity.name Like '%" + m.CommodityName + "%'")
|
||||||
|
}
|
||||||
|
if m.ErpCategoryId != 0 {
|
||||||
|
qs = qs.Where("erp_commodity.erp_category_id=?", m.ErpCategoryId)
|
||||||
|
}
|
||||||
|
|
||||||
|
var commodities []struct {
|
||||||
|
ErpCommodity
|
||||||
|
TotalCount int
|
||||||
|
ErpStockId int
|
||||||
|
}
|
||||||
|
|
||||||
|
err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
|
||||||
|
if err != nil && err != RecordNotFound {
|
||||||
|
logger.Error("commodityList err", logger.Field("err", err))
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
err = qs.Count(&count).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("commodityList count err", logger.Field("err", err))
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//遍历商品资料,转换为库存列表数据
|
||||||
|
var stockList []ErpStock
|
||||||
|
for _, commodity := range commodities {
|
||||||
|
if commodity.TotalCount != 0 {
|
||||||
|
var stock ErpStock
|
||||||
|
stock.ID = uint32(commodity.ErpStockId)
|
||||||
|
stock.ErpCommodityId = commodity.ID
|
||||||
|
stock.ErpCommodityName = commodity.Name
|
||||||
|
stock.ErpCategoryId = commodity.ErpCategoryId
|
||||||
|
stock.ErpCategoryName = commodity.ErpCategoryName
|
||||||
|
stock.CommoditySerialNumber = commodity.SerialNumber
|
||||||
|
stock.IMEIType = commodity.IsIMEI
|
||||||
|
stock.RetailPrice = commodity.RetailPrice
|
||||||
|
stock.MinRetailPrice = commodity.MinRetailPrice
|
||||||
|
stock.Count = uint32(commodity.TotalCount)
|
||||||
|
stock.DispatchCount = 0
|
||||||
|
|
||||||
|
stockList = append(stockList, stock)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//跟之前保持一致
|
||||||
|
resp.Total = len(stockList)
|
||||||
|
resp.PageIndex = page + 1
|
||||||
|
resp.PageSize = m.PageSize
|
||||||
|
resp.List = stockList
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选条件无:库存情况筛选
|
||||||
|
// (1)先查询商品资料,并排序;支持筛选条件:商品编号、商品分类、商品名称
|
||||||
|
// (2)然后查询每个商品资料的库存情况,没传门店id,则查所有库存;否则查当前门店的库存情况
|
||||||
|
func (m *ErpStockListReq) allCommodityList() (*ErpStockListResp, error) {
|
||||||
|
resp := &ErpStockListResp{
|
||||||
|
PageIndex: m.PageIndex,
|
||||||
|
PageSize: m.PageSize,
|
||||||
|
}
|
||||||
|
page := m.PageIndex - 1
|
||||||
|
if page < 0 {
|
||||||
|
page = 0
|
||||||
|
}
|
||||||
|
if m.PageSize == 0 {
|
||||||
|
m.PageSize = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
//组合查询
|
||||||
|
SELECT
|
||||||
|
ec.*,
|
||||||
|
COALESCE(SUM(es.count), 0) AS total_count
|
||||||
|
FROM
|
||||||
|
erp_commodity ec
|
||||||
|
LEFT JOIN
|
||||||
|
erp_stock es ON ec.id = es.erp_commodity_id
|
||||||
|
GROUP BY
|
||||||
|
ec.id
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN ec.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) THEN CAST((SELECT number FROM erp_category WHERE id = ec.erp_category_id) AS SIGNED)
|
||||||
|
ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = ec.erp_category_id)), 1, 3) AS SIGNED)
|
||||||
|
END,
|
||||||
|
CAST((SELECT pid FROM erp_category WHERE id = ec.erp_category_id) AS SIGNED),
|
||||||
|
CAST(SUBSTRING(ec.serial_number, -4) AS SIGNED);
|
||||||
|
***/
|
||||||
|
|
||||||
|
qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||||||
|
|
||||||
|
if m.SerialNumber != "" {
|
||||||
|
qs = qs.Where("erp_commodity.serial_number=?", m.SerialNumber)
|
||||||
|
}
|
||||||
|
if m.CommodityName != "" {
|
||||||
|
qs = qs.Where("erp_commodity.name Like '%" + m.CommodityName + "%'")
|
||||||
|
}
|
||||||
|
if m.ErpCategoryId != 0 {
|
||||||
|
qs = qs.Where("erp_commodity.erp_category_id=?", m.ErpCategoryId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.StoreId == 0 { // 没指定门店,连表查询并计算总数量
|
||||||
|
qs = qs.Select("erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, erp_stock.id AS erp_stock_id").
|
||||||
|
Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
|
||||||
|
Group("erp_commodity.id").
|
||||||
|
Order("CASE WHEN erp_commodity.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) " +
|
||||||
|
"THEN CAST((SELECT number FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED) " +
|
||||||
|
"ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id)), 1, 3) AS SIGNED) " +
|
||||||
|
"END, CAST((SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED), " +
|
||||||
|
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
|
||||||
|
} else { // 指定了门店,连表查询指定store_id的count
|
||||||
|
qs = qs.Select("erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, erp_stock.id AS erp_stock_id").
|
||||||
|
Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id "+
|
||||||
|
"AND erp_stock.store_id = ?", m.StoreId).
|
||||||
|
Group("erp_commodity.id").
|
||||||
|
Order("CASE WHEN erp_category.pid = 0 THEN CAST(erp_category.number AS SIGNED) " +
|
||||||
|
"ELSE CAST(SUBSTRING(erp_category.number, 1, 3) AS SIGNED) END, " +
|
||||||
|
"CAST(erp_category.pid AS SIGNED), " +
|
||||||
|
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)").
|
||||||
|
Joins("JOIN erp_category ON erp_commodity.erp_category_id = erp_category.id")
|
||||||
|
}
|
||||||
|
|
||||||
|
var commodities []struct {
|
||||||
|
ErpCommodity
|
||||||
|
TotalCount int
|
||||||
|
ErpStockId int
|
||||||
|
}
|
||||||
|
|
||||||
|
err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
|
||||||
|
if err != nil && err != RecordNotFound {
|
||||||
|
logger.Error("commodityList err", logger.Field("err", err))
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int64
|
||||||
|
err = qs.Count(&count).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("commodityList count err", logger.Field("err", err))
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//遍历商品资料,转换为库存列表数据
|
||||||
|
var stockList []ErpStock
|
||||||
|
for _, commodity := range commodities {
|
||||||
|
var stock ErpStock
|
||||||
|
stock.ID = uint32(commodity.ErpStockId)
|
||||||
|
stock.ErpCommodityId = commodity.ID
|
||||||
|
stock.ErpCommodityName = commodity.Name
|
||||||
|
stock.ErpCategoryId = commodity.ErpCategoryId
|
||||||
|
stock.ErpCategoryName = commodity.ErpCategoryName
|
||||||
|
stock.CommoditySerialNumber = commodity.SerialNumber
|
||||||
|
stock.IMEIType = commodity.IsIMEI
|
||||||
|
stock.RetailPrice = commodity.RetailPrice
|
||||||
|
stock.MinRetailPrice = commodity.MinRetailPrice
|
||||||
|
stock.Count = uint32(commodity.TotalCount)
|
||||||
|
stock.DispatchCount = 0
|
||||||
|
|
||||||
|
stockList = append(stockList, stock)
|
||||||
|
}
|
||||||
|
|
||||||
|
//跟之前保持一致
|
||||||
|
resp.Total = int(count)
|
||||||
|
resp.PageIndex = page + 1
|
||||||
|
resp.PageSize = m.PageSize
|
||||||
|
resp.List = stockList
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ErpStockCommodityListSetAge(commodities []ErpStockCommodity) {
|
func ErpStockCommodityListSetAge(commodities []ErpStockCommodity) {
|
||||||
nowTime := time.Now()
|
nowTime := time.Now()
|
||||||
for i, _ := range commodities {
|
for i, _ := range commodities {
|
||||||
|
@ -1139,7 +1534,7 @@ type ErpStockCommodityListReq struct {
|
||||||
IMEI string `json:"imei"` // 串码
|
IMEI string `json:"imei"` // 串码
|
||||||
StoreId uint32 `json:"store_id"` // 门店编号
|
StoreId uint32 `json:"store_id"` // 门店编号
|
||||||
SupplierId uint32 `json:"supplier_id"` // 供应商id
|
SupplierId uint32 `json:"supplier_id"` // 供应商id
|
||||||
State uint32 `json:"state"` // 库存状态:1-在库 2-已售 3-采购退货 4-调拨中
|
State uint32 `json:"state"` // 库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库
|
||||||
Sn string `json:"sn"` // 首次入库订单编号
|
Sn string `json:"sn"` // 首次入库订单编号
|
||||||
StorageType uint32 `json:"storage_type"` // 首次入库方式:1-系统入库 2-采购入库
|
StorageType uint32 `json:"storage_type"` // 首次入库方式:1-系统入库 2-采购入库
|
||||||
StockTimeStart string `json:"stock_time_start"` // 最近入库开始时间
|
StockTimeStart string `json:"stock_time_start"` // 最近入库开始时间
|
||||||
|
@ -1174,7 +1569,12 @@ func (m *ErpStockCommodityListReq) GetDetailList() (*ErpStockCommodityListResp,
|
||||||
m.PageSize = 10
|
m.PageSize = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
qs := orm.Eloquent.Table("erp_stock_commodity").Order("id DESC")
|
if m.ErpStockId != 0 {
|
||||||
|
updateCommodityStock(m.ErpStockId) // 同步详情表的库存id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 出库数据不查询
|
||||||
|
qs := orm.Eloquent.Table("erp_stock_commodity").Where("state != 5").Order("id DESC")
|
||||||
|
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
m.buildQueryConditions(qs)
|
m.buildQueryConditions(qs)
|
||||||
|
@ -1269,18 +1669,18 @@ func (m *ErpStockCommodityListReq) buildQueryConditions(qs *gorm.DB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.StockTimeStart != "" { //最近入库开始时间
|
if m.StockTimeStart != "" { //最近入库开始时间
|
||||||
startTime, err := time.Parse(DateTimeFormat, m.StockTimeStart)
|
startTime, err := time.Parse(QueryTimeFormat, m.StockTimeStart)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
qs = qs.Where("first_stock_time>?", startTime)
|
qs = qs.Where("stock_time>?", startTime)
|
||||||
} else {
|
} else {
|
||||||
//logger.Error("stock time start parse err:", err)
|
//logger.Error("stock time start parse err:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.StockTimeEnd != "" { //最近入库结束时间
|
if m.StockTimeEnd != "" { //最近入库结束时间
|
||||||
endTime, err := time.Parse(DateTimeFormat, m.StockTimeEnd)
|
endTime, err := time.Parse(QueryTimeFormat, m.StockTimeEnd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
qs = qs.Where("first_stock_time<?", endTime)
|
qs = qs.Where("stock_time<?", endTime)
|
||||||
} else {
|
} else {
|
||||||
//logger.Error("stock time end parse err:", err)
|
//logger.Error("stock time end parse err:", err)
|
||||||
}
|
}
|
||||||
|
@ -1296,15 +1696,51 @@ func (m *ErpStockCommodityListReq) buildQueryConditions(qs *gorm.DB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetStockCommodityState 更新库存状态
|
// SetStockCommodityState 更新库存状态
|
||||||
func SetStockCommodityState(id, state uint32) error {
|
func SetStockCommodityState(id uint32) error { //更新库存状态为5,并同步扣减库存数量
|
||||||
if state != 4 {
|
begin := orm.Eloquent.Begin()
|
||||||
state = 4
|
|
||||||
|
// 查询库存详情
|
||||||
|
var commodityInfo ErpStockCommodity
|
||||||
|
err := orm.Eloquent.Table("erp_stock_commodity").
|
||||||
|
Raw("SELECT * FROM erp_stock_commodity WHERE id = ?", id).
|
||||||
|
Scan(&commodityInfo).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("查询库存商品信息失败", logger.Field("err", err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if err := orm.Eloquent.Model(&ErpStockCommodity{}).Where("id=?", id).Updates(map[string]interface{}{
|
|
||||||
"state": state}).Error; err != nil {
|
// 查询库存数据
|
||||||
|
var record ErpStock
|
||||||
|
err = orm.Eloquent.Table("erp_stock").
|
||||||
|
Where("erp_commodity_name = ? and store_id = ?",
|
||||||
|
commodityInfo.ErpCommodityName, commodityInfo.StoreId).First(&record).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("查询库存数量失败", logger.Field("err", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新商品库存详情表状态为5:出库
|
||||||
|
if err := begin.Model(&ErpStockCommodity{}).Where("id=?", id).Updates(map[string]interface{}{
|
||||||
|
"state": 5}).Error; err != nil {
|
||||||
return fmt.Errorf("[update err]:%v", err)
|
return fmt.Errorf("[update err]:%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if record.Count > 0 {
|
||||||
|
// 扣减商品库存数量
|
||||||
|
err = begin.Model(&record).Update("count", record.Count-1).Error
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("扣减库存数量失败", logger.Field("err", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = begin.Commit().Error
|
||||||
|
if err != nil {
|
||||||
|
begin.Rollback()
|
||||||
|
logger.Error("出库事务失败", logger.Field("err", err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,9 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate goqueryset -in cooperative_business.go
|
|
||||||
// gen:qs
|
// gen:qs
|
||||||
|
//
|
||||||
|
//go:generate goqueryset -in cooperative_business.go
|
||||||
type CooperativeBusiness struct {
|
type CooperativeBusiness struct {
|
||||||
Model
|
Model
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ import (
|
||||||
orm "go-admin/common/global"
|
orm "go-admin/common/global"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate goqueryset -in config.go
|
|
||||||
// gen:qs
|
// gen:qs
|
||||||
|
//
|
||||||
|
//go:generate goqueryset -in config.go
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Model
|
Model
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,8 @@ func checkCommodityExcel(sheetCols [][]string) error {
|
||||||
// (9)数量:必填项,限制≥1正整数,
|
// (9)数量:必填项,限制≥1正整数,
|
||||||
// 串码类商品需拆分成每个数量为1单独导入,
|
// 串码类商品需拆分成每个数量为1单独导入,
|
||||||
// 非串码可大于1直接导入 * 串码类商品如数量填写>1,红框展示,下方红字提示“串码类商品数量只能为1”
|
// 非串码可大于1直接导入 * 串码类商品如数量填写>1,红框展示,下方红字提示“串码类商品数量只能为1”
|
||||||
|
|
||||||
|
// (10)入库时间:必须早于/小于当前时间
|
||||||
func checkStockExcel(sheetCols [][]string) error {
|
func checkStockExcel(sheetCols [][]string) error {
|
||||||
if len(sheetCols) != 9 {
|
if len(sheetCols) != 9 {
|
||||||
return errors.New("模版错误,请检查文件")
|
return errors.New("模版错误,请检查文件")
|
||||||
|
@ -358,6 +360,11 @@ func checkStockExcel(sheetCols [][]string) error {
|
||||||
return errors.New("第" + strconv.Itoa(nMax+1) + "行商品名称和商品编号不能同时为空")
|
return errors.New("第" + strconv.Itoa(nMax+1) + "行商品名称和商品编号不能同时为空")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否有重复串码
|
||||||
|
if duplicateName, nFlag := hasDuplicateIMEI(sheetCols[3]); nFlag {
|
||||||
|
return fmt.Errorf("商品串码不允许重复,请检查:[%v]", duplicateName)
|
||||||
|
}
|
||||||
|
|
||||||
//先遍历第1列
|
//先遍历第1列
|
||||||
for i := 1; i < nLow; i++ {
|
for i := 1; i < nLow; i++ {
|
||||||
if sheetCols[0][i] == "" && sheetCols[1][i] == "" { // 商品名称和编号不能都为空
|
if sheetCols[0][i] == "" && sheetCols[1][i] == "" { // 商品名称和编号不能都为空
|
||||||
|
@ -390,7 +397,7 @@ func checkStockExcel(sheetCols [][]string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 商品串码规则校验 当串码行数跟其他一致时正常遍历,如果小于其他行,则最后一行不遍历 todo
|
// 商品串码规则校验 当串码行数跟其他一致时正常遍历,如果小于其他行,则最后一行不遍历 todo
|
||||||
// 如何串码在商品库存表已经存在,则报错提示
|
// 如串码在商品库存表已经存在,则报错提示
|
||||||
if len(sheetCols[3]) <= nLow && i+1 < nLow {
|
if len(sheetCols[3]) <= nLow && i+1 < nLow {
|
||||||
if err := checkSerialCode(sheetCols[0][i], sheetCols[1][i], sheetCols[3][i], i); err != nil {
|
if err := checkSerialCode(sheetCols[0][i], sheetCols[1][i], sheetCols[3][i], i); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -419,7 +426,8 @@ func checkStockExcel(sheetCols [][]string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 入库时间格式校验
|
// 入库时间格式校验
|
||||||
if len(sheetCols[7]) < nLow && i+1 < nLow {
|
//if len(sheetCols[7]) < nLow && i+1 < nLow {
|
||||||
|
if i+1 <= len(sheetCols[7]) {
|
||||||
if sheetCols[7][i] != "" {
|
if sheetCols[7][i] != "" {
|
||||||
parsedTime, err := time.Parse("2006/1/2", sheetCols[7][i])
|
parsedTime, err := time.Parse("2006/1/2", sheetCols[7][i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -428,6 +436,13 @@ func checkStockExcel(sheetCols [][]string) error {
|
||||||
// 格式化时间为指定格式
|
// 格式化时间为指定格式
|
||||||
formattedTime := parsedTime.Format(DateTimeFormat)
|
formattedTime := parsedTime.Format(DateTimeFormat)
|
||||||
sheetCols[7][i] = formattedTime + "00-00-00"
|
sheetCols[7][i] = formattedTime + "00-00-00"
|
||||||
|
|
||||||
|
// 需小于当前时间
|
||||||
|
nFlag, _ := isInputTimeBeforeOrEqualNow(formattedTime)
|
||||||
|
if !nFlag {
|
||||||
|
return errors.New("第" + strconv.Itoa(i+1) + "行入库时间不能晚于当前时间")
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,6 +455,35 @@ func checkStockExcel(sheetCols [][]string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否早于等于当前时间
|
||||||
|
func isInputTimeBeforeOrEqualNow(inputTimeString string) (bool, error) {
|
||||||
|
// 将输入时间字符串解析为 time.Time 类型
|
||||||
|
inputTime, _ := time.Parse(time.RFC3339, inputTimeString)
|
||||||
|
|
||||||
|
// 获取当前时间
|
||||||
|
currentTime := time.Now()
|
||||||
|
|
||||||
|
// 比较时间
|
||||||
|
isBeforeOrEqual := inputTime.After(currentTime)
|
||||||
|
|
||||||
|
return !isBeforeOrEqual, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验串码是否相同,有则false
|
||||||
|
func hasDuplicateIMEI(sheetCols []string) (string, bool) {
|
||||||
|
nameMap := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, name := range sheetCols {
|
||||||
|
if _, exists := nameMap[name]; exists && name != "" {
|
||||||
|
// 有重复的名称
|
||||||
|
return name, true
|
||||||
|
}
|
||||||
|
nameMap[name] = struct{}{}
|
||||||
|
}
|
||||||
|
// 没有重复的名称
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
func findMaxLength(sheetCols [][]string) int {
|
func findMaxLength(sheetCols [][]string) int {
|
||||||
maxLength := 0
|
maxLength := 0
|
||||||
for _, col := range sheetCols {
|
for _, col := range sheetCols {
|
||||||
|
@ -534,7 +578,15 @@ func checkSerialCode(productName, productCode, serialCode string, row int) error
|
||||||
return errors.New("非串码商品,无需填写串码")
|
return errors.New("非串码商品,无需填写串码")
|
||||||
}
|
}
|
||||||
|
|
||||||
if nIMEIType != 1 && !isNumericOrAlpha(serialCode) {
|
//if nIMEIType == 2 && serialCode != ""{
|
||||||
|
// return errors.New("第" + strconv.Itoa(row+1) + "行串码无需填写,该商品串码系统自动生成")
|
||||||
|
//}
|
||||||
|
|
||||||
|
if nIMEIType == 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if nIMEIType != 3 && !isNumericOrAlpha(serialCode) {
|
||||||
return errors.New("串码类商品,请填写正确的串码")
|
return errors.New("串码类商品,请填写正确的串码")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ func (e *SysFileDir) Delete(id int) (success bool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//批量删除
|
// 批量删除
|
||||||
func (e *SysFileDir) BatchDelete(id []int) (Result bool, err error) {
|
func (e *SysFileDir) BatchDelete(id []int) (Result bool, err error) {
|
||||||
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysFileDir{}).Error; err != nil {
|
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysFileDir{}).Error; err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,5 +20,5 @@ func TestExpressInfo(t *testing.T) {
|
||||||
//fmt.Println("paramJson:", string(paramJson))
|
//fmt.Println("paramJson:", string(paramJson))
|
||||||
|
|
||||||
//ExpressInfo("zhongtong","73155364431352")
|
//ExpressInfo("zhongtong","73155364431352")
|
||||||
ExpressInfo("emsbg","9868015085913")
|
ExpressInfo("emsbg", "9868015085913")
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ func (role *SysRole) GetRoleDeptId() ([]int, error) {
|
||||||
return deptIds, nil
|
return deptIds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改
|
// 修改
|
||||||
func (role *SysRole) Update(id int) (update SysRole, err error) {
|
func (role *SysRole) Update(id int) (update SysRole, err error) {
|
||||||
if err = orm.Eloquent.Table(role.TableName()).First(&update, id).Error; err != nil {
|
if err = orm.Eloquent.Table(role.TableName()).First(&update, id).Error; err != nil {
|
||||||
return
|
return
|
||||||
|
@ -172,7 +172,7 @@ func (role *SysRole) Update(id int) (update SysRole, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//批量删除
|
// 批量删除
|
||||||
func (role *SysRole) BatchDelete(id []int) (Result bool, err error) {
|
func (role *SysRole) BatchDelete(id []int) (Result bool, err error) {
|
||||||
tx := orm.Eloquent.Begin()
|
tx := orm.Eloquent.Begin()
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
orm "go-admin/common/global"
|
orm "go-admin/common/global"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys_role_dept
|
// sys_role_dept
|
||||||
type SysRoleDept struct {
|
type SysRoleDept struct {
|
||||||
RoleId int `gorm:""`
|
RoleId int `gorm:""`
|
||||||
DeptId int `gorm:""`
|
DeptId int `gorm:""`
|
||||||
|
|
|
@ -112,7 +112,7 @@ func (e *SysCategory) Delete(id int) (success bool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//批量删除
|
// 批量删除
|
||||||
func (e *SysCategory) BatchDelete(id []int) (Result bool, err error) {
|
func (e *SysCategory) BatchDelete(id []int) (Result bool, err error) {
|
||||||
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysCategory{}).Error; err != nil {
|
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysCategory{}).Error; err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -122,7 +122,7 @@ func (e *SysContent) Delete(id int) (success bool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//批量删除
|
// 批量删除
|
||||||
func (e *SysContent) BatchDelete(id []int) (Result bool, err error) {
|
func (e *SysContent) BatchDelete(id []int) (Result bool, err error) {
|
||||||
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysContent{}).Error; err != nil {
|
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysContent{}).Error; err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -102,7 +102,7 @@ func (e *SysFileInfo) Delete(id int) (success bool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//批量删除
|
// 批量删除
|
||||||
func (e *SysFileInfo) BatchDelete(id []int) (Result bool, err error) {
|
func (e *SysFileInfo) BatchDelete(id []int) (Result bool, err error) {
|
||||||
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysFileInfo{}).Error; err != nil {
|
if err = orm.Eloquent.Table(e.TableName()).Where("id in (?)", id).Delete(&SysFileInfo{}).Error; err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -107,7 +107,7 @@ func (e *SysJob) Delete(id int) (success bool, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//批量删除
|
// 批量删除
|
||||||
func (e *SysJob) BatchDelete(id []int) error {
|
func (e *SysJob) BatchDelete(id []int) error {
|
||||||
return orm.Eloquent.Table(e.TableName()).Where(id).Delete(&SysJob{}).Error
|
return orm.Eloquent.Table(e.TableName()).Where(id).Delete(&SysJob{}).Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,4 +105,3 @@ func RandomLenNum(length int) string {
|
||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@ const (
|
||||||
|
|
||||||
const DateTimeFormat = "2006-01-02"
|
const DateTimeFormat = "2006-01-02"
|
||||||
const TimeFormat = "2006-01-02 15-04-05"
|
const TimeFormat = "2006-01-02 15-04-05"
|
||||||
|
const QueryTimeFormat = "2006-01-02T15:04:05-07:00"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ExportUrl = "https://dev.admin.deovo.com/load/export/"
|
ExportUrl = "https://dev.admin.deovo.com/load/export/"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//go:build sqlite3
|
||||||
// +build sqlite3
|
// +build sqlite3
|
||||||
|
|
||||||
package database
|
package database
|
||||||
|
|
15
docs/docs.go
15
docs/docs.go
|
@ -4063,17 +4063,12 @@ const docTemplate = `{
|
||||||
"inventorymanage.DeliveryCargoReq": {
|
"inventorymanage.DeliveryCargoReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"id",
|
"id"
|
||||||
"state"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"description": "商品库存列表id",
|
"description": "商品库存列表id",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"description": "库存状态:4-出库",
|
|
||||||
"type": "integer"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -4937,7 +4932,7 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中",
|
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"stock_time_end": {
|
"stock_time_end": {
|
||||||
|
@ -5893,6 +5888,10 @@ const docTemplate = `{
|
||||||
"description": "耗时",
|
"description": "耗时",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"menuTitle": {
|
||||||
|
"description": "操作模块",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"method": {
|
"method": {
|
||||||
"description": "函数",
|
"description": "函数",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -5946,7 +5945,7 @@ const docTemplate = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"description": "操作模块",
|
"description": "操作模块-具体事件",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"updateBy": {
|
"updateBy": {
|
||||||
|
|
|
@ -4052,17 +4052,12 @@
|
||||||
"inventorymanage.DeliveryCargoReq": {
|
"inventorymanage.DeliveryCargoReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"id",
|
"id"
|
||||||
"state"
|
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"description": "商品库存列表id",
|
"description": "商品库存列表id",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"state": {
|
|
||||||
"description": "库存状态:4-出库",
|
|
||||||
"type": "integer"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -4926,7 +4921,7 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中",
|
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"stock_time_end": {
|
"stock_time_end": {
|
||||||
|
@ -5882,6 +5877,10 @@
|
||||||
"description": "耗时",
|
"description": "耗时",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"menuTitle": {
|
||||||
|
"description": "操作模块",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"method": {
|
"method": {
|
||||||
"description": "函数",
|
"description": "函数",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -5935,7 +5934,7 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"description": "操作模块",
|
"description": "操作模块-具体事件",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"updateBy": {
|
"updateBy": {
|
||||||
|
|
|
@ -413,12 +413,8 @@ definitions:
|
||||||
id:
|
id:
|
||||||
description: 商品库存列表id
|
description: 商品库存列表id
|
||||||
type: integer
|
type: integer
|
||||||
state:
|
|
||||||
description: 库存状态:4-出库
|
|
||||||
type: integer
|
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- state
|
|
||||||
type: object
|
type: object
|
||||||
models.BatchPrintInfo:
|
models.BatchPrintInfo:
|
||||||
properties:
|
properties:
|
||||||
|
@ -1048,7 +1044,7 @@ definitions:
|
||||||
description: 首次入库订单编号
|
description: 首次入库订单编号
|
||||||
type: string
|
type: string
|
||||||
state:
|
state:
|
||||||
description: 库存状态:1-在库 2-已售 3-采购退货 4-调拨中
|
description: 库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库
|
||||||
type: integer
|
type: integer
|
||||||
stock_time_end:
|
stock_time_end:
|
||||||
description: 最近入库结束时间
|
description: 最近入库结束时间
|
||||||
|
@ -1735,6 +1731,9 @@ definitions:
|
||||||
latencyime:
|
latencyime:
|
||||||
description: 耗时
|
description: 耗时
|
||||||
type: string
|
type: string
|
||||||
|
menuTitle:
|
||||||
|
description: 操作模块
|
||||||
|
type: string
|
||||||
method:
|
method:
|
||||||
description: 函数
|
description: 函数
|
||||||
type: string
|
type: string
|
||||||
|
@ -1775,7 +1774,7 @@ definitions:
|
||||||
description: 操作状态
|
description: 操作状态
|
||||||
type: string
|
type: string
|
||||||
title:
|
title:
|
||||||
description: 操作模块
|
description: 操作模块-具体事件
|
||||||
type: string
|
type: string
|
||||||
updateBy:
|
updateBy:
|
||||||
description: 更新者
|
description: 更新者
|
||||||
|
|
|
@ -6,8 +6,6 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"go-admin/tools/config"
|
"go-admin/tools/config"
|
||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -51,7 +49,8 @@ func init() {
|
||||||
defer fileLogger.Close()
|
defer fileLogger.Close()
|
||||||
|
|
||||||
// 将日志同时输出到文件和控制台
|
// 将日志同时输出到文件和控制台
|
||||||
l.SetOutput(io.MultiWriter(os.Stdout, fileLogger))
|
//l.SetOutput(io.MultiWriter(os.Stdout, fileLogger))
|
||||||
|
l.SetOutput(fileLogger)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取日志文件名,按照 server-2023-12-01.log 的格式
|
// 获取日志文件名,按照 server-2023-12-01.log 的格式
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
// 获取文件大小
|
// 获取文件大小
|
||||||
func GetSize(f multipart.File) (int, error) {
|
func GetSize(f multipart.File) (int, error) {
|
||||||
content, err := ioutil.ReadAll(f)
|
content, err := io.ReadAll(f)
|
||||||
|
|
||||||
return len(content), err
|
return len(content), err
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ func GetExt(fileName string) string {
|
||||||
return path.Ext(fileName)
|
return path.Ext(fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
//检查文件是否存在
|
// 检查文件是否存在
|
||||||
func CheckExist(src string) bool {
|
func CheckExist(src string) bool {
|
||||||
_, err := os.Stat(src)
|
_, err := os.Stat(src)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ func CheckPermission(src string) bool {
|
||||||
return os.IsPermission(err)
|
return os.IsPermission(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果不存在则新建文件夹
|
// 如果不存在则新建文件夹
|
||||||
func IsNotExistMkDir(src string) error {
|
func IsNotExistMkDir(src string) error {
|
||||||
if exist := CheckExist(src); exist == false {
|
if exist := CheckExist(src); exist == false {
|
||||||
if err := MkDir(src); err != nil {
|
if err := MkDir(src); err != nil {
|
||||||
|
@ -44,7 +44,7 @@ func IsNotExistMkDir(src string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//新建文件夹
|
// 新建文件夹
|
||||||
func MkDir(src string) error {
|
func MkDir(src string) error {
|
||||||
err := os.MkdirAll(src, os.ModePerm)
|
err := os.MkdirAll(src, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -76,7 +76,7 @@ func GetCurrentTimeStamp() int64 {
|
||||||
return time.Now().UnixNano() / 1e6
|
return time.Now().UnixNano() / 1e6
|
||||||
}
|
}
|
||||||
|
|
||||||
//slice去重
|
// slice去重
|
||||||
func RemoveRepByMap(slc []string) []string {
|
func RemoveRepByMap(slc []string) []string {
|
||||||
result := []string{}
|
result := []string{}
|
||||||
tempMap := map[string]byte{}
|
tempMap := map[string]byte{}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
|
|
||||||
var store = base64Captcha.DefaultMemStore
|
var store = base64Captcha.DefaultMemStore
|
||||||
|
|
||||||
//configJsonBody json request body.
|
// configJsonBody json request body.
|
||||||
type configJsonBody struct {
|
type configJsonBody struct {
|
||||||
Id string
|
Id string
|
||||||
CaptchaType string
|
CaptchaType string
|
||||||
|
|
|
@ -110,7 +110,7 @@ func GetFileSize(filename string) int64 {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取当前路径,比如:E:/abc/data/test
|
// 获取当前路径,比如:E:/abc/data/test
|
||||||
func GetCurrentPath() string {
|
func GetCurrentPath() string {
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -3,14 +3,14 @@ package tools
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 获取外网ip地址
|
// 获取外网ip地址
|
||||||
func GetLocation(ip string) string {
|
func GetLocation(ip string) string {
|
||||||
if ip == "127.0.0.1" || ip == "localhost" {
|
if ip == "127.0.0.1" || ip == "localhost" || ip == "::1" {
|
||||||
return "内部IP"
|
return "内部IP"
|
||||||
}
|
}
|
||||||
resp, err := http.Get("https://restapi.amap.com/v3/ip?ip=" + ip + "&key=3fabc36c20379fbb9300c79b19d5d05e")
|
resp, err := http.Get("https://restapi.amap.com/v3/ip?ip=" + ip + "&key=3fabc36c20379fbb9300c79b19d5d05e")
|
||||||
|
@ -19,7 +19,7 @@ func GetLocation(ip string) string {
|
||||||
|
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
s, err := ioutil.ReadAll(resp.Body)
|
s, err := io.ReadAll(resp.Body)
|
||||||
fmt.Printf(string(s))
|
fmt.Printf(string(s))
|
||||||
|
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
//获取URL中批量id并解析
|
// 获取URL中批量id并解析
|
||||||
func IdsStrToIdsIntGroup(key string, c *gin.Context) []int {
|
func IdsStrToIdsIntGroup(key string, c *gin.Context) []int {
|
||||||
return IdsStrToIdsIntGroupStr(c.Param(key))
|
return IdsStrToIdsIntGroupStr(c.Param(key))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user