1.新增库存变动相关接口(新增、编辑、审核、删除、列表、详情);

This commit is contained in:
chenlin 2024-04-17 09:37:02 +08:00
parent 7c8a431c2b
commit 3dd501a3dc
13 changed files with 1375 additions and 209 deletions

View File

@ -20,10 +20,10 @@ type CommodityCreateRequest struct {
ErpBarcode string `json:"erp_barcode"` // 商品条码
IMEIType uint32 `json:"imei_type"` // 系统生成串码2-是(系统生成) 3-否(手动添加)
ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 主供应商
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价
RetailPrice float64 `json:"retail_price"` // 指导零售价
MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价
StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice float64 `json:"wholesale_price"` // 指导采购价
Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成
Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成
MemberDiscount float64 `json:"member_discount"` // 会员优惠
@ -240,10 +240,10 @@ type CommodityEditRequest struct {
IsIMEI uint32 `json:"is_imei" binding:"required"` // 是否串码1-串码类 2-非串码
IMEIType uint32 `json:"imei_type" binding:"required"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 主供应商id
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价
RetailPrice float64 `json:"retail_price"` // 指导零售价
MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价
StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice float64 `json:"wholesale_price"` // 指导采购价
Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成
Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成
MemberDiscount float64 `json:"member_discount"` // 会员优惠

View File

@ -2,8 +2,12 @@ package inventorymanage
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"go-admin/app/admin/models"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"go-admin/tools/app"
"net/http"
)
@ -21,12 +25,31 @@ import (
func InventoryChangeAdd(c *gin.Context) {
req := &models.InventoryChangeAddReq{}
if err := c.ShouldBindJSON(&req); err != nil {
//logger.Error(err)
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
app.Error(c, http.StatusBadRequest, errors.New("param err"), "参数错误:"+err.Error())
return
}
app.OK(c, "", "OK")
err := tools.Validate(req) //必填参数校验
if err != nil {
app.Error(c, http.StatusBadRequest, err, err.Error())
return
}
sysUser, err := models.GetSysUserByCtx(c)
if err != nil {
logger.Error("sys user err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "操作失败")
return
}
changeProductOrder, err := models.AddInventoryChange(req, sysUser)
if err != nil {
logger.Error("InventoryChangeAdd err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "新增失败:"+err.Error())
return
}
app.OK(c, changeProductOrder, "新增成功")
return
}
@ -41,12 +64,24 @@ func InventoryChangeAdd(c *gin.Context) {
func InventoryChangeEdit(c *gin.Context) {
req := &models.InventoryChangeEditReq{}
if err := c.ShouldBindJSON(&req); err != nil {
//logger.Error(err)
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
app.Error(c, http.StatusBadRequest, errors.New("param err"), "参数错误:"+err.Error())
return
}
app.OK(c, "", "OK")
err := tools.Validate(req) //必填参数校验
if err != nil {
app.Error(c, http.StatusBadRequest, err, err.Error())
return
}
changeProductOrder, err := models.EditChangeInventory(req)
if err != nil {
logger.Error("InventoryChangeEdit err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "编辑失败:"+err.Error())
return
}
app.OK(c, changeProductOrder, "编辑成功")
return
}
@ -62,11 +97,24 @@ func InventoryChangeAudit(c *gin.Context) {
req := &models.InventoryChangeAuditReq{}
if err := c.ShouldBindJSON(&req); err != nil {
//logger.Error(err)
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
app.Error(c, http.StatusBadRequest, errors.New("param err"), "参数错误:"+err.Error())
return
}
app.OK(c, "", "OK")
sysUser, err := models.GetSysUserByCtx(c)
if err != nil {
logger.Error("sys user err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "操作失败")
return
}
err = models.AuditChangeInventory(req, sysUser)
if err != nil {
app.Error(c, http.StatusInternalServerError, err, "审核失败:"+err.Error())
return
}
app.OK(c, nil, "操作成功")
return
}
@ -82,11 +130,77 @@ func InventoryChangeDelete(c *gin.Context) {
req := &models.InventoryChangeDeleteReq{}
if err := c.ShouldBindJSON(&req); err != nil {
//logger.Error(err)
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
app.Error(c, http.StatusBadRequest, errors.New("param err"), "参数错误")
return
}
app.OK(c, "", "OK")
err := tools.Validate(req) //必填参数校验
if err != nil {
app.Error(c, http.StatusBadRequest, err, err.Error())
return
}
// todo 需要校验当前用户是否有权限
var inventoryChangeOrder models.ErpInventoryChangeOrder
err = orm.Eloquent.Table("erp_inventory_change_order").Where("serial_number = ?", req.SerialNumber).
Find(&inventoryChangeOrder).Error
if err != nil {
logger.Error("order err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "删除失败:"+err.Error())
return
}
if inventoryChangeOrder.SerialNumber == "" {
logger.Error("order is null")
app.Error(c, http.StatusInternalServerError, err, "删除失败:订单不存在")
return
}
// 仅待审核订单可删除
if inventoryChangeOrder.State != models.ErpInventoryChangeOrderUnAudit {
logger.Error("order err, inventoryChangeOrder.State is:", logger.Field("inventoryChangeOrder.State",
inventoryChangeOrder.State))
app.Error(c, http.StatusInternalServerError, err, "删除失败:仅待审核订单可删除")
return
}
begin := orm.Eloquent.Begin()
// 1-删除采购订单表
err = begin.Delete(inventoryChangeOrder).Error
if err != nil {
logger.Error("order delete1 err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "删除失败:"+err.Error())
return
}
// 2-删除采购订单商品表
var commodities []models.ErpInventoryChangeCommodity
err = orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
inventoryChangeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
app.Error(c, http.StatusInternalServerError, err, "删除失败:"+err.Error())
return
}
if len(commodities) != 0 {
err = begin.Delete(&commodities).Error
if err != nil {
logger.Error("更新商品订单信息-删除 error")
app.Error(c, http.StatusInternalServerError, err, "删除失败:"+err.Error())
return
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return
}
app.OK(c, nil, "删除成功")
return
}
@ -102,11 +216,17 @@ func InventoryChangeList(c *gin.Context) {
req := &models.InventoryChangeListReq{}
if err := c.ShouldBindJSON(&req); err != nil {
//logger.Error(err)
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
app.Error(c, http.StatusBadRequest, errors.New("param err"), "参数错误:"+err.Error())
return
}
app.OK(c, "", "OK")
resp, err := req.List()
if err != nil {
app.Error(c, http.StatusInternalServerError, err, "获取失败:"+err.Error())
return
}
app.OK(c, resp, "查询成功")
return
}
@ -121,11 +241,42 @@ func InventoryChangeList(c *gin.Context) {
func InventoryChangeDetail(c *gin.Context) {
req := &models.InventoryChangeDetailReq{}
if err := c.ShouldBindJSON(&req); err != nil {
//logger.Error(err)
app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误")
app.Error(c, http.StatusBadRequest, errors.New("param err"), "参数错误:"+err.Error())
return
}
app.OK(c, "", "OK")
var changeOrder models.ErpInventoryChangeOrder
err := orm.Eloquent.Table("erp_inventory_change_order").Where("serial_number=?", req.SerialNumber).
Find(&changeOrder).Error
if err != nil {
logger.Error("change order err:", logger.Field("err", err))
app.Error(c, http.StatusBadRequest, err, "获取失败")
return
}
if changeOrder.ID == 0 {
logger.Error("change commodities err:", logger.Field("err", err))
app.Error(c, http.StatusBadRequest, err, fmt.Sprintf("未查询到订单[%s]", req.SerialNumber))
return
}
// 校验时间如果为01-01-01 08:05则赋值为空
if changeOrder.MakerTime != nil && changeOrder.MakerTime.IsZero() {
changeOrder.MakerTime = nil
}
if changeOrder.AuditTime != nil && changeOrder.AuditTime.IsZero() {
changeOrder.AuditTime = nil
}
var changeCommodities []models.ErpInventoryChangeCommodity
err = orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id=?", changeOrder.ID).
Find(&changeCommodities).Error
if err != nil {
logger.Error("change commodities err:", logger.Field("err", err))
app.Error(c, http.StatusBadRequest, err, "获取失败")
return
}
changeOrder.Commodities = changeCommodities
app.OK(c, changeOrder, "查询成功")
return
}

View File

@ -281,8 +281,9 @@ func UpdateSysUser(c *gin.Context) {
tools.HasError(err, "数据解析失败", 500)
}
sysInfo := models.GetUserById(uint32(req.UserId))
// 判断小程序账号ID是否正常
if req.Uid != 0 {
if req.Uid != 0 && sysInfo.Uid != req.Uid {
userInfo, err := models.GetUserInfoByUid(req.Uid)
if err != nil {
logger.Error("get user info err:", logger.Field("err", err))
@ -339,7 +340,6 @@ func UpdateSysUser(c *gin.Context) {
tools.HasError(err, "修改失败", 500)
// 判断是否修改了uid
sysInfo := models.GetUserById(uint32(req.UserId))
if sysInfo.Uid == 0 && req.Uid != 0 { // 新增uid直接更新为2即可
err = models.UpdateUserType(begin, req.Uid, 2)
} else if sysInfo.Uid != 0 {

View File

@ -6,6 +6,7 @@ import (
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"go-admin/tools/config"
"golang.org/x/sync/errgroup"
"gorm.io/gorm"
@ -18,9 +19,12 @@ import (
)
const (
NoIMEICommodity = 1 // 非串码商品类型
NoIMEICommodity = 1 // 非串码商品类型
SystemInventory = 1 // 系统入库
PurchaseInventory = 2 // 采购入库
ProductInventory = 3 // 产品入库
CheckInventory = 4 // 盘点入库
InStock = 1 // 在库
SoldOut = 2 // 已售
@ -28,6 +32,7 @@ const (
InAllot = 4 // 调拨中(调入门店)
OnSale = 5 // 销售锁定中
ProductReturn = 6 // 产品出库
CheckOut = 7 // 盘点出库
)
// ErpStock 库存列表
@ -42,8 +47,8 @@ type ErpStock struct {
ErpCategoryName string `json:"erp_category_name"` // 分类名称
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编码/串码
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
RetailPrice float64 `json:"retail_price"` // 指导零售价
MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价
Count uint32 `json:"count"` // 数量
DispatchCount uint32 `json:"dispatch_count"` // 调拨中数量
Commodities []ErpStockCommodity `json:"commodities" gorm:"-"`
@ -67,14 +72,14 @@ type ErpStockCommodity struct {
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
StockTime time.Time `json:"stock_time"` // 最近入库时间
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价加价50不是加价后的价格
WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价
RetailPrice float64 `json:"retail_price"` // 指导零售价
MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价
StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价加价50不是加价后的价格
WholesalePrice float64 `json:"wholesale_price"` // 指导采购价
MemberDiscount float64 `json:"member_discount"` // 会员优惠
State uint32 `json:"state"` // 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中
State uint32 `json:"state"` // 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 6-产品出库 7-盘点出库
Count uint32 `json:"count"` // 数量
StorageType uint32 `json:"storage_type"` // 入库方式1-系统入库 2-采购入库 3-产品入库
StorageType uint32 `json:"storage_type"` // 入库方式1-系统入库 2-采购入库 3-产品入库 4-盘点入库
FirstStockTime time.Time `json:"first_stock_time"` // 首次入库时间
StockSn string `json:"stock_sn"` // 库存订单编号(跟采购入库的入库编号关联)
OriginalSn string `json:"original_sn" gorm:"index"` // 首次入库订单编号(单据编号)
@ -102,10 +107,10 @@ type ErpCommodity struct {
IMEI string `json:"imei"` // 串码
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 主供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 主供应商名称
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价加价50不是加价后的价格
WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价
RetailPrice float64 `json:"retail_price"` // 指导零售价
MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价
StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价加价50不是加价后的价格
WholesalePrice float64 `json:"wholesale_price"` // 指导采购价
Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成
Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成
MemberDiscount float64 `json:"member_discount"` // 会员优惠
@ -155,18 +160,18 @@ type ErpSupplier struct {
type ErpInventoryStock struct {
Model
StoreId uint32 `json:"store_id" gorm:"index"`
StoreName string `json:"store_name"`
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"`
ErpCommodityName string `json:"erp_commodity_name"`
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"`
ErpCategoryName string `json:"erp_category_name"`
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"`
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
RetailPrice uint32 `json:"retail_price"`
MinRetailPrice uint32 `json:"min_retail_price"`
Count uint32 `json:"count"`
Sn string `json:"sn" gorm:"index"`
StoreId uint32 `json:"store_id" gorm:"index"`
StoreName string `json:"store_name"`
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"`
ErpCommodityName string `json:"erp_commodity_name"`
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"`
ErpCategoryName string `json:"erp_category_name"`
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"`
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
RetailPrice float64 `json:"retail_price"`
MinRetailPrice float64 `json:"min_retail_price"`
Count uint32 `json:"count"`
Sn string `json:"sn" gorm:"index"`
//ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"`
//ErpSupplierName string `json:"erp_supplier_name"`
//IMEI string `json:"imei"`
@ -188,10 +193,10 @@ type ErpInventoryStockCommodity struct {
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"`
ErpSupplierName string `json:"erp_supplier_name"`
StockTime time.Time `json:"stock_time"`
RetailPrice uint32 `json:"retail_price"`
MinRetailPrice uint32 `json:"min_retail_price"`
StaffCostPrice uint32 `json:"staff_cost_price"`
WholesalePrice uint32 `json:"wholesale_price"`
RetailPrice float64 `json:"retail_price"`
MinRetailPrice float64 `json:"min_retail_price"`
StaffCostPrice float64 `json:"staff_cost_price"`
WholesalePrice float64 `json:"wholesale_price"`
Count uint32 `json:"count"`
StorageType uint32 `json:"storage_type"`
Sn string `json:"sn" gorm:"index"`
@ -564,10 +569,10 @@ func (e *ErpStockFileExcel) Processing() {
}
e.StockTime = parseTime
e.RetailPrice = PercentFloatStringToUin32(e.RetailPriceString)
e.MinRetailPrice = PercentFloatStringToUin32(e.MinRetailPriceString)
e.StaffCostPrice = PercentFloatStringToUin32(e.StaffCostPriceString)
e.WholesalePrice = PercentFloatStringToUin32(e.WholesalePriceString)
e.RetailPrice = PercentFloatStringToFloat64(e.RetailPriceString)
e.MinRetailPrice = PercentFloatStringToFloat64(e.MinRetailPriceString)
e.StaffCostPrice = PercentFloatStringToFloat64(e.StaffCostPriceString)
e.WholesalePrice = PercentFloatStringToFloat64(e.WholesalePriceString)
}
@ -669,11 +674,11 @@ func (m *StockImporter) ImportStockData(colsMap []map[string]interface{}) error
}
// 注意:表格导入是员工成本价,数据库存储是员工成本价加价=员工成本价-指导采购价
nStaffCostPrice, err := strconv.ParseUint(list[i].StaffCostPrice, 10, 32)
nStaffCostPrice, err := strconv.ParseFloat(list[i].StaffCostPrice, 64)
if err != nil {
return fmt.Errorf("员工成本价转换有误:[%v]", err)
}
nWholesalePrice, err := strconv.ParseUint(list[i].WholesalePrice, 10, 32) // 指导采购价
nWholesalePrice, err := strconv.ParseFloat(list[i].WholesalePrice, 64) // 指导采购价
if err != nil {
return fmt.Errorf("指导采购价转换有误:[%v]", err)
}
@ -697,10 +702,10 @@ func (m *StockImporter) ImportStockData(colsMap []map[string]interface{}) error
ErpCategoryName: v2.ErpCategoryName,
ErpSupplierId: v3,
ErpSupplierName: list[i].SupplierName,
StaffCostPrice: uint32(nStaffCostPrice - nWholesalePrice),
WholesalePrice: uint32(nWholesalePrice),
State: 1,
StorageType: 1,
StaffCostPrice: tools.RoundToTwoDecimalPlaces(nStaffCostPrice - nWholesalePrice),
WholesalePrice: tools.RoundToTwoDecimalPlaces(nWholesalePrice),
State: InStock,
StorageType: SystemInventory,
FirstStockTime: nowTime,
StockTime: nowTime,
Count: 1,
@ -1825,8 +1830,8 @@ func (m *ErpStockCommodityListReq) GetDetailList() (*ErpStockCommodityListResp,
}
nTotalCount := &struct {
TotalWholesalePrice int `json:"total_wholesale_price"`
TotalStaffCostPrice int `json:"total_staff_cost_price"`
TotalWholesalePrice float64 `json:"total_wholesale_price"`
TotalStaffCostPrice float64 `json:"total_staff_cost_price"`
}{}
err := es.Debug().Select("SUM(wholesale_price) as total_wholesale_price, SUM(staff_cost_price) as total_staff_cost_price").
Scan(&nTotalCount).Error
@ -2102,8 +2107,8 @@ func StringToFloat(req string) (float64, error) {
return strconv.ParseFloat(req, 64)
}
func PercentFloatStringToUin32(s string) uint32 {
u := uint32(0)
func PercentFloatStringToFloat64(s string) float64 {
u := float64(0)
if s != "" {
s = strings.ReplaceAll(s, "%", "")
}
@ -2113,8 +2118,8 @@ func PercentFloatStringToUin32(s string) uint32 {
return u
}
u = uint32(f * 100)
return u
u = f * 100
return tools.RoundToTwoDecimalPlaces(u)
}
func IntStringToUin32(s string) uint32 {

View File

@ -817,7 +817,7 @@ func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state int) error {
for j := 0; j < int(commodities[i].Count); j++ {
// 通过门店id商品id查找状态为2-已售的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 2, 1).
"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, SoldOut, NoIMEICommodity).
Order("first_stock_time DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))

View File

@ -10,6 +10,7 @@ import (
"go-admin/app/admin/models/tools"
orm "go-admin/common/global"
"go-admin/logger"
tool "go-admin/tools"
"gorm.io/gorm"
"reflect"
"strconv"
@ -349,11 +350,11 @@ func hasDuplicateNames(sheetCols [][]string) (string, bool) {
// 确保每一列数据都有相同数量的行数
rowsCount := len(sheetCols[0])
for i, col := range sheetCols {
if len(col) != rowsCount && i != 2 {
return "每列数据的行数不一致", true
}
}
//for i, col := range sheetCols {
// if len(col) != rowsCount && i != 2 {
// return "每列数据的行数不一致", true
// }
//}
for i := 0; i < rowsCount; i++ {
//// 检查第一列
@ -524,13 +525,13 @@ func checkStockExcel(sheetCols [][]string) error {
// 采购价、员工成本价必须大于0
if i < len(sheetCols[4]) {
if purchasePrice, err := strconv.Atoi(sheetCols[4][i]); err != nil || purchasePrice <= 0 {
if purchasePrice, err := strconv.ParseFloat(sheetCols[4][i], 64); err != nil || purchasePrice <= 0 {
return errors.New("第" + strconv.Itoa(i+1) + "行采购价必须是大于0的数字")
}
}
if i < len(sheetCols[5]) {
if employeeCost, err := strconv.Atoi(sheetCols[5][i]); err != nil || employeeCost <= 0 {
if employeeCost, err := strconv.ParseFloat(sheetCols[5][i], 64); err != nil || employeeCost <= 0 {
return errors.New("第" + strconv.Itoa(i+1) + "行员工成本价必须是大于0的数字")
}
}
@ -1059,19 +1060,19 @@ func convertToErpCommodity(item CommodityExcel, category *Category, supplier *Su
if err != nil {
return ErpCommodity{}, fmt.Errorf("会员优惠转换有误:[%v]", err)
}
nRetailPrice, err := strconv.ParseUint(item.RetailPrice, 10, 32) // 指导零售价
nRetailPrice, err := strconv.ParseFloat(item.RetailPrice, 64) // 指导零售价
if err != nil {
return ErpCommodity{}, fmt.Errorf("指导零售价转换有误:[%v]", err)
}
nMinRetailPrice, err := strconv.ParseUint(item.MinRetailPrice, 10, 32) // 最低零售价
nMinRetailPrice, err := strconv.ParseFloat(item.MinRetailPrice, 64) // 最低零售价
if err != nil {
return ErpCommodity{}, fmt.Errorf("最低零售价转换有误:[%v]", err)
}
nStaffCostPrice, err := strconv.ParseUint(item.StaffCostPrice, 10, 32) // 员工成本价加价
nStaffCostPrice, err := strconv.ParseFloat(item.StaffCostPrice, 64) // 员工成本价加价
if err != nil {
return ErpCommodity{}, fmt.Errorf("员工成本价加价转换有误:[%v]", err)
}
nWholesalePrice, err := strconv.ParseUint(item.WholesalePrice, 10, 32) // 指导采购价
nWholesalePrice, err := strconv.ParseFloat(item.WholesalePrice, 64) // 指导采购价
if err != nil {
return ErpCommodity{}, fmt.Errorf("指导采购价转换有误:[%v]", err)
}
@ -1105,13 +1106,13 @@ func convertToErpCommodity(item CommodityExcel, category *Category, supplier *Su
IMEIType: nIMEIType,
ErpSupplierId: supplier.ID,
ErpSupplierName: item.SupplierName,
RetailPrice: uint32(nRetailPrice),
MinRetailPrice: uint32(nMinRetailPrice),
StaffCostPrice: uint32(nStaffCostPrice),
WholesalePrice: uint32(nWholesalePrice),
Brokerage1: brokerage1Float,
Brokerage2: brokerage2Float,
MemberDiscount: memberDiscountFloat,
RetailPrice: tool.RoundToTwoDecimalPlaces(nRetailPrice),
MinRetailPrice: tool.RoundToTwoDecimalPlaces(nMinRetailPrice),
StaffCostPrice: tool.RoundToTwoDecimalPlaces(nStaffCostPrice),
WholesalePrice: tool.RoundToTwoDecimalPlaces(nWholesalePrice),
Brokerage1: tool.RoundToTwoDecimalPlaces(brokerage1Float),
Brokerage2: tool.RoundToTwoDecimalPlaces(brokerage2Float),
MemberDiscount: tool.RoundToTwoDecimalPlaces(memberDiscountFloat),
Origin: item.Origin,
Remark: item.Remark,
}, nil
@ -1207,7 +1208,7 @@ func GenerateSerialNumber(categoryId uint32) (string, error) {
}
// UpdateErpStockAmountInfo 更新库存和库存商品表的金额:指导零售价、最低零售价
func UpdateErpStockAmountInfo(begin *gorm.DB, commodityId, retailPrice, minRetailPrice uint32, barCode string,
func UpdateErpStockAmountInfo(begin *gorm.DB, commodityId uint32, retailPrice, minRetailPrice float64, barCode string,
category *ErpCategory) error {
if category != nil && category.ID != 0 { // 分类信息有值
// 更新库存表

View File

@ -6,6 +6,7 @@ import (
orm "go-admin/common/global"
"go-admin/logger"
"gorm.io/gorm"
"math/rand"
"time"
)
@ -190,6 +191,31 @@ func checkAllotInventoryParam(req *InventoryAllotAddReq, editFlag bool) error {
return nil
}
// newAllotInventorySn 生成库存调拨订单号
func newAllotInventorySn() string {
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create NewProductInventorySn err")
return ""
}
random := rand.Intn(9000) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_inventory_allot_order "+
"WHERE serial_number='%s'", "db"+sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return "db" + sn
}
max++
}
}
// AddInventoryAllot 新增库存调拨
func AddInventoryAllot(req *InventoryAllotAddReq, sysUser *SysUser) (*ErpInventoryAllotOrder, error) {
// 检查库存调拨信息
@ -208,12 +234,12 @@ func AddInventoryAllot(req *InventoryAllotAddReq, sysUser *SysUser) (*ErpInvento
// 组合库存调拨订单数据
inventoryAllotOrder := &ErpInventoryAllotOrder{
SerialNumber: "db" + NewProductInventorySn(),
SerialNumber: newAllotInventorySn(),
DeliverStoreId: req.DeliverStoreId,
DeliverStoreName: req.DeliverStoreName,
ReceiveStoreId: req.ReceiveStoreId,
ReceiveStoreName: req.ReceiveStoreName,
HandlerId: req.HandlerId,
HandlerId: uint32(sysUser.UserId),
HandlerName: req.HandlerName,
MakerTime: &nowTime,
MakerId: uint32(sysUser.UserId),
@ -339,7 +365,7 @@ func updateAllotCommodityData(gdb *gorm.DB, orderId uint32, req *InventoryAllotE
var found bool
for _, dbCommodity := range commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.IMEI == dbCommodity.IMEI {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
break
}
@ -353,7 +379,7 @@ func updateAllotCommodityData(gdb *gorm.DB, orderId uint32, req *InventoryAllotE
for _, dbCommodity := range commodities {
var found bool
for _, reqCommodity := range req.Commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.IMEI == dbCommodity.IMEI {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
// 找到匹配的商品,加入匹配列表
matchingCommodities = append(matchingCommodities, reqCommodity)
@ -470,7 +496,7 @@ func (m *InventoryAllotListReq) List() (*InventoryAllotListResp, error) {
return resp, nil
}
// AuditAllotInventory 审核产品入库 state1-审核2-取消审核
// AuditAllotInventory 审核库存调拨入库 state1-审核2-取消审核
func AuditAllotInventory(req *InventoryAllotAuditReq, sysUser *SysUser) error {
// 查询订单信息
var inventoryAllotOrder ErpInventoryAllotOrder
@ -732,9 +758,11 @@ func DeliverAllotInventory(req *InventoryAllotDeliverReq) error {
return errors.New("订单不是待发货状态")
}
nowTime := time.Now()
inventoryAllotOrder.LogisticsNumber = req.LogisticsNumber
inventoryAllotOrder.Remark = req.Remark
inventoryAllotOrder.State = ErpInventoryAllotOrderWaitReceive
inventoryAllotOrder.DeliverTime = &nowTime
err = orm.Eloquent.Model(&ErpInventoryAllotOrder{}).Where("id = ?", inventoryAllotOrder.ID).
Updates(inventoryAllotOrder).Error
@ -842,7 +870,9 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq) error {
}
// 更新调拨订单的状态为:已完成
nowTime := time.Now()
inventoryAllotOrder.State = ErpInventoryAllotOrderFinished
inventoryAllotOrder.ReceiveTime = &nowTime
err := begin.Model(&ErpInventoryAllotOrder{}).Where("id = ?", inventoryAllotOrder.ID).
Updates(inventoryAllotOrder).Error
if err != nil {

View File

@ -1,6 +1,23 @@
package models
import "time"
import (
"errors"
"fmt"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"gorm.io/gorm"
"math/rand"
"time"
)
const (
ErpInventoryChangeOrderUnAudit = 1 // 库存变动-待审核
ErpInventoryChangeOrderFinished = 2 // 库存变动-已完成
AddChangeOrder = "add" // 库存增加
ReduceChangeOrder = "reduce" // 库存减少
)
// ErpInventoryChangeOrder 库存变动订单表
type ErpInventoryChangeOrder struct {
@ -46,6 +63,7 @@ type InventoryChangeAddReq struct {
StoreName string `json:"store_name" binding:"required"` // 门店名称
HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id
HandlerName string `json:"handler_name" binding:"required"` // 经手人名称
ChangeType string `json:"change_type" binding:"required"` // 库存变动类型add-库存增加 reduce-库存减少
Commodities []ErpInventoryChangeCommodity `json:"commodities" binding:"required"` // 库存变动商品信息
}
@ -91,3 +109,882 @@ type InventoryChangeListResp struct {
type InventoryChangeDetailReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
}
// newChangeInventorySn 生成库存变动订单号
func newChangeInventorySn(changeType string) string {
var prefix string
switch changeType {
case "add": // 库存增加
prefix = "kcz"
case "reduce": // 库存减少
prefix = "kcj"
}
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create NewChangeInventorySn err")
return ""
}
random := rand.Intn(9000) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_inventory_change_order "+
"WHERE serial_number='%s'", prefix+sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return prefix + sn
}
max++
}
}
// 检查新增库存变动入参信息
func checkChangeInventoryParam(req *InventoryChangeAddReq, editFlag bool) error {
if len(req.Commodities) == 0 {
return errors.New("商品信息为空")
}
if req.ChangeType != AddChangeOrder && req.ChangeType != ReduceChangeOrder {
return errors.New("库存变动类型错误")
}
noIMEICommodityMap := make(map[uint32]bool, 0)
for _, item := range req.Commodities {
// 校验数量
if item.Count <= 0 {
return fmt.Errorf("商品[%s]数量[%d]错误需大于0", item.CommodityName, item.Count)
} else {
if item.Count != 1 && item.IMEIType != NoIMEICommodity { // 串码商品数量不为1则报错
return fmt.Errorf("串码商品[%s]数量[%d]错误需为1", item.CommodityName, item.Count)
}
}
// 校验编辑订单时是否有传商品ID
if editFlag {
if item.ID == 0 {
return fmt.Errorf("商品[%s]ID为空", item.CommodityName)
}
}
// 校验串码类型
switch item.IMEIType {
case 1, 2, 3:
// 串码商品校验串码是否为空
if item.IMEIType != NoIMEICommodity && item.IMEI == "" {
return fmt.Errorf("[%s]是串码商品,其串码不能为空", item.CommodityName)
}
default:
return fmt.Errorf("商品[%s]串码类型[%d]错误", item.CommodityName, item.IMEIType)
}
// 校验非串码商品是否重复
if item.IMEIType == NoIMEICommodity {
_, ok := noIMEICommodityMap[item.CommodityId]
if !ok {
noIMEICommodityMap[item.CommodityId] = true
} else {
return fmt.Errorf("商品[%s]重复相同的非串码商品只能有1条数据", item.CommodityName)
}
}
if req.ChangeType == ReduceChangeOrder { // 库存减少
// 检查调出门店是否有对应商品,库存变动数量是否 > 商品库存数量
var stockCount int64
var err error
if item.IMEIType == NoIMEICommodity { // 非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1", item.CommodityId, req.StoreId).
Count(&stockCount).Error
} else { // 串码商品
err = orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1 AND imei = ?", item.CommodityId,
req.StoreId, item.IMEI).Count(&stockCount).Error
}
if err != nil {
return errors.New("查询商品库存失败," + err.Error())
}
if stockCount == 0 {
return fmt.Errorf("商品[%s]库存数量为0", item.CommodityName)
}
if stockCount < int64(item.Count) {
return fmt.Errorf("商品[%s]库存数量[%d]少于库存减少数量[%d]", item.CommodityName, stockCount, item.Count)
}
}
}
return nil
}
// AddInventoryChange 新增库存变动订单
func AddInventoryChange(req *InventoryChangeAddReq, sysUser *SysUser) (*ErpInventoryChangeOrder, error) {
// 检查库存变动信息
if err := checkChangeInventoryParam(req, false); err != nil {
return nil, err
}
var err error
nowTime := time.Now()
// 计算库存变动的总数量,总金额
var nTotalCount uint32
var nTotalAmount float64
for i, _ := range req.Commodities {
nTotalCount += req.Commodities[i].Count // 数量
nTotalAmount += req.Commodities[i].Amount // 金额
}
// 组合库存变动订单数据
inventoryChangeOrder := &ErpInventoryChangeOrder{
SerialNumber: newChangeInventorySn(req.ChangeType),
ChangeType: req.ChangeType,
StoreId: req.StoreId,
StoreName: req.StoreName,
HandlerId: uint32(sysUser.UserId),
HandlerName: req.HandlerName,
MakerTime: &nowTime,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpInventoryChangeOrderUnAudit,
TotalCount: nTotalCount,
TotalAmount: nTotalAmount,
}
// 创建库存变动订单
begin := orm.Eloquent.Begin()
err = begin.Create(inventoryChangeOrder).Error
if err != nil {
begin.Rollback()
logger.Error("create change order err:", logger.Field("err", err))
return nil, err
}
// 创建库存变动商品信息添加库存变动订单id
for i, _ := range req.Commodities {
req.Commodities[i].ChangeOrderId = inventoryChangeOrder.ID
err = begin.Create(&req.Commodities[i]).Error
if err != nil {
begin.Rollback()
logger.Error("create change commodity err:", logger.Field("err", err))
return nil, err
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit change commodity err:", logger.Field("err", err))
return nil, err
}
return inventoryChangeOrder, nil
}
// EditChangeInventory 编辑库存变动
func EditChangeInventory(req *InventoryChangeEditReq) (*ErpInventoryChangeOrder, error) {
// 查询订单信息
var inventoryChangeOrder ErpInventoryChangeOrder
err := orm.Eloquent.Table("erp_inventory_change_order").Where("serial_number = ?", req.SerialNumber).
Find(&inventoryChangeOrder).Error
if err != nil {
logger.Error("allot order err:", logger.Field("err", err))
return nil, err
}
// 未找到订单
if inventoryChangeOrder.ID == 0 {
return nil, fmt.Errorf("未找到该订单,请检查单据编号[%s]", req.SerialNumber)
}
if inventoryChangeOrder.State != ErpInventoryChangeOrderUnAudit { // 只有待审核的订单才能编辑
return nil, errors.New("订单不是待审核状态")
}
// 检查库存调拨信息
if err = checkChangeInventoryParam(&req.InventoryChangeAddReq, true); err != nil {
return nil, err
}
// 计算库存调拨的总数量
var nTotalCount uint32
var nTotalAmount float64
for i, _ := range req.Commodities {
nTotalCount += req.Commodities[i].Count // 数量
nTotalAmount += req.Commodities[i].Amount // 金额
}
begin := orm.Eloquent.Begin()
// 1-更新库存调拨信息
inventoryChangeOrder.ChangeType = req.ChangeType
inventoryChangeOrder.StoreId = req.StoreId
inventoryChangeOrder.StoreName = req.StoreName
inventoryChangeOrder.HandlerId = req.HandlerId
inventoryChangeOrder.HandlerName = req.HandlerName
inventoryChangeOrder.TotalCount = nTotalCount
inventoryChangeOrder.TotalAmount = nTotalAmount
err = begin.Model(&ErpInventoryChangeOrder{}).Where("id = ?", inventoryChangeOrder.ID).
Updates(inventoryChangeOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update change order err:", logger.Field("err", err))
return nil, err
}
// 2-更新库存调拨商品表
err = updateChangeCommodityData(begin, inventoryChangeOrder.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_inventory_change_commodity err:", logger.Field("err", err))
return nil, err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return nil, err
}
return &inventoryChangeOrder, nil
}
// updateChangeCommodityData 更新库存变动商品信息
func updateChangeCommodityData(gdb *gorm.DB, orderId uint32, req *InventoryChangeEditReq) error {
// 查询现有的零售订单信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?", orderId).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
var newCommodities []ErpInventoryChangeCommodity
var deletedCommodities []ErpInventoryChangeCommodity
var matchingCommodities []ErpInventoryChangeCommodity
// 找到新增的商品
for i, reqCommodity := range req.Commodities {
// 订单商品表信息添加零售订单id
req.Commodities[i].ChangeOrderId = orderId
var found bool
for _, dbCommodity := range commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
break
}
}
if !found {
newCommodities = append(newCommodities, reqCommodity)
}
}
// 找到删除的商品
for _, dbCommodity := range commodities {
var found bool
for _, reqCommodity := range req.Commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
// 找到匹配的商品,加入匹配列表
matchingCommodities = append(matchingCommodities, reqCommodity)
break
}
}
if !found {
deletedCommodities = append(deletedCommodities, dbCommodity)
}
}
// 2-更新商品订单信息-更新
for _, commodity := range matchingCommodities {
if err := gdb.Model(&ErpInventoryChangeCommodity{}).Where("id = ?", commodity.ID).Updates(commodity).Error; err != nil {
logger.Error("更新商品订单信息-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 2-更新商品订单信息-新增
if len(newCommodities) != 0 {
err = gdb.Create(&newCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
//2-更新商品订单信息-删除
if len(deletedCommodities) != 0 {
err = gdb.Delete(&deletedCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}
// List 查询采购订单列表
func (m *InventoryChangeListReq) List() (*InventoryChangeListResp, error) {
resp := &InventoryChangeListResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
qs := orm.Eloquent.Table("erp_inventory_change_order")
if m.SerialNumber != "" {
qs = qs.Where("serial_number=?", m.SerialNumber)
} else {
if m.ChangeType != "" {
qs = qs.Where("change_type=?", m.ChangeType)
}
if m.StoreId != 0 {
qs = qs.Where("store_id=?", m.StoreId)
}
if m.HandlerId != 0 {
qs = qs.Where("handler_id=?", m.HandlerId)
}
if m.State != 0 {
qs = qs.Where("state=?", m.State)
}
if m.AuditTimeStart != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("ChangeInventoryList err:", err)
return nil, err
}
qs = qs.Where("audit_time > ?", parse)
}
if m.AuditTimeEnd != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("ChangeInventoryList err:", err)
return nil, err
}
qs = qs.Where("audit_time < ?", parse)
}
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
resp.Total = int(count)
var orders []ErpInventoryChangeOrder
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("change list err:", logger.Field("err", err))
return resp, err
}
// 校验时间如果为01-01-01 08:05则赋值为空
for i, v := range orders {
if v.MakerTime != nil && v.MakerTime.IsZero() {
orders[i].MakerTime = nil
}
if v.AuditTime != nil && v.AuditTime.IsZero() {
orders[i].AuditTime = nil
}
}
resp.List = orders
return resp, nil
}
// AuditChangeInventory 审核库存变动入库 state1-审核2-取消审核
func AuditChangeInventory(req *InventoryChangeAuditReq, sysUser *SysUser) error {
// 查询订单信息
var inventoryChangeOrder ErpInventoryChangeOrder
err := orm.Eloquent.Table("erp_inventory_change_order").Where("serial_number = ?", req.SerialNumber).
Find(&inventoryChangeOrder).Error
if err != nil {
logger.Error("order err:", logger.Field("err", err))
return err
}
if inventoryChangeOrder.ID == 0 {
return errors.New("未查询到订单信息")
}
begin := orm.Eloquent.Begin()
// 判断入参state1-审核2-取消审核
orderState := 0
switch req.State {
case 1: // 1-审核:待审核状态可以审核
if inventoryChangeOrder.State == ErpInventoryChangeOrderFinished { // 订单已完成
return errors.New("订单已审核,无需再次审核")
}
orderState = ErpInventoryChangeOrderFinished
case 2: // 2-取消审核
if inventoryChangeOrder.State == ErpInventoryChangeOrderUnAudit { // 订单未审核
return errors.New("订单是未审核状态,无需取消审核")
}
orderState = ErpInventoryChangeOrderUnAudit
default:
logger.Error("order err, req.State is:", logger.Field("req.State", req.State))
return errors.New("参数有误")
}
// 更新商品的库存状态
err = changeInventoryUpdateStock(begin, inventoryChangeOrder, req.State)
if err != nil {
begin.Rollback()
logger.Error("changeInventoryUpdateStock err:", logger.Field("err", err))
return err
}
// 更新库存调拨订单表
err = begin.Table("erp_inventory_change_order").Where("id = ?", inventoryChangeOrder.ID).
Updates(map[string]interface{}{
"state": orderState,
"auditor_id": sysUser.UserId,
"audit_time": time.Now(),
"auditor_name": sysUser.NickName,
}).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_inventory_change_order err:", logger.Field("err", err))
return err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Errorf("commit err:", err)
return err
}
return nil
}
// changeInventoryUpdateStock 库存变动更新库存信息
func changeInventoryUpdateStock(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder, nState int) error {
if nState != 1 && nState != 2 {
return errors.New("无效的状态")
}
if changeOrder.ChangeType != AddChangeOrder && changeOrder.ChangeType != ReduceChangeOrder {
return errors.New("无效的库存变动类型")
}
// 根据状态和库存变动类型执行不同的逻辑
switch {
case nState == 1 && changeOrder.ChangeType == AddChangeOrder:
return handleInventoryAdd(gdb, changeOrder)
case nState == 1 && changeOrder.ChangeType == ReduceChangeOrder:
return handleInventoryReduce(gdb, changeOrder)
case nState == 2 && changeOrder.ChangeType == AddChangeOrder:
return handleCancelInventoryAdd(gdb, changeOrder)
case nState == 2 && changeOrder.ChangeType == ReduceChangeOrder:
return handleCancelInventoryReduce(gdb, changeOrder)
default:
return nil
}
}
// 库存增加逻辑
func handleInventoryAdd(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
// 遍历采购入库商品信息
var stockList []ErpStockCommodity
for _, v := range commodities {
commodityInfo, err := GetCommodity(v.CommodityId)
if err != nil {
logger.Errorf("GetCommodity err:", err)
return err
}
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND "+
"erp_commodity_id=%d", changeOrder.StoreId, v.CommodityId))
if err != nil {
logger.Errorf("exist err:", err)
return err
}
if exist {
err = gdb.Exec(fmt.Sprintf(
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d",
v.Count, changeOrder.StoreId, v.CommodityId)).Error
if err != nil {
logger.Errorf("update stock err:", err)
return err
}
} else {
stock := &ErpStock{
StoreId: changeOrder.StoreId,
StoreName: changeOrder.StoreName,
ErpCommodityId: v.CommodityId,
ErpCommodityName: v.CommodityName,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
CommoditySerialNumber: commodityInfo.SerialNumber,
IMEIType: v.IMEIType,
RetailPrice: commodityInfo.RetailPrice,
MinRetailPrice: commodityInfo.MinRetailPrice,
Count: v.Count,
DispatchCount: 0,
}
err = gdb.Create(stock).Error
if err != nil {
logger.Errorf("create stock err:", err)
return err
}
}
for i := 0; i < int(v.Count); i++ {
nowTime := time.Now()
stockCommodity := ErpStockCommodity{
StoreId: changeOrder.StoreId,
StoreName: changeOrder.StoreName,
ErpCommodityId: v.CommodityId,
ErpCommodityName: v.CommodityName,
CommoditySerialNumber: commodityInfo.SerialNumber,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: v.SupplierId,
ErpSupplierName: v.SupplierName,
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.Price),
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.Price),
State: InStock,
StorageType: CheckInventory, // 盘点入库
FirstStockTime: nowTime,
StockTime: nowTime,
Count: 1,
ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码
IMEIType: v.IMEIType,
IMEI: v.IMEI,
Remark: "",
MemberDiscount: commodityInfo.MemberDiscount,
MinRetailPrice: commodityInfo.MinRetailPrice,
RetailPrice: commodityInfo.RetailPrice,
OriginalSn: changeOrder.SerialNumber,
//StockSn: v.SerialNumber,
}
stockList = append(stockList, stockCommodity)
}
}
err = gdb.Debug().Create(&stockList).Error
if err != nil {
logger.Errorf("create stock commodity err:", err)
return err
}
return nil
}
// 库存减少逻辑
func handleInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
if len(commodities) == 0 {
return errors.New("未查询到商品信息")
}
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?",
commodities[i].IMEI).Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("handleInventoryReduce query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经销售", stockCommodityInfo.ErpCommodityName)
} else if stockCommodityInfo.State == OnSale {
return fmt.Errorf("商品[%s]在销售锁定中", stockCommodityInfo.ErpCommodityName)
}
// 更新库存商品状态为:盘点出库
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Update("state", CheckOut).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
// 更新库存数量:库存数量-1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
} else {
// 查询商品实际库存详情处剩余有效数,不包含已出库的数量
var nCount int64
err = orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodities[i].CommodityId,
changeOrder.StoreId).Count(&nCount).Error
if err != nil {
return err
}
// 如果库存数量不够则报错
if uint32(nCount) < commodities[i].Count {
return fmt.Errorf("商品[%s]库存不足", commodities[i].CommodityName)
}
var stockCommodity []ErpStockCommodity
// 非串码商品可能不止1个更新库存商品状态
for j := 0; j < int(commodities[i].Count); j++ {
// 通过门店id商品id查找状态为1-在库的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and "+
"store_id = ? and state = ? and imei_type = ?", commodities[i].CommodityId, changeOrder.StoreId,
InStock, NoIMEICommodity).Order("first_stock_time DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil {
return errors.New("find no stock commodity")
}
// 找一个可用的库存商品表主键ID
rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList,
commodities[i].CommodityId, stockCommodity)
if err != nil {
return err
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Update("state", CheckOut).Error // 状态更新为:盘点出库
if err != nil {
logger.Error("handleInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId)
}
// 更新库存数量:库存数量-count
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", commodities[i].Count)}).Error
if err != nil {
logger.Error("handleInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
}
}
return nil
}
// 取消审核时库存增加逻辑
func handleCancelInventoryAdd(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
if len(commodities) == 0 {
return errors.New("未查询到商品信息")
}
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?",
commodities[i].IMEI).Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("handleCancelInventoryAdd query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经销售", stockCommodityInfo.ErpCommodityName)
} else if stockCommodityInfo.State == OnSale {
return fmt.Errorf("商品[%s]在销售锁定中", stockCommodityInfo.ErpCommodityName)
}
// 更新库存数量:库存数量-1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error
if err != nil {
logger.Error("handleCancelInventoryAdd commodities err:", logger.Field("err", err))
return err
}
} else {
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
nCount, err := GetCommodityStockByPurchaseId(changeOrder.SerialNumber,
commodities[i].CommodityId)
if err != nil {
logger.Error("handleCancelInventoryAdd GetCommodityStockByPurchaseId err:",
logger.Field("err", err))
return err
}
// 如果库存数量不够则报错
if nCount < commodities[i].Count {
return fmt.Errorf("商品[%s]库存数量不足", commodities[i].CommodityName)
}
// 更新库存数量:库存数量-count
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", commodities[i].Count)}).Error
if err != nil {
logger.Error("handleCancelInventoryAdd commodities err:", logger.Field("err", err))
return err
}
}
}
// 删除库存商品表对应的记录
err = gdb.Where("original_sn = ? and state = ?", changeOrder.SerialNumber, InStock).Delete(&ErpStockCommodity{}).Error
if err != nil {
logger.Error("delete erp_stock_commodity err:", logger.Field("err", err))
return err
}
return nil
}
// 取消审核时库存减少逻辑
func handleCancelInventoryReduce(gdb *gorm.DB, changeOrder ErpInventoryChangeOrder) error {
// 查询库存变动商品信息
var commodities []ErpInventoryChangeCommodity
err := orm.Eloquent.Table("erp_inventory_change_commodity").Where("change_order_id = ?",
changeOrder.ID).Find(&commodities).Error
if err != nil {
logger.Error("query erp_inventory_change_commodity err:", logger.Field("err", err))
return err
}
if len(commodities) == 0 {
return errors.New("未查询到商品信息")
}
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
// 更新库存数量
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?",
commodities[i].IMEI).Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("handleCancelInventoryReduce query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经销售", stockCommodityInfo.ErpCommodityName)
} else if stockCommodityInfo.State == OnSale {
return fmt.Errorf("商品[%s]在销售锁定中", stockCommodityInfo.ErpCommodityName)
}
// 更新库存商品状态:在库
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Update("state", InStock).Error
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
// 更新库存数量:库存数量+1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
} else {
var stockCommodity []ErpStockCommodity
// 非串码商品可能不止1个更新库存商品状态
for j := 0; j < int(commodities[i].Count); j++ {
// 通过门店id商品id查找状态为7-盘点出库的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and "+
"store_id = ? and state = ? and imei_type = ?", commodities[i].CommodityId, changeOrder.StoreId,
CheckOut, NoIMEICommodity).Order("first_stock_time DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil {
return errors.New("find no stock commodity")
}
// 找一个可用的库存商品表主键ID
rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList,
commodities[i].CommodityId, stockCommodity)
if err != nil {
return err
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Update("state", InStock).Error // 状态更新为:在库
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock_commodity err:",
logger.Field("err", err))
return err
}
usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId)
}
// 更新库存数量:库存数量+count
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
changeOrder.StoreId, commodities[i].CommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", commodities[i].Count)}).Error
if err != nil {
logger.Error("handleCancelInventoryReduce update erp_stock err:", logger.Field("err", err))
return err
}
}
}
return nil
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"gorm.io/gorm"
"math/rand"
"time"
@ -103,8 +104,8 @@ type ProductInventoryDetailReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
}
// NewProductInventorySn 生成产品入库订单号
func NewProductInventorySn() string {
// newProductInventorySn 生成产品入库订单号
func newProductInventorySn() string {
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
@ -115,12 +116,13 @@ func NewProductInventorySn() string {
}
random := rand.Intn(9000) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_inventory_product_order WHERE serial_number='%s'", sn))
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_inventory_product_order "+
"WHERE serial_number='%s'", "cpr"+sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
return "cpr" + sn
}
max++
@ -240,7 +242,7 @@ func AddProductInventory(req *ProductInventoryAddReq, sysUser *SysUser) (*ErpInv
// 组合产品入库订单数据
inventoryProductOrder := &ErpInventoryProductOrder{
SerialNumber: "cpr" + NewProductInventorySn(),
SerialNumber: newProductInventorySn(),
StoreId: req.StoreId,
StoreName: req.StoreName,
HandlerId: req.HandlerId,
@ -371,7 +373,7 @@ func updateProductCommodityData(gdb *gorm.DB, orderId uint32, req *ProductInvent
var found bool
for _, dbCommodity := range commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.IMEI == dbCommodity.IMEI {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
break
}
@ -385,7 +387,7 @@ func updateProductCommodityData(gdb *gorm.DB, orderId uint32, req *ProductInvent
for _, dbCommodity := range commodities {
var found bool
for _, reqCommodity := range req.Commodities {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.IMEI == dbCommodity.IMEI {
if reqCommodity.CommodityId == dbCommodity.CommodityId && reqCommodity.ID == dbCommodity.ID {
found = true
// 找到匹配的商品,加入匹配列表
matchingCommodities = append(matchingCommodities, reqCommodity)
@ -641,8 +643,8 @@ func productAuditAndUpdateStock(gdb *gorm.DB, productOrder ErpInventoryProductOr
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: v.SupplierId,
ErpSupplierName: v.SupplierName,
StaffCostPrice: uint32(v.EmployeePrice - v.Price),
WholesalePrice: uint32(v.Price),
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.Price),
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.Price),
State: InStock,
StorageType: ProductInventory, // 产品入库
FirstStockTime: nowTime,

View File

@ -6,6 +6,7 @@ import (
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"go-admin/tools/config"
"gorm.io/gorm"
"math"
@ -72,7 +73,7 @@ type ErpPurchaseCommodity struct {
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
RetailPrice uint32 `json:"retail_price"` // 指导零售价
RetailPrice float64 `json:"retail_price"` // 指导零售价
Count uint32 `json:"count"` // 计划采购数量
Price float64 `json:"price"` // 计划采购单价
Amount float64 `json:"amount"` // 计划采购金额
@ -275,7 +276,7 @@ type DemandData struct {
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
RetailPrice uint32 `json:"retail_price"` // 指导零售价
RetailPrice float64 `json:"retail_price"` // 指导零售价
LastWholesalePrice float64 `json:"last_wholesale_price"` // 最近采购价
TotalCount uint32 `json:"total_count"` // 需采购总数量
TotalAmount float64 `json:"total_amount"` // 需采购总金额
@ -463,7 +464,7 @@ type ErpPurchaseReportBySupplierResp struct {
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
Count uint32 `json:"count"` // 采购数量
Count int32 `json:"count"` // 采购数量
Amount float64 `json:"amount"` // 采购金额
RejectAmount float64 `json:"reject_amount"` // 退货金额
Difference float64 `json:"difference"` // 差额
@ -482,7 +483,7 @@ type PurchaseReportData struct {
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
Count uint32 `json:"count"` // 采购数量
Count int32 `json:"count"` // 采购数量
Amount float64 `json:"amount"` // 采购金额
RejectAmount float64 `json:"reject_amount"` // 退货金额
Difference float64 `json:"difference"` // 差额
@ -622,8 +623,16 @@ func (m *ErpPurchaseOrderListReq) List() (*ErpPurchaseOrderListResp, error) {
return resp, nil
}
// NewErpPurchaseSn 生成采购订单号
func NewErpPurchaseSn() string {
// newErpPurchaseSn 生成采购订单号
func newErpPurchaseSn(purchaseType string) string {
var prefix string
switch purchaseType {
case ErpProcureOrder: // 采购入库订单
prefix = "cgr"
case ErpRejectOrder: // 采购退货订单
prefix = "cgt"
}
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
@ -634,12 +643,13 @@ func NewErpPurchaseSn() string {
}
random := rand.Intn(9000) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE serial_number='%s'", sn))
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE "+
"serial_number='%s'", prefix+sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
return prefix + sn
}
max++
@ -823,7 +833,7 @@ func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPu
purchaseOrder := &ErpPurchaseOrder{}
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgr" + NewErpPurchaseSn(),
SerialNumber: newErpPurchaseSn(req.PurchaseType),
PurchaseType: req.PurchaseType,
StoreId: req.StoreId,
ErpSupplierId: req.ErpSupplierId,
@ -854,7 +864,7 @@ func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPu
}
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgt" + NewErpPurchaseSn(),
SerialNumber: newErpPurchaseSn(req.PurchaseType),
PurchaseType: req.PurchaseType,
StoreId: erpPurchaseOrder.StoreId,
ErpSupplierId: erpPurchaseOrder.ErpSupplierId,
@ -1235,8 +1245,8 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory,
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: purchaseOrder.ErpSupplierId,
ErpSupplierName: purchaseOrder.ErpSupplierName,
StaffCostPrice: uint32(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: uint32(v.ImplementationPrice),
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.ImplementationPrice),
State: InStock,
StorageType: PurchaseInventory, // 采购入库
FirstStockTime: nowTime,
@ -2781,7 +2791,7 @@ func GetTotalsAndAveragesByCommodityID(commodityID, orderID uint32) (Result, err
}
// UpdateRetailPrice 更新指导零售价
func UpdateRetailPrice(begin *gorm.DB, commodityId, retailPrice uint32) error {
func UpdateRetailPrice(begin *gorm.DB, commodityId uint32, retailPrice float64) error {
// 更新商品信息表
err := begin.Table("erp_commodity").Where("id=?", commodityId).
Updates(map[string]interface{}{
@ -4446,8 +4456,20 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
"erp_purchase_order.erp_supplier_name, " +
"erp_purchase_inventory.erp_commodity_id, erp_purchase_inventory.erp_commodity_name, " +
"erp_purchase_inventory.erp_category_id, erp_purchase_inventory.erp_category_name, " +
"SUM(erp_purchase_inventory.count) AS total_count, " +
"SUM(erp_purchase_inventory.amount) AS total_amount").
"SUM(erp_purchase_inventory.count) AS count, " +
"SUM(erp_purchase_inventory.amount) AS amount").
Joins("JOIN erp_purchase_order ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
Group("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.erp_commodity_id, " +
"erp_purchase_inventory.erp_commodity_name, erp_purchase_inventory.erp_category_id")
countQuery := orm.Eloquent.Model(&ErpPurchaseInventory{}).
Select("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.purchase_type, " +
"erp_purchase_order.store_id, erp_purchase_order.store_name, erp_purchase_order.erp_supplier_id, " +
"erp_purchase_order.erp_supplier_name, " +
"erp_purchase_inventory.erp_commodity_id, erp_purchase_inventory.erp_commodity_name, " +
"erp_purchase_inventory.erp_category_id, erp_purchase_inventory.erp_category_name, " +
"SUM(erp_purchase_inventory.count) AS count, " +
"SUM(erp_purchase_inventory.amount) AS amount").
Joins("JOIN erp_purchase_order ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
Group("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.erp_commodity_id, " +
"erp_purchase_inventory.erp_commodity_name, erp_purchase_inventory.erp_category_id")
@ -4455,13 +4477,16 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
// 根据请求参数过滤数据
if req.PurchaseType != "" {
query = query.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType)
countQuery = countQuery.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType)
}
if len(req.ErpCommodityName) > 0 {
query = query.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
countQuery = countQuery.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
}
if len(req.ErpCategoryID) > 0 {
query = query.Where("erp_purchase_inventory.erp_category_id IN (?)", req.ErpCategoryID)
countQuery = countQuery.Where("erp_purchase_inventory.erp_category_id IN (?)", req.ErpCategoryID)
}
if req.StartTime != "" { // 入/出库开始时间
@ -4471,6 +4496,7 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
return nil, err
}
query = query.Where("erp_purchase_inventory.created_at >= ?", parse)
countQuery = countQuery.Where("erp_purchase_inventory.created_at >= ?", parse)
}
if req.EndTime != "" { // 入/出库结束时间
@ -4480,15 +4506,17 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
return nil, err
}
query = query.Where("erp_purchase_inventory.created_at <= ?", parse)
countQuery = countQuery.Where("erp_purchase_inventory.created_at <= ?", parse)
}
if len(req.StoreList) > 0 {
query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
}
// 获取总数
//获取总数
var total int64
query.Count(&total)
countQuery.Count(&total)
resp.Total = int(total)
// 分页查询
@ -4536,9 +4564,24 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
}
if data.PurchaseType == "reject" {
data.Amount = -data.Amount
data.RejectAmount = -data.RejectAmount
data.Difference = data.Amount + data.RejectAmount
// 查询退货商品的采购金额
var oldOrderInfo ErpPurchaseOrder
err = orm.Eloquent.Where("serial_number = ?", po.SerialNumber).First(&oldOrderInfo).Error
if err != nil {
return nil, err
}
// 查找对应的采购入库记录
var resultInfo Result
resultInfo, err = GetTotalsAndAveragesByCommodityID(respItem.ErpCommodityId, oldOrderInfo.ID)
if err != nil {
return nil, err
}
data.RejectAmount = -data.Amount
data.Amount = -resultInfo.AvgImplementationPrice * float64(data.Count)
data.Difference = data.RejectAmount - data.Amount
data.Count = -data.Count
}
esData = append(esData, data)
@ -4550,7 +4593,10 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
// 补充关联的供应商和店铺信息
for i := range resp.List {
var purchaseOrderInfo ErpPurchaseOrder
orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrderInfo)
err = orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrderInfo).Error
if err != nil {
return nil, err
}
resp.List[i].StoreId = purchaseOrderInfo.StoreId
resp.List[i].StoreName = purchaseOrderInfo.StoreName
@ -4558,9 +4604,24 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
resp.List[i].ErpSupplierName = purchaseOrderInfo.ErpSupplierName
if resp.List[i].PurchaseType == "reject" {
resp.List[i].Amount = -resp.List[i].Amount
resp.List[i].RejectAmount = -resp.List[i].RejectAmount
resp.List[i].Difference = resp.List[i].Amount + resp.List[i].RejectAmount
// 查询退货商品的采购金额
var oldOrderInfo ErpPurchaseOrder
err = orm.Eloquent.Where("serial_number = ?", purchaseOrderInfo.SerialNumber).First(&oldOrderInfo).Error
if err != nil {
return nil, err
}
// 查找对应的采购入库记录
var resultInfo Result
resultInfo, err = GetTotalsAndAveragesByCommodityID(resp.List[i].ErpCommodityId, oldOrderInfo.ID)
if err != nil {
return nil, err
}
resp.List[i].RejectAmount = -resp.List[i].Amount
resp.List[i].Amount = -resultInfo.AvgImplementationPrice * float64(resp.List[i].Count)
resp.List[i].Difference = resp.List[i].RejectAmount - resp.List[i].Amount
resp.List[i].Count = -resp.List[i].Count
}
}
}
@ -4569,7 +4630,7 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor
// 统计总计数量和金额
var totalAmount float64
var totalCount uint32
var totalCount int32
var totalRejectAmount float64
var totalDifference float64
for _, item := range mergedData {
@ -4676,10 +4737,6 @@ func mergeData(esData []PurchaseReportData) []PurchaseReportData {
Difference: data.Difference,
}
if data.PurchaseType == ErpRejectOrder {
mergedMap[key].RejectAmount = mergedMap[key].Amount
mergedMap[key].Amount = 0
}
keys = append(keys, key) // 将键添加到有序的键列表中
} else {
// 如果键已存在,进行累加操作
@ -4687,11 +4744,6 @@ func mergeData(esData []PurchaseReportData) []PurchaseReportData {
mergedMap[key].Amount += data.Amount
mergedMap[key].RejectAmount += data.RejectAmount
mergedMap[key].Difference += data.Difference
if data.PurchaseType == ErpRejectOrder {
mergedMap[key].RejectAmount = mergedMap[key].Amount
mergedMap[key].Amount = 0
}
}
}
@ -4936,7 +4988,7 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR
return nil, err
}
resp.List[i].Price = -float64(price)
resp.List[i].Price = -price
resp.List[i].DifferencePrice = -resp.List[i].DifferencePrice
resp.List[i].RejectPrice = -resp.List[i].RejectPrice
@ -4960,7 +5012,7 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR
}
// 根据采购单据号查询入库采购价
func getPrice(serialNumber string) (uint32, error) {
func getPrice(serialNumber string) (float64, error) {
var stockCommodity ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("stock_sn = ?", serialNumber).
Find(&stockCommodity).Error
@ -5264,8 +5316,8 @@ func ErpRejectOrderCancelAuditUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventor
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: purchaseOrder.ErpSupplierId,
ErpSupplierName: purchaseOrder.ErpSupplierName,
StaffCostPrice: uint32(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: uint32(v.ImplementationPrice),
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.ImplementationPrice),
State: InStock,
StorageType: PurchaseInventory, // 采购入库
FirstStockTime: nowTime,

View File

@ -6054,7 +6054,7 @@ const docTemplate = `{
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"name": {
"description": "商品名称",
@ -6070,15 +6070,15 @@ const docTemplate = `{
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"staff_cost_price": {
"description": "员工成本价加价",
"type": "integer"
"type": "number"
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -6156,7 +6156,7 @@ const docTemplate = `{
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"name": {
"description": "商品名称",
@ -6172,15 +6172,15 @@ const docTemplate = `{
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"staff_cost_price": {
"description": "员工成本价加价",
"type": "integer"
"type": "number"
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -7267,7 +7267,7 @@ const docTemplate = `{
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"store_list": {
"type": "array",
@ -7567,7 +7567,7 @@ const docTemplate = `{
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"name": {
"description": "商品名称",
@ -7587,7 +7587,7 @@ const docTemplate = `{
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"serial_number": {
"description": "商品编号",
@ -7595,7 +7595,7 @@ const docTemplate = `{
},
"staff_cost_price": {
"description": "员工成本价加价加价50不是加价后的价格",
"type": "integer"
"type": "number"
},
"stock_count": {
"description": "库存数量",
@ -7603,7 +7603,7 @@ const docTemplate = `{
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -9386,7 +9386,7 @@ const docTemplate = `{
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
}
}
},
@ -10520,11 +10520,11 @@ const docTemplate = `{
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"store_id": {
"description": "门店编号",
@ -10613,7 +10613,7 @@ const docTemplate = `{
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"original_sn": {
"description": "首次入库订单编号(单据编号)",
@ -10625,14 +10625,14 @@ const docTemplate = `{
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"staff_cost_price": {
"description": "员工成本价加价加价50不是加价后的价格",
"type": "integer"
"type": "number"
},
"state": {
"description": "状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中",
"description": "状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 6-产品出库 7-盘点出库",
"type": "integer"
},
"stock_end_time": {
@ -10652,7 +10652,7 @@ const docTemplate = `{
"type": "string"
},
"storage_type": {
"description": "入库方式1-系统入库 2-采购入库 3-产品入库",
"description": "入库方式1-系统入库 2-采购入库 3-产品入库 4-盘点入库",
"type": "integer"
},
"store_id": {
@ -10665,7 +10665,7 @@ const docTemplate = `{
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -11448,6 +11448,7 @@ const docTemplate = `{
"models.InventoryChangeAddReq": {
"type": "object",
"required": [
"change_type",
"commodities",
"handler_id",
"handler_name",
@ -11455,6 +11456,10 @@ const docTemplate = `{
"store_name"
],
"properties": {
"change_type": {
"description": "库存变动类型add-库存增加 reduce-库存减少",
"type": "string"
},
"commodities": {
"description": "库存变动商品信息",
"type": "array",
@ -11524,6 +11529,7 @@ const docTemplate = `{
"models.InventoryChangeEditReq": {
"type": "object",
"required": [
"change_type",
"commodities",
"handler_id",
"handler_name",
@ -11532,6 +11538,10 @@ const docTemplate = `{
"store_name"
],
"properties": {
"change_type": {
"description": "库存变动类型add-库存增加 reduce-库存减少",
"type": "string"
},
"commodities": {
"description": "库存变动商品信息",
"type": "array",

View File

@ -6043,7 +6043,7 @@
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"name": {
"description": "商品名称",
@ -6059,15 +6059,15 @@
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"staff_cost_price": {
"description": "员工成本价加价",
"type": "integer"
"type": "number"
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -6145,7 +6145,7 @@
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"name": {
"description": "商品名称",
@ -6161,15 +6161,15 @@
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"staff_cost_price": {
"description": "员工成本价加价",
"type": "integer"
"type": "number"
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -7256,7 +7256,7 @@
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"store_list": {
"type": "array",
@ -7556,7 +7556,7 @@
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"name": {
"description": "商品名称",
@ -7576,7 +7576,7 @@
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"serial_number": {
"description": "商品编号",
@ -7584,7 +7584,7 @@
},
"staff_cost_price": {
"description": "员工成本价加价加价50不是加价后的价格",
"type": "integer"
"type": "number"
},
"stock_count": {
"description": "库存数量",
@ -7592,7 +7592,7 @@
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -9375,7 +9375,7 @@
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
}
}
},
@ -10509,11 +10509,11 @@
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"store_id": {
"description": "门店编号",
@ -10602,7 +10602,7 @@
},
"min_retail_price": {
"description": "最低零售价",
"type": "integer"
"type": "number"
},
"original_sn": {
"description": "首次入库订单编号(单据编号)",
@ -10614,14 +10614,14 @@
},
"retail_price": {
"description": "指导零售价",
"type": "integer"
"type": "number"
},
"staff_cost_price": {
"description": "员工成本价加价加价50不是加价后的价格",
"type": "integer"
"type": "number"
},
"state": {
"description": "状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中",
"description": "状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 6-产品出库 7-盘点出库",
"type": "integer"
},
"stock_end_time": {
@ -10641,7 +10641,7 @@
"type": "string"
},
"storage_type": {
"description": "入库方式1-系统入库 2-采购入库 3-产品入库",
"description": "入库方式1-系统入库 2-采购入库 3-产品入库 4-盘点入库",
"type": "integer"
},
"store_id": {
@ -10654,7 +10654,7 @@
},
"wholesale_price": {
"description": "指导采购价",
"type": "integer"
"type": "number"
}
}
},
@ -11437,6 +11437,7 @@
"models.InventoryChangeAddReq": {
"type": "object",
"required": [
"change_type",
"commodities",
"handler_id",
"handler_name",
@ -11444,6 +11445,10 @@
"store_name"
],
"properties": {
"change_type": {
"description": "库存变动类型add-库存增加 reduce-库存减少",
"type": "string"
},
"commodities": {
"description": "库存变动商品信息",
"type": "array",
@ -11513,6 +11518,7 @@
"models.InventoryChangeEditReq": {
"type": "object",
"required": [
"change_type",
"commodities",
"handler_id",
"handler_name",
@ -11521,6 +11527,10 @@
"store_name"
],
"properties": {
"change_type": {
"description": "库存变动类型add-库存增加 reduce-库存减少",
"type": "string"
},
"commodities": {
"description": "库存变动商品信息",
"type": "array",

View File

@ -131,7 +131,7 @@ definitions:
type: number
min_retail_price:
description: 最低零售价
type: integer
type: number
name:
description: 商品名称
type: string
@ -143,13 +143,13 @@ definitions:
type: string
retail_price:
description: 指导零售价
type: integer
type: number
staff_cost_price:
description: 员工成本价加价
type: integer
type: number
wholesale_price:
description: 指导采购价
type: integer
type: number
required:
- erp_category_id
- erp_supplier_id
@ -204,7 +204,7 @@ definitions:
type: number
min_retail_price:
description: 最低零售价
type: integer
type: number
name:
description: 商品名称
type: string
@ -216,13 +216,13 @@ definitions:
type: string
retail_price:
description: 指导零售价
type: integer
type: number
staff_cost_price:
description: 员工成本价加价
type: integer
type: number
wholesale_price:
description: 指导采购价
type: integer
type: number
required:
- erp_category_id
- erp_supplier_id
@ -1021,7 +1021,7 @@ definitions:
type: string
retail_price:
description: 指导零售价
type: integer
type: number
store_list:
items:
properties:
@ -1237,7 +1237,7 @@ definitions:
type: number
min_retail_price:
description: 最低零售价
type: integer
type: number
name:
description: 商品名称
type: string
@ -1252,19 +1252,19 @@ definitions:
type: string
retail_price:
description: 指导零售价
type: integer
type: number
serial_number:
description: 商品编号
type: string
staff_cost_price:
description: 员工成本价加价加价50不是加价后的价格
type: integer
type: number
stock_count:
description: 库存数量
type: integer
wholesale_price:
description: 指导采购价
type: integer
type: number
type: object
models.ErpCommodityListReq:
properties:
@ -2568,7 +2568,7 @@ definitions:
type: string
retail_price:
description: 指导零售价
type: integer
type: number
type: object
models.ErpPurchaseCommodityData:
properties:
@ -3396,10 +3396,10 @@ definitions:
type: integer
min_retail_price:
description: 最低零售价
type: integer
type: number
retail_price:
description: 指导零售价
type: integer
type: number
store_id:
description: 门店编号
type: integer
@ -3465,7 +3465,7 @@ definitions:
type: number
min_retail_price:
description: 最低零售价
type: integer
type: number
original_sn:
description: 首次入库订单编号(单据编号)
type: string
@ -3474,12 +3474,12 @@ definitions:
type: string
retail_price:
description: 指导零售价
type: integer
type: number
staff_cost_price:
description: 员工成本价加价加价50不是加价后的价格
type: integer
type: number
state:
description: 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中
description: 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 6-产品出库 7-盘点出库
type: integer
stock_end_time:
description: 最近入库结束时间
@ -3494,7 +3494,7 @@ definitions:
description: 最近入库时间
type: string
storage_type:
description: 入库方式1-系统入库 2-采购入库 3-产品入库
description: 入库方式1-系统入库 2-采购入库 3-产品入库 4-盘点入库
type: integer
store_id:
description: 门店id
@ -3504,7 +3504,7 @@ definitions:
type: string
wholesale_price:
description: 指导采购价
type: integer
type: number
type: object
models.ErpStockCommodityListReq:
properties:
@ -4069,6 +4069,9 @@ definitions:
type: object
models.InventoryChangeAddReq:
properties:
change_type:
description: 库存变动类型add-库存增加 reduce-库存减少
type: string
commodities:
description: 库存变动商品信息
items:
@ -4087,6 +4090,7 @@ definitions:
description: 门店名称
type: string
required:
- change_type
- commodities
- handler_id
- handler_name
@ -4123,6 +4127,9 @@ definitions:
type: object
models.InventoryChangeEditReq:
properties:
change_type:
description: 库存变动类型add-库存增加 reduce-库存减少
type: string
commodities:
description: 库存变动商品信息
items:
@ -4144,6 +4151,7 @@ definitions:
description: 门店名称
type: string
required:
- change_type
- commodities
- handler_id
- handler_name