1.格式化代码;2.修复库存导入缺陷;3.修改库存列表接口,调整逻辑;4.修改获取IP地址接口;5.优化操作日志记录逻辑;

This commit is contained in:
chenlin 2023-12-11 16:21:21 +08:00
parent df19d305b8
commit aa3329c25e
36 changed files with 635 additions and 119 deletions

View File

@ -1,6 +1 @@
package admincron

View File

@ -12,8 +12,7 @@ import (
)
type DeliveryCargoReq struct {
Id uint32 `json:"id" binding:"required"` // 商品库存列表id
State uint32 `json:"state" binding:"required"` // 库存状态:4-出库
Id uint32 `json:"id" binding:"required"` // 商品库存列表id
}
type AddRemarkReq struct {
@ -21,6 +20,27 @@ type AddRemarkReq struct {
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 查询库存列表
// @Summary 查询库存列表
// @Tags 库存管理
@ -36,8 +56,14 @@ func GetInventoryList(c *gin.Context) {
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
return
}
// 如果筛选条件有:库存情况筛选;则以库存表为准,查库存表即可
// 1没门店则查所有库存情况并排序
// 2有门店则查门店对应的库存情况并排序
resp, err := req.List()
// 如果筛选条件没有库存情况,则先查询商品资料,并排序;支持筛选条件:商品编号、商品分类、商品名称
// 然后查询每个商品资料的库存情况没传门店id则查所有库存否则查当前门店的库存情况
resp, err := req.StockList()
if err != nil {
//logger.Error("erp commodity list err:", err)
app.Error(c, http.StatusInternalServerError, err, "获取失败")
@ -96,7 +122,7 @@ func DeliveryCargo(c *gin.Context) {
return
}
err := models.SetStockCommodityState(req.Id, req.State)
err := models.SetStockCommodityState(req.Id)
if err != nil {
//logger.Error("erp stock err:", err)
app.Error(c, http.StatusInternalServerError, err, "获取失败")

View File

@ -98,7 +98,15 @@ func RequestOutLog(c *gin.Context) {
_, ok := global.WHILTE[resultUrl]
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
if len(menuList) > 0 {
sysOperLog.Title = menuList[0].Title
sysOperLog.Title = menuList[0].Title //事件
menu.Title = menuList[0].Title
sysOperLog.MenuTitle, _ = menu.GetParentTitle()
sysOperLog.MenuTitle, _ = menu.GetParentTitle() //操作模块
}
sysOperLog.CreateBy = tools.GetUserName(c)

View File

@ -1,6 +1,6 @@
package models
//sys_casbin_rule
// sys_casbin_rule
type CasbinRule struct {
PType string `json:"p_type" gorm:"size:100;"`
V0 string `json:"v0" gorm:"size:100;"`

View File

@ -631,7 +631,7 @@ func (m *StockImporter) ImportStockData(colsMap []map[string]interface{}) error
StoreName: list[i].StoreName,
ErpCommodityId: v2.ID,
ErpCommodityName: v2.Name,
CommoditySerialNumber: list[i].SerialNum,
CommoditySerialNumber: v2.SerialNumber,
ErpCategoryId: v2.ErpCategoryId,
ErpCategoryName: v2.ErpCategoryName,
ErpSupplierId: v3,
@ -647,6 +647,12 @@ func (m *StockImporter) ImportStockData(colsMap []map[string]interface{}) error
IMEI: v2.IMEI,
Remark: "",
}
if list[i].StockTime != "" { //导入时间不为空
parsedTime, _ := time.Parse("2006/1/2", list[i].StockTime)
stockCommodity.FirstStockTime = parsedTime
}
if list[i].SysGenerate != "" { //导入串码不为空则默认为3手动添加
stockCommodity.IMEIType = 3
stockCommodity.IMEI = list[i].SysGenerate
@ -686,11 +692,11 @@ func (m *StockImporter) processErpStocks(erpStocks []ErpStockCommodity) error {
stockList := erpStocks[start:end]
errGroup.Go(func() error {
return createStockList(begin, stockList)
return createStockList(begin, stockList) //插入库存商品详情
})
}
err := m.ErpStockCountUpdate(begin)
err := m.ErpStockCountUpdate(begin) //更新or插入库存表
if err != nil {
begin.Rollback()
return err
@ -780,7 +786,26 @@ func (m *StockImporter) ErpStockCountUpdate(gdb *gorm.DB) error {
fmt.Println("inventoryStock", inventoryStock.Count)
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 {
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 != "" {
qs = qs.Where("commodity_serial_number=?", m.SerialNumber)
}
@ -1099,6 +1127,12 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
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
if err := qs.Count(&count).Error; err != nil {
//logger.Error("count err:", err)
@ -1106,7 +1140,7 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
}
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) {
//logger.Error("erp commodity list err:", err)
return resp, err
@ -1121,6 +1155,367 @@ func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
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) {
nowTime := time.Now()
for i, _ := range commodities {
@ -1139,7 +1534,7 @@ type ErpStockCommodityListReq struct {
IMEI string `json:"imei"` // 串码
StoreId uint32 `json:"store_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"` // 首次入库订单编号
StorageType uint32 `json:"storage_type"` // 首次入库方式1-系统入库 2-采购入库
StockTimeStart string `json:"stock_time_start"` // 最近入库开始时间
@ -1174,7 +1569,12 @@ func (m *ErpStockCommodityListReq) GetDetailList() (*ErpStockCommodityListResp,
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)
@ -1269,18 +1669,18 @@ func (m *ErpStockCommodityListReq) buildQueryConditions(qs *gorm.DB) {
}
if m.StockTimeStart != "" { //最近入库开始时间
startTime, err := time.Parse(DateTimeFormat, m.StockTimeStart)
startTime, err := time.Parse(QueryTimeFormat, m.StockTimeStart)
if err == nil {
qs = qs.Where("first_stock_time>?", startTime)
qs = qs.Where("stock_time>?", startTime)
} else {
//logger.Error("stock time start parse err:", err)
}
}
if m.StockTimeEnd != "" { //最近入库结束时间
endTime, err := time.Parse(DateTimeFormat, m.StockTimeEnd)
endTime, err := time.Parse(QueryTimeFormat, m.StockTimeEnd)
if err == nil {
qs = qs.Where("first_stock_time<?", endTime)
qs = qs.Where("stock_time<?", endTime)
} else {
//logger.Error("stock time end parse err:", err)
}
@ -1296,15 +1696,51 @@ func (m *ErpStockCommodityListReq) buildQueryConditions(qs *gorm.DB) {
}
// SetStockCommodityState 更新库存状态
func SetStockCommodityState(id, state uint32) error {
if state != 4 {
state = 4
func SetStockCommodityState(id uint32) error { //更新库存状态为5并同步扣减库存数量
begin := orm.Eloquent.Begin()
// 查询库存详情
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)
}
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
}

View File

@ -19,8 +19,8 @@ type SysConfig struct {
UpdateBy string `json:"updateBy" gorm:"size:128;"`
BaseModel
DataScope string `json:"dataScope" gorm:"-"`
Params string `json:"params" gorm:"-"`
DataScope string `json:"dataScope" gorm:"-"`
Params string `json:"params" gorm:"-"`
}
func (SysConfig) TableName() string {

View File

@ -10,8 +10,9 @@ import (
"time"
)
//go:generate goqueryset -in cooperative_business.go
// gen:qs
//
//go:generate goqueryset -in cooperative_business.go
type CooperativeBusiness struct {
Model

View File

@ -9,17 +9,17 @@ import (
)
type SysDept struct {
DeptId int `json:"deptId" gorm:"primary_key;auto_increment;"` //部门编码
ParentId int `json:"parentId" gorm:""` //上级部门
DeptPath string `json:"deptPath" gorm:"size:255;"` //
DeptName string `json:"deptName" gorm:"size:128;"` //部门名称
Sort int `json:"sort" gorm:""` //排序
Leader string `json:"leader" gorm:"size:128;"` //负责人
Phone string `json:"phone" gorm:"size:11;"` //手机
Email string `json:"email" gorm:"size:64;"` //邮箱
Status string `json:"status" gorm:"size:4;"` //状态
CreateBy string `json:"createBy" gorm:"size:64;"`
UpdateBy string `json:"updateBy" gorm:"size:64;"`
DeptId int `json:"deptId" gorm:"primary_key;auto_increment;"` //部门编码
ParentId int `json:"parentId" gorm:""` //上级部门
DeptPath string `json:"deptPath" gorm:"size:255;"` //
DeptName string `json:"deptName" gorm:"size:128;"` //部门名称
Sort int `json:"sort" gorm:""` //排序
Leader string `json:"leader" gorm:"size:128;"` //负责人
Phone string `json:"phone" gorm:"size:11;"` //手机
Email string `json:"email" gorm:"size:64;"` //邮箱
Status string `json:"status" gorm:"size:4;"` //状态
CreateBy string `json:"createBy" gorm:"size:64;"`
UpdateBy string `json:"updateBy" gorm:"size:64;"`
BaseModel
DataScope string `json:"dataScope" gorm:"-"`

View File

@ -10,17 +10,17 @@ import (
)
type DictType struct {
DictId int `gorm:"primary_key;auto_increment;" json:"dictId"`
DictName string `gorm:"size:128;" json:"dictName"` //字典名称
DictType string `gorm:"size:128;" json:"dictType"` //字典类型
Status string `gorm:"size:4;" json:"status"` //状态
CreateBy string `gorm:"size:11;" json:"createBy"` //创建者
UpdateBy string `gorm:"size:11;" json:"updateBy"` //更新者
Remark string `gorm:"size:255;" json:"remark"` //备注
DictId int `gorm:"primary_key;auto_increment;" json:"dictId"`
DictName string `gorm:"size:128;" json:"dictName"` //字典名称
DictType string `gorm:"size:128;" json:"dictType"` //字典类型
Status string `gorm:"size:4;" json:"status"` //状态
CreateBy string `gorm:"size:11;" json:"createBy"` //创建者
UpdateBy string `gorm:"size:11;" json:"updateBy"` //更新者
Remark string `gorm:"size:255;" json:"remark"` //备注
BaseModel
DataScope string `gorm:"-" json:"dataScope"` //
Params string `gorm:"-" json:"params"` //
DataScope string `gorm:"-" json:"dataScope"` //
Params string `gorm:"-" json:"params"` //
}
func (DictType) TableName() string {

View File

@ -7,8 +7,9 @@ import (
orm "go-admin/common/global"
)
//go:generate goqueryset -in config.go
// gen:qs
//
//go:generate goqueryset -in config.go
type Config struct {
Model

View File

@ -346,6 +346,8 @@ func checkCommodityExcel(sheetCols [][]string) error {
// (9)数量必填项限制≥1正整数
// 串码类商品需拆分成每个数量为1单独导入
// 非串码可大于1直接导入 * 串码类商品如数量填写1红框展示下方红字提示“串码类商品数量只能为1”
// 10入库时间必须早于/小于当前时间
func checkStockExcel(sheetCols [][]string) error {
if len(sheetCols) != 9 {
return errors.New("模版错误,请检查文件")
@ -358,6 +360,11 @@ func checkStockExcel(sheetCols [][]string) error {
return errors.New("第" + strconv.Itoa(nMax+1) + "行商品名称和商品编号不能同时为空")
}
// 判断是否有重复串码
if duplicateName, nFlag := hasDuplicateIMEI(sheetCols[3]); nFlag {
return fmt.Errorf("商品串码不允许重复,请检查:[%v]", duplicateName)
}
//先遍历第1列
for i := 1; i < nLow; i++ {
if sheetCols[0][i] == "" && sheetCols[1][i] == "" { // 商品名称和编号不能都为空
@ -390,7 +397,7 @@ func checkStockExcel(sheetCols [][]string) error {
}
// 商品串码规则校验 当串码行数跟其他一致时正常遍历,如果小于其他行,则最后一行不遍历 todo
// 如串码在商品库存表已经存在,则报错提示
// 如串码在商品库存表已经存在,则报错提示
if len(sheetCols[3]) <= nLow && i+1 < nLow {
if err := checkSerialCode(sheetCols[0][i], sheetCols[1][i], sheetCols[3][i], i); err != nil {
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] != "" {
parsedTime, err := time.Parse("2006/1/2", sheetCols[7][i])
if err != nil {
@ -428,6 +436,13 @@ func checkStockExcel(sheetCols [][]string) error {
// 格式化时间为指定格式
formattedTime := parsedTime.Format(DateTimeFormat)
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
}
// 判断是否早于等于当前时间
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 {
maxLength := 0
for _, col := range sheetCols {
@ -534,7 +578,15 @@ func checkSerialCode(productName, productCode, serialCode string, row int) error
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("串码类商品,请填写正确的串码")
}

View File

@ -127,7 +127,7 @@ func (e *SysFileDir) Delete(id int) (success bool, err error) {
return
}
//批量删除
// 批量删除
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 {
return

View File

@ -20,5 +20,5 @@ func TestExpressInfo(t *testing.T) {
//fmt.Println("paramJson:", string(paramJson))
//ExpressInfo("zhongtong","73155364431352")
ExpressInfo("emsbg","9868015085913")
ExpressInfo("emsbg", "9868015085913")
}

View File

@ -6,14 +6,14 @@ import (
)
type Post struct {
PostId int `gorm:"primary_key;AUTO_INCREMENT" json:"postId"` //岗位编号
PostName string `gorm:"size:128;" json:"postName"` //岗位名称
PostCode string `gorm:"size:128;" json:"postCode"` //岗位代码
Sort int `gorm:"" json:"sort"` //岗位排序
Status string `gorm:"size:4;" json:"status"` //状态
Remark string `gorm:"size:255;" json:"remark"` //描述
CreateBy string `gorm:"size:128;" json:"createBy"`
UpdateBy string `gorm:"size:128;" json:"updateBy"`
PostId int `gorm:"primary_key;AUTO_INCREMENT" json:"postId"` //岗位编号
PostName string `gorm:"size:128;" json:"postName"` //岗位名称
PostCode string `gorm:"size:128;" json:"postCode"` //岗位代码
Sort int `gorm:"" json:"sort"` //岗位排序
Status string `gorm:"size:4;" json:"status"` //状态
Remark string `gorm:"size:255;" json:"remark"` //描述
CreateBy string `gorm:"size:128;" json:"createBy"`
UpdateBy string `gorm:"size:128;" json:"updateBy"`
BaseModel
DataScope string `gorm:"-" json:"dataScope"`

View File

@ -22,9 +22,9 @@ type SysRole struct {
DataScope string `json:"dataScope" gorm:"size:128;"`
BaseModel
Params string `json:"params" gorm:"-"`
MenuIds []int `json:"menuIds" gorm:"-"`
DeptIds []int `json:"deptIds" gorm:"-"`
Params string `json:"params" gorm:"-"`
MenuIds []int `json:"menuIds" gorm:"-"`
DeptIds []int `json:"deptIds" gorm:"-"`
}
func (SysRole) TableName() string {
@ -150,7 +150,7 @@ func (role *SysRole) GetRoleDeptId() ([]int, error) {
return deptIds, nil
}
//修改
// 修改
func (role *SysRole) Update(id int) (update SysRole, err error) {
if err = orm.Eloquent.Table(role.TableName()).First(&update, id).Error; err != nil {
return
@ -172,7 +172,7 @@ func (role *SysRole) Update(id int) (update SysRole, err error) {
return
}
//批量删除
// 批量删除
func (role *SysRole) BatchDelete(id []int) (Result bool, err error) {
tx := orm.Eloquent.Begin()

View File

@ -6,7 +6,7 @@ import (
orm "go-admin/common/global"
)
//sys_role_dept
// sys_role_dept
type SysRoleDept struct {
RoleId int `gorm:""`
DeptId int `gorm:""`

View File

@ -112,7 +112,7 @@ func (e *SysCategory) Delete(id int) (success bool, err error) {
return
}
//批量删除
// 批量删除
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 {
return

View File

@ -122,7 +122,7 @@ func (e *SysContent) Delete(id int) (success bool, err error) {
return
}
//批量删除
// 批量删除
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 {
return

View File

@ -102,7 +102,7 @@ func (e *SysFileInfo) Delete(id int) (success bool, err error) {
return
}
//批量删除
// 批量删除
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 {
return

View File

@ -24,7 +24,7 @@ type SysJob struct {
UpdateBy string `json:"updateBy" gorm:"size:128;"` //
BaseModel
DataScope string `json:"dataScope" gorm:"-"`
DataScope string `json:"dataScope" gorm:"-"`
}
func (SysJob) TableName() string {
@ -107,7 +107,7 @@ func (e *SysJob) Delete(id int) (success bool, err error) {
return
}
//批量删除
// 批量删除
func (e *SysJob) BatchDelete(id []int) error {
return orm.Eloquent.Table(e.TableName()).Where(id).Delete(&SysJob{}).Error
}

View File

@ -105,4 +105,3 @@ func RandomLenNum(length int) string {
}
return str
}

View File

@ -87,6 +87,7 @@ const (
const DateTimeFormat = "2006-01-02"
const TimeFormat = "2006-01-02 15-04-05"
const QueryTimeFormat = "2006-01-02T15:04:05-07:00"
const (
ExportUrl = "https://dev.admin.deovo.com/load/export/"

View File

@ -37,7 +37,7 @@ func (m *SysJobSearch) Generate() dto.Index {
}
type SysJobControl struct {
JobId uint `json:"jobId"`
JobId uint `json:"jobId"`
JobName string `json:"jobName" validate:"required"` // 名称
JobGroup string `json:"jobGroup"` // 任务分组
JobType int `json:"jobType"` // 任务类型
@ -93,7 +93,7 @@ func (s *SysJobById) GenerateM() (common.ActiveRecord, error) {
}
type SysJobItem struct {
JobId uint `json:"jobId"`
JobId uint `json:"jobId"`
JobName string `json:"jobName" validate:"required"` // 名称
JobGroup string `json:"jobGroup"` // 任务分组
JobType int `json:"jobType"` // 任务类型

View File

@ -1,3 +1,4 @@
//go:build sqlite3
// +build sqlite3
package database

View File

@ -27,4 +27,4 @@ func (res *Response) ReturnOK() *Response {
func (res *Response) ReturnError(code int) *Response {
res.Code = code
return res
}
}

View File

@ -4063,17 +4063,12 @@ const docTemplate = `{
"inventorymanage.DeliveryCargoReq": {
"type": "object",
"required": [
"id",
"state"
"id"
],
"properties": {
"id": {
"description": "商品库存列表id",
"type": "integer"
},
"state": {
"description": "库存状态:4-出库",
"type": "integer"
}
}
},
@ -4937,7 +4932,7 @@ const docTemplate = `{
"type": "string"
},
"state": {
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中",
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库",
"type": "integer"
},
"stock_time_end": {
@ -5893,6 +5888,10 @@ const docTemplate = `{
"description": "耗时",
"type": "string"
},
"menuTitle": {
"description": "操作模块",
"type": "string"
},
"method": {
"description": "函数",
"type": "string"
@ -5946,7 +5945,7 @@ const docTemplate = `{
"type": "string"
},
"title": {
"description": "操作模块",
"description": "操作模块-具体事件",
"type": "string"
},
"updateBy": {

View File

@ -4052,17 +4052,12 @@
"inventorymanage.DeliveryCargoReq": {
"type": "object",
"required": [
"id",
"state"
"id"
],
"properties": {
"id": {
"description": "商品库存列表id",
"type": "integer"
},
"state": {
"description": "库存状态:4-出库",
"type": "integer"
}
}
},
@ -4926,7 +4921,7 @@
"type": "string"
},
"state": {
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中",
"description": "库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库",
"type": "integer"
},
"stock_time_end": {
@ -5882,6 +5877,10 @@
"description": "耗时",
"type": "string"
},
"menuTitle": {
"description": "操作模块",
"type": "string"
},
"method": {
"description": "函数",
"type": "string"
@ -5935,7 +5934,7 @@
"type": "string"
},
"title": {
"description": "操作模块",
"description": "操作模块-具体事件",
"type": "string"
},
"updateBy": {

View File

@ -413,12 +413,8 @@ definitions:
id:
description: 商品库存列表id
type: integer
state:
description: 库存状态:4-出库
type: integer
required:
- id
- state
type: object
models.BatchPrintInfo:
properties:
@ -1048,7 +1044,7 @@ definitions:
description: 首次入库订单编号
type: string
state:
description: 库存状态:1-在库 2-已售 3-采购退货 4-调拨中
description: 库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库
type: integer
stock_time_end:
description: 最近入库结束时间
@ -1735,6 +1731,9 @@ definitions:
latencyime:
description: 耗时
type: string
menuTitle:
description: 操作模块
type: string
method:
description: 函数
type: string
@ -1775,7 +1774,7 @@ definitions:
description: 操作状态
type: string
title:
description: 操作模块
description: 操作模块-具体事件
type: string
updateBy:
description: 更新者

View File

@ -6,8 +6,6 @@ import (
"github.com/sirupsen/logrus"
"go-admin/tools/config"
"gopkg.in/natefinch/lumberjack.v2"
"io"
"os"
"path/filepath"
"time"
)
@ -51,7 +49,8 @@ func init() {
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 的格式

View File

@ -1,7 +1,7 @@
package utils
import (
"io/ioutil"
"io"
"mime/multipart"
"os"
"path"
@ -9,7 +9,7 @@ import (
// 获取文件大小
func GetSize(f multipart.File) (int, error) {
content, err := ioutil.ReadAll(f)
content, err := io.ReadAll(f)
return len(content), err
}
@ -19,7 +19,7 @@ func GetExt(fileName string) string {
return path.Ext(fileName)
}
//检查文件是否存在
// 检查文件是否存在
func CheckExist(src string) bool {
_, err := os.Stat(src)
@ -33,7 +33,7 @@ func CheckPermission(src string) bool {
return os.IsPermission(err)
}
//如果不存在则新建文件夹
// 如果不存在则新建文件夹
func IsNotExistMkDir(src string) error {
if exist := CheckExist(src); exist == false {
if err := MkDir(src); err != nil {
@ -44,7 +44,7 @@ func IsNotExistMkDir(src string) error {
return nil
}
//新建文件夹
// 新建文件夹
func MkDir(src string) error {
err := os.MkdirAll(src, os.ModePerm)
if err != nil {

View File

@ -76,7 +76,7 @@ func GetCurrentTimeStamp() int64 {
return time.Now().UnixNano() / 1e6
}
//slice去重
// slice去重
func RemoveRepByMap(slc []string) []string {
result := []string{}
tempMap := map[string]byte{}

View File

@ -9,7 +9,7 @@ import (
var store = base64Captcha.DefaultMemStore
//configJsonBody json request body.
// configJsonBody json request body.
type configJsonBody struct {
Id string
CaptchaType string

View File

@ -110,7 +110,7 @@ func GetFileSize(filename string) int64 {
return result
}
//获取当前路径比如E:/abc/data/test
// 获取当前路径比如E:/abc/data/test
func GetCurrentPath() string {
dir, err := os.Getwd()
if err != nil {

View File

@ -3,14 +3,14 @@ package tools
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"net"
"net/http"
)
// 获取外网ip地址
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"
}
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()
s, err := ioutil.ReadAll(resp.Body)
s, err := io.ReadAll(resp.Body)
fmt.Printf(string(s))
m := make(map[string]string)

View File

@ -24,4 +24,4 @@ func StructToJsonStr(e interface{}) (string, error) {
} else {
return "", err
}
}
}

View File

@ -6,7 +6,7 @@ import (
"github.com/gin-gonic/gin"
)
//获取URL中批量id并解析
// 获取URL中批量id并解析
func IdsStrToIdsIntGroup(key string, c *gin.Context) []int {
return IdsStrToIdsIntGroupStr(c.Param(key))
}