diff --git a/app/admin/apis/purchasemanage/purchase_change.go b/app/admin/apis/purchasemanage/purchase_change.go new file mode 100644 index 0000000..bb3802c --- /dev/null +++ b/app/admin/apis/purchasemanage/purchase_change.go @@ -0,0 +1,363 @@ +package purchasemanage + +import ( + "errors" + "github.com/gin-gonic/gin" + model "go-admin/app/admin/models" + orm "go-admin/common/global" + "go-admin/logger" + "go-admin/tools" + "go-admin/tools/app" + "net/http" + "time" +) + +// ErpPurchaseChangeCreate 采购换机-新增 +// @Summary 采购换机-新增 +// @Tags 采购换机, V1.4.5 +// @Produce json +// @Accept json +// @Param request body models.ErpPurchaseChangeCreateReq true "采购换机-新增模型" +// @Success 200 {object} models.ErpPurchaseChangeOrder +// @Router /api/v1/erp_purchase/change/create [post] +func ErpPurchaseChangeCreate(c *gin.Context) { + req := new(model.ErpPurchaseChangeCreateReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误"+err.Error()) + return + } + sysUser, err := model.GetSysUserByCtx(c) + if err != nil { + logger.Error("sys user err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + // 检验参数 + err = model.CheckCreateErpPurchaseChangeOrderParam(req) + if err != nil { + logger.Error("CheckCreateErpPurchaseOrderParam err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, err.Error()) + return + } + + if len(req.Commodities) == 0 { + logger.Error("erp purchase change commodities is nil") + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + // 校验入参门店是否包含在用户所有门店中,是否过期 + if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { + if !model.CheckUserStore(req.StoreId, sysUser) { + app.Error(c, http.StatusInternalServerError, errors.New("操作失败:您没有该门店权限"), "操作失败:您没有该门店权限") + return + } + } + + purchaseOrder, err := model.CreateErpPurchaseChangeOrder(req, sysUser) + if err != nil { + logger.Error("CreateErpPurchaseOrder err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "新增失败:"+err.Error()) + return + } + + purchaseOrder.Commodities = req.Commodities + + app.OK(c, purchaseOrder, "") + return +} + +// ErpPurchaseChangeEdit 采购换机-编辑 +// @Summary 采购换机-编辑 +// @Tags 采购换机, V1.4.5 +// @Produce json +// @Accept json +// @Param request body models.ErpPurchaseChangeEditReq true "采购换机-编辑模型" +// @Success 200 {object} models.ErpPurchaseChangeEditResp +// @Router /api/v1/erp_purchase/change/edit [post] +func ErpPurchaseChangeEdit(c *gin.Context) { + req := new(model.ErpPurchaseChangeEditReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误"+err.Error()) + return + } + + sysUser, err := model.GetSysUserByCtx(c) + if err != nil { + logger.Error("sys user err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + // 检验参数 + err = model.CheckEditErpPurchaseChangeOrderParam(req) + if err != nil { + logger.Error("CheckEditErpPurchaseChangeOrderParam err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, err.Error()) + return + } + + if len(req.Commodities) == 0 { + logger.Error("erp purchase change commodities is nil") + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + // 校验入参门店是否包含在用户所有门店中,是否过期 + if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { + if !model.CheckUserStore(req.StoreId, sysUser) { + app.Error(c, http.StatusInternalServerError, errors.New("操作失败:您没有该门店权限"), "操作失败:您没有该门店权限") + return + } + } + + // 更新订单信息 + purchaseOrder, err := model.EditErpPurchaseChangeOrder(req, sysUser) + if err != nil { + logger.Error("EditErpPurchaseChangeOrder err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "编辑失败:"+err.Error()) + return + } + + purchaseOrder.Commodities = req.Commodities + app.OK(c, purchaseOrder, "") + return +} + +// ErpPurchaseChangeList 采购换机列表 +// @Summary 采购换机列表 +// @Tags 采购换机, V1.4.5 +// @Produce json +// @Accept json +// @Param request body models.ErpPurchaseChangeOrderListReq true "采购换机列表模型" +// @Success 200 {object} models.ErpPurchaseChangeListResp +// @Router /api/v1/erp_purchase/change/list [post] +func ErpPurchaseChangeList(c *gin.Context) { + req := &model.ErpPurchaseChangeOrderListReq{} + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") + return + } + + resp, err := req.List(c) + if err != nil { + logger.Error("ErpPurchaseChangeList err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "获取失败"+err.Error()) + return + } + + app.OK(c, resp, "") + return +} + +// ErpPurchaseChangeDelete 采购换机-删除 +// @Summary 采购换机-删除 +// @Tags 采购换机, V1.4.5 +// @Produce json +// @Accept json +// @Param request body models.ErpPurchaseChangeDeleteReq true "采购换机-删除模型" +// @Success 200 {object} app.Response +// @Router /api/v1/erp_purchase/change/delete [post] +func ErpPurchaseChangeDelete(c *gin.Context) { + var req = new(model.ErpPurchaseChangeDeleteReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) + return + } + + err := tools.Validate(req) //必填参数校验 + if err != nil { + app.Error(c, http.StatusBadRequest, err, err.Error()) + return + } + + sysUser, err := model.GetSysUserByCtx(c) + if err != nil { + logger.Error("sys user err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + var erpPurchaseChangeOrder model.ErpPurchaseChangeOrder + err = orm.Eloquent.Table("erp_purchase_change_order").Where("serial_number = ?", req.SerialNumber).Find(&erpPurchaseChangeOrder).Error + if err != nil { + logger.Error("order err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "删除失败:"+err.Error()) + return + } + + // 校验入参门店是否包含在用户所有门店中,是否过期 + if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { + if !model.CheckUserStore(erpPurchaseChangeOrder.StoreId, sysUser) { + app.Error(c, http.StatusInternalServerError, errors.New("操作失败:您没有该门店权限"), "操作失败:您没有该门店权限") + return + } + } + + if erpPurchaseChangeOrder.SerialNumber == "" { + logger.Error("order is null") + app.Error(c, http.StatusInternalServerError, err, "删除失败:订单不存在") + return + } + + // 仅待审核订单可删除 + if erpPurchaseChangeOrder.State != model.ErpPurchaseChangeOrderUnAudit { + logger.Error("order err, erpPurchaseChangeOrder.State is:", logger.Field("erpPurchaseChangeOrder.State", erpPurchaseChangeOrder.State)) + app.Error(c, http.StatusInternalServerError, err, "删除失败:仅待审核订单可删除") + return + } + + begin := orm.Eloquent.Begin() + // 1-删除采购订单表 + err = begin.Delete(erpPurchaseChangeOrder).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 []model.ErpPurchaseChangeCommodity + err = orm.Eloquent.Table("erp_purchase_change_commodity").Where("change_order_id = ?", erpPurchaseChangeOrder.ID).Find(&commodities).Error + if err != nil { + logger.Error("query erp_purchase_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 +} + +// ErpPurchaseChangeAudit 采购换机-审核 +// @Summary 采购换机-审核 +// @Tags 采购换机, V1.4.5 +// @Produce json +// @Accept json +// @Param request body models.ErpPurchaseChangeAuditReq true "采购换机-审核模型" +// @Success 200 {object} app.Response +// @Router /api/v1/erp_purchase/change/audit [post] +func ErpPurchaseChangeAudit(c *gin.Context) { + var req = new(model.ErpPurchaseChangeAuditReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) + return + } + + err := tools.Validate(req) //必填参数校验 + if err != nil { + app.Error(c, http.StatusBadRequest, err, err.Error()) + return + } + + sysUser, err := model.GetSysUserByCtx(c) + if err != nil { + logger.Error("sys user err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + var erpPurchaseChangeOrder model.ErpPurchaseChangeOrder + err = orm.Eloquent.Table("erp_purchase_change_order").Where("serial_number = ?", req.SerialNumber). + Find(&erpPurchaseChangeOrder).Error + if err != nil { + logger.Error("order err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "审核失败:"+err.Error()) + return + } + + // 校验入参门店是否包含在用户所有门店中,是否过期 + if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { + if !model.CheckUserStore(erpPurchaseChangeOrder.StoreId, sysUser) { + app.Error(c, http.StatusInternalServerError, errors.New("操作失败:您没有该门店权限"), + "操作失败:您没有该门店权限") + return + } + } + + begin := orm.Eloquent.Begin() + // 判断入参state:1-审核,2-取消审核 + orderState := 0 + switch req.State { + case 1: // 1-审核:待审核状态可以审核 + if erpPurchaseChangeOrder.State == model.ErpPurchaseChangeOrderUnAudit { + orderState = model.ErpPurchaseChangeOrderFinished + } else { + app.OK(c, nil, "订单已审核") + return + } + case 2: // 2-取消审核:取消后对应的退库或入库 + if erpPurchaseChangeOrder.State == model.ErpPurchaseChangeOrderUnAudit { + app.OK(c, nil, "订单已取消审核") + return + } + if model.IsMonthEndClosed(*erpPurchaseChangeOrder.AuditTime) { + app.Error(c, http.StatusInternalServerError, errors.New("反审核失败,财务已月结"), + "反审核失败,财务已月结") + return + } + + orderState = model.ErpPurchaseChangeOrderUnAudit + default: + logger.Error("order err, req.State is:", logger.Field("req.State", req.State)) + app.Error(c, http.StatusInternalServerError, err, "审核失败:参数有误") + return + } + + // 更新库存信息 + // 审核:旧机器出库、新机器入库 + // 反审核:旧机器入库、新机器出库 + err = model.AuditChangeOrder(begin, erpPurchaseChangeOrder, orderState) + if err != nil { + begin.Rollback() + app.Error(c, http.StatusInternalServerError, err, "审核失败:"+err.Error()) + return + } + + err = begin.Table("erp_purchase_change_order").Where("id = ?", erpPurchaseChangeOrder.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_purchase_change_order err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "审核失败:"+err.Error()) + return + } + + err = begin.Commit().Error + if err != nil { + begin.Rollback() + logger.Errorf("commit err:", err) + app.Error(c, http.StatusInternalServerError, err, "审核失败") + return + } + + app.OK(c, nil, "操作成功") + return +} diff --git a/app/admin/models/commodity.go b/app/admin/models/commodity.go index 36b1a45..ee5e4c8 100644 --- a/app/admin/models/commodity.go +++ b/app/admin/models/commodity.go @@ -37,6 +37,7 @@ const ( CheckOut = 6 // 盘点出库 OnSale = 7 // 销售锁定中 PurchaseCancel = 8 // 采购订单反审核 + PurchaseChange = 9 // 采购换机 ) // ErpStock 库存列表 diff --git a/app/admin/models/purchase.go b/app/admin/models/purchase.go index 66cc307..e1c8fda 100644 --- a/app/admin/models/purchase.go +++ b/app/admin/models/purchase.go @@ -34,6 +34,9 @@ const ( ErpDemandStateWait = 1 // 待采购 ErpDemandStateFinish = 2 // 完成采购 + + ErpPurchaseChangeOrderUnAudit = 1 // 采购换机-待审核 + ErpPurchaseChangeOrderFinished = 2 // 采购换机-已完成 ) // ErpPurchaseOrder 采购订单表 diff --git a/app/admin/models/purchase_change.go b/app/admin/models/purchase_change.go new file mode 100644 index 0000000..06f038b --- /dev/null +++ b/app/admin/models/purchase_change.go @@ -0,0 +1,582 @@ +package models + +import ( + "errors" + "fmt" + "github.com/gin-gonic/gin" + orm "go-admin/common/global" + "go-admin/logger" + "go-admin/tools" + "gorm.io/gorm" + "math/rand" + "time" +) + +// ErpPurchaseChangeOrder 采购换机订单表 +type ErpPurchaseChangeOrder struct { + Model + SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号 + StoreId uint32 `json:"store_id" gorm:"index"` // 门店id + StoreName string `json:"store_name"` // 门店名称 + ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id + ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称 + MakerTime *time.Time `json:"maker_time"` // 制单时间 + MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id + MakerName string `json:"maker_name"` // 制单人名称 + AuditTime *time.Time `json:"audit_time"` // 审核时间 + AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id + AuditorName string `json:"auditor_name"` // 审核人名称 + State uint32 `json:"state"` // 1-待审核 2-已完成 + Remark string `json:"remark"` // 备注 + Commodities []ErpPurchaseChangeCommodity `json:"commodities" gorm:"-"` // 采购换机商品信息 +} + +// ErpPurchaseChangeCommodity 采购换机订单商品表 +type ErpPurchaseChangeCommodity struct { + Model + ChangeOrderId uint32 `json:"change_order_id" gorm:"index"` // 采购换机订单id + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 + IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 + OriginIMEI string `json:"origin_imei"` // 原机身串码 + NewIMEI string `json:"new_imei"` // 新机身串码 + Count uint32 `json:"count"` // 数量 + OriginColor string `json:"origin_color"` // 原机身颜色 + NewColor string `json:"new_color"` // 新机身颜色 + Remark string `json:"remark"` // 备注 +} + +// ErpPurchaseChangeCreateReq 新建采购换机订单入参 +type ErpPurchaseChangeCreateReq struct { + StoreId uint32 `json:"store_id"` // 门店id:入库必传 + ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id:入库必传 + Remark string `json:"remark"` // 备注 + Commodities []ErpPurchaseChangeCommodity `json:"commodities" binding:"required"` // 采购换机商品信息 +} + +// ErpPurchaseChangeEditReq 编辑采购换机订单入参 +type ErpPurchaseChangeEditReq struct { + ChangeOrderId uint32 `json:"change_order_id" gorm:"index"` // 采购换机订单id + StoreId uint32 `json:"store_id"` // 门店id:入库必传 + ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id:入库必传 + Remark string `json:"remark"` // 备注 + Commodities []ErpPurchaseChangeCommodity `json:"Commodities" binding:"required"` // 采购商品信息 +} + +// ErpPurchaseChangeOrderListReq 查询采购换机订单列表入参 +type ErpPurchaseChangeOrderListReq struct { + SerialNumber string `json:"serial_number"` // 单据编号 + StoreId uint32 `json:"store_id"` // 门店id + ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id + AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 + AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 + State []uint32 `json:"state"` // 状态:1-待审核 2-已完成 3-已终止 + HandlerId uint32 `json:"handler_id"` // 经手人id + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 页面条数 +} + +// ErpPurchaseChangeOrderListResp 查询采购换机订单列表出参 +type ErpPurchaseChangeOrderListResp struct { + List []ErpPurchaseChangeOrder `json:"list"` + Total int `json:"total"` // 总条数 + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 页面条数 +} + +// ErpPurchaseChangeDeleteReq 删除采购换机订单入参 +type ErpPurchaseChangeDeleteReq struct { + SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 +} + +// ErpPurchaseChangeAuditReq 审核采购换机订单入参 +type ErpPurchaseChangeAuditReq struct { + SerialNumber string `json:"serial_number" binding:"required"` // 单据编号 + State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核 +} + +// newErpPurchaseChangeSn 生成采购换机订单号 +func newErpPurchaseChangeSn() string { + var prefix string + prefix = "cgh" + + nowTime := time.Now() + rand.Seed(nowTime.UnixNano()) + max := 1 + for { + if max > 5 { + logger.Error("create sn err") + return "" + } + random := rand.Intn(9000) + 1000 + sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random) + exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_change_order WHERE "+ + "serial_number='%s'", prefix+sn)) + if err != nil { + logger.Error("exist sn err") + } + if !exist { + return prefix + sn + } + + max++ + } +} + +// IdInit 添加商户和供应商信息 +func (m *ErpPurchaseChangeOrder) IdInit() error { + if m.StoreId != 0 { + store, err := GetStore(m.StoreId) + if err != nil { + logger.Error("get store err:", logger.Field("err", err)) + return err + } + m.StoreName = store.Name + } + + if m.ErpSupplierId != 0 { + supplier, err := GetErpSupplier(m.ErpSupplierId) + if err != nil { + logger.Error("get supplier err:", logger.Field("err", err)) + return err + } + m.ErpSupplierName = supplier.Name + } + + return nil +} + +// CheckCreateErpPurchaseChangeOrderParam 新增采购换机订单-检查参数 +func CheckCreateErpPurchaseChangeOrderParam(req *ErpPurchaseChangeCreateReq) error { + if req.StoreId == 0 { + return errors.New("操作失败:门店id为空") + } + if req.ErpSupplierId == 0 { + return errors.New("操作失败:供应商id为空") + } + for _, item := range req.Commodities { + if item.Count <= 0 { + return errors.New("操作失败:采购换机数量需大于0") + } + + // 判断是否是串码商品,非串码商品不支持 + if item.IMEIType == 1 { + return errors.New("操作失败:非串码商品不支持") + } + + var imeiStockCommodity ErpStockCommodity + err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", + item.OriginIMEI, InStock).Find(&imeiStockCommodity).Error + if err != nil { + return err + } + + if imeiStockCommodity.ID == 0 { + return errors.New("商品" + "[" + item.OriginIMEI + "]不在库") + } + + if imeiStockCommodity.StoreId != req.StoreId { + return errors.New(item.OriginIMEI + "商品非所选门店库存,请检查") + } + + // 判断新商品串码是否已录入或者使用过 + var newImeiStockCommodity ErpStockCommodity + err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", + item.NewIMEI).Find(&newImeiStockCommodity).Error + if err != nil { + return err + } + + if imeiStockCommodity.ID != 0 { + return errors.New("串码" + "[" + item.OriginIMEI + "]重复") + } + } + + return nil +} + +// CheckEditErpPurchaseChangeOrderParam 编辑采购换机订单-检查参数 +func CheckEditErpPurchaseChangeOrderParam(req *ErpPurchaseChangeEditReq) error { + if req.StoreId == 0 { + return errors.New("操作失败:门店id为空") + } + if req.ErpSupplierId == 0 { + return errors.New("操作失败:供应商id为空") + } + for _, item := range req.Commodities { + if item.Count <= 0 { + return errors.New("操作失败:采购换机数量需大于0") + } + + // 判断是否是串码商品,非串码商品不支持 + if item.IMEIType == 1 { + return errors.New("操作失败:非串码商品不支持") + } + + var imeiStockCommodity ErpStockCommodity + err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", + item.OriginIMEI, InStock).Find(&imeiStockCommodity).Error + if err != nil { + return err + } + + if imeiStockCommodity.ID == 0 { + return errors.New("商品" + "[" + item.OriginIMEI + "]不在库") + } + + if imeiStockCommodity.StoreId != req.StoreId { + return errors.New(item.OriginIMEI + "商品非所选门店库存,请检查") + } + + // 判断新商品串码是否已录入或者使用过 + var newImeiStockCommodity ErpStockCommodity + err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", + item.NewIMEI).Find(&newImeiStockCommodity).Error + if err != nil { + return err + } + + if imeiStockCommodity.ID != 0 { + return errors.New("串码" + "[" + item.OriginIMEI + "]重复") + } + } + + return nil +} + +// CreateErpPurchaseChangeOrder 新增采购换机订单 +func CreateErpPurchaseChangeOrder(req *ErpPurchaseChangeCreateReq, sysUser *SysUser) (*ErpPurchaseChangeOrder, error) { + var err error + nowTime := time.Now() + + purchaseOrder := &ErpPurchaseChangeOrder{} + purchaseOrder = &ErpPurchaseChangeOrder{ + SerialNumber: newErpPurchaseChangeSn(), + StoreId: req.StoreId, + ErpSupplierId: req.ErpSupplierId, + MakerTime: &nowTime, + MakerId: uint32(sysUser.UserId), + MakerName: sysUser.NickName, + State: ErpPurchaseChangeOrderUnAudit, // 1-待审核 + Remark: req.Remark, + } + err = purchaseOrder.IdInit() + if err != nil { + logger.Error("info err:", logger.Field("err", err)) + return nil, err + } + + begin := orm.Eloquent.Begin() + err = begin.Create(purchaseOrder).Error + if err != nil { + begin.Rollback() + logger.Error("create purchase order err:", logger.Field("err", err)) + return nil, err + } + + for i, _ := range req.Commodities { + req.Commodities[i].ChangeOrderId = purchaseOrder.ID + err = begin.Create(&req.Commodities[i]).Error + if err != nil { + begin.Rollback() + logger.Error("create purchase commodity err:", logger.Field("err", err)) + return nil, err + } + } + err = begin.Commit().Error + if err != nil { + begin.Rollback() + logger.Error("commit purchase commodity err:", logger.Field("err", err)) + return nil, err + } + + return purchaseOrder, nil +} + +// EditErpPurchaseChangeOrder 编辑采购订单 +func EditErpPurchaseChangeOrder(req *ErpPurchaseChangeEditReq, sysUser *SysUser) (*ErpPurchaseChangeOrder, error) { + // 查询订单信息 + var purchaseChangeOrder ErpPurchaseChangeOrder + err := orm.Eloquent.Table("erp_purchase_change_order").Where("id=?", req.ChangeOrderId).Find(&purchaseChangeOrder).Error + if err != nil { + logger.Error("purchase change order err:", logger.Field("err", err)) + return nil, err + } + + if purchaseChangeOrder.State != ErpPurchaseChangeOrderUnAudit { // 只有待审核的订单才能编辑 + return nil, errors.New("订单不是待审核状态") + } + + if req.StoreId == 0 { + return nil, errors.New("操作失败:门店id为空") + } + + begin := orm.Eloquent.Begin() + // 1-更新采购订单信息 + purchaseChangeOrder.StoreId = req.StoreId + purchaseChangeOrder.ErpSupplierId = req.ErpSupplierId + purchaseChangeOrder.MakerId = uint32(sysUser.UserId) + purchaseChangeOrder.MakerName = sysUser.NickName + purchaseChangeOrder.Remark = req.Remark + err = purchaseChangeOrder.IdInit() + if err != nil { + logger.Error("purchase change IdInit err:", logger.Field("err", err)) + return nil, err + } + + err = begin.Model(&ErpPurchaseChangeOrder{}).Where("id = ?", req.ChangeOrderId). + Omit("created_at").Save(purchaseChangeOrder).Error + if err != nil { + begin.Rollback() + logger.Error("update erp_order err:", logger.Field("err", err)) + return nil, err + } + + // 2-更新采购订单商品表 + err = updatePurchaseChangeCommodityData(begin, req.ChangeOrderId, req) + if err != nil { + begin.Rollback() + logger.Error("update erp_purchase_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 &purchaseChangeOrder, nil +} + +// updatePurchaseChangeCommodityData 更新采购订单商品信息 +func updatePurchaseChangeCommodityData(gdb *gorm.DB, orderId uint32, req *ErpPurchaseChangeEditReq) error { + // 查询现有的零售订单信息 + var commodities []ErpPurchaseChangeCommodity + err := orm.Eloquent.Table("erp_purchase_change_commodity").Where("change_order_id = ?", orderId).Find(&commodities).Error + if err != nil { + logger.Error("query erp_purchase_change_commodity err:", logger.Field("err", err)) + return err + } + + // 1-删除所有的商品信息 + if len(commodities) != 0 { + err = gdb.Delete(&commodities).Error + if err != nil { + logger.Error("更新商品订单信息-删除 error") + return errors.New("操作失败:" + err.Error()) + } + } + + for i, _ := range req.Commodities { + req.Commodities[i].ID = 0 + if req.Commodities[i].ChangeOrderId == 0 { //发现前端有时会没传,后端打补丁 + req.Commodities[i].ChangeOrderId = req.ChangeOrderId + } + } + + // 2-更新商品订单信息-新增 + if len(req.Commodities) != 0 { + err = gdb.Create(&req.Commodities).Error + if err != nil { + logger.Error("更新商品订单信息-新增 error") + return errors.New("操作失败:" + err.Error()) + } + } + + return nil +} + +// List 查询采购订单列表 +func (m *ErpPurchaseChangeOrderListReq) List(c *gin.Context) (*ErpPurchaseChangeOrderListResp, error) { + resp := &ErpPurchaseChangeOrderListResp{ + 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_purchase_change_order") + + if m.SerialNumber != "" { + qs = qs.Where("serial_number=?", m.SerialNumber) + } else { + if m.StoreId != 0 { + qs = qs.Where("store_id=?", m.StoreId) + } + // 非管理员才判断所属门店 + if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") { + sysUser, err := GetSysUserByCtx(c) + if err != nil { + return nil, errors.New("操作失败:" + err.Error()) + } + + // 返回sysUser未过期的门店id列表 + storeList := GetValidStoreIDs(sysUser.StoreData) + if len(storeList) > 0 { + if len(storeList) == 1 { + qs = qs.Where("store_id = ?", storeList[0]) + } else { + qs = qs.Where("store_id IN (?)", storeList) + } + } else { + return nil, errors.New("用户未绑定门店") + } + } + if m.ErpSupplierId != 0 { + qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId) + } + if len(m.State) > 0 { + qs = qs.Where("state IN (?)", m.State) + } + if m.AuditTimeStart != "" { + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) + if err != nil { + logger.Errorf("erpPurchaseChangeOrderList 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("erpPurchaseChangeOrderList err:", err) + return nil, err + } + //parse = parse.AddDate(0, 0, 1) + qs = qs.Where("audit_time < ?", parse) + } + if m.HandlerId != 0 { + qs = qs.Where("handler_id=?", m.HandlerId) + } + } + + 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 []ErpPurchaseChangeOrder + err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error + if err != nil && err != RecordNotFound { + logger.Error("erp commodity 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 +} + +// AuditChangeOrder 审核采购换机订单 +func AuditChangeOrder(begin *gorm.DB, req ErpPurchaseChangeOrder, state int) error { + var purchaseChangeOrder ErpPurchaseChangeOrder + err := orm.Eloquent.Table("erp_purchase_change_order").Where("id=?", req.ID).Find(&purchaseChangeOrder).Error + if err != nil { + logger.Error("check erp_purchase_change_order err:", logger.Field("err", err)) + return err + } + + if state == ErpPurchaseChangeOrderUnAudit { // 反向审核,状态更新为:待审核 + for i, _ := range req.Commodities { + if req.Commodities[i].IMEIType == 2 || req.Commodities[i].IMEIType == 3 { // 串码商品 + // 旧串码商品出库 + if req.Commodities[i].OriginIMEI == "" { + return errors.New("串码为空") + } + + var imeiStockCommodity ErpStockCommodity + err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", + req.Commodities[i].OriginIMEI, InStock).Find(&imeiStockCommodity).Error + if err != nil { + return err + } + + if imeiStockCommodity.ID == 0 { + return errors.New("商品" + "[" + req.Commodities[i].ErpCommodityName + "]库存不足") + } + + if imeiStockCommodity.StoreId != req.StoreId { + return errors.New(req.Commodities[i].ErpCommodityName + "商品非所选门店库存,请检查") + } + + err = begin.Table("erp_stock_commodity").Where("imei = ?", req.Commodities[i].OriginIMEI). + Updates(map[string]interface{}{ + "state": PurchaseChange, + "updated_at": time.Now(), + }).Error // 状态更新为"采购换机" + if err != nil { + begin.Rollback() + logger.Error("commodities err:", logger.Field("err", err)) + return err + } + + // 新串码商品入库 + newStockCommodity := imeiStockCommodity + newStockCommodity.ID = 0 + newStockCommodity.IMEI = req.Commodities[i].NewIMEI + err = begin.Create(newStockCommodity).Error + if err != nil { + begin.Rollback() + logger.Error("create purchase order err:", logger.Field("err", err)) + return err + } + } else { + return errors.New("非串码商品不支持采购换货") + } + } + } else if state == ErpPurchaseChangeOrderFinished { // 正向审核,状态更新为:已完成 + for i, _ := range req.Commodities { + // 查询新串码的库存情况 + var imeiStockCommodity ErpStockCommodity + err = orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", + req.Commodities[i].NewIMEI, InStock).Find(&imeiStockCommodity).Error + if err != nil { + return err + } + + if imeiStockCommodity.ID == 0 { + return errors.New("商品" + "[" + req.Commodities[i].NewIMEI + "]不在库") + } + + err = begin.Delete(imeiStockCommodity).Error // 删除新串码库存 + if err != nil { + begin.Rollback() + logger.Error("commodities err:", logger.Field("err", err)) + return err + } + + // 更新旧串码为在库状态 + err = begin.Table("erp_stock_commodity").Where("imei = ?", req.Commodities[i].OriginIMEI). + Updates(map[string]interface{}{ + "state": InStock, + "updated_at": time.Now(), + }).Error // 状态更新为"在库" + if err != nil { + begin.Rollback() + logger.Error("commodities err:", logger.Field("err", err)) + return err + } + } + } + + return nil +} diff --git a/app/admin/router/purchasemanage.go b/app/admin/router/purchasemanage.go index cab852b..ed39abb 100644 --- a/app/admin/router/purchasemanage.go +++ b/app/admin/router/purchasemanage.go @@ -29,4 +29,9 @@ func registerErpPurchaseManageRouter(v1 *gin.RouterGroup, authMiddleware *jwt.Gi r.POST("report/supplier", purchasemanage.ErpPurchaseReportBySupplier) // 供应商采购汇总 r.POST("report/detail", purchasemanage.ErpPurchaseReportDetail) // 采购明细 + r.POST("change/create", purchasemanage.ErpPurchaseChangeCreate) // 采购换机-新增 + r.POST("change/edit", purchasemanage.ErpPurchaseChangeEdit) // 采购换机-编辑 + r.POST("change/list", purchasemanage.ErpPurchaseChangeList) // 采购换机列表 + r.POST("change/delete", purchasemanage.ErpPurchaseChangeDelete) // 采购换机-删除 + r.POST("change/audit", purchasemanage.ErpPurchaseChangeAudit) // 采购换机-审核 }