2023-11-08 03:51:33 +00:00
package models
import (
"errors"
"fmt"
2024-04-17 09:44:43 +00:00
"github.com/gin-gonic/gin"
2023-11-08 03:51:33 +00:00
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
2024-04-17 01:37:02 +00:00
"go-admin/tools"
2023-11-23 12:38:11 +00:00
"go-admin/tools/config"
2023-11-08 03:51:33 +00:00
"golang.org/x/sync/errgroup"
"gorm.io/gorm"
2023-12-13 12:05:53 +00:00
"math/rand"
2024-05-10 01:54:37 +00:00
"sort"
2023-11-08 03:51:33 +00:00
"strconv"
"strings"
"sync"
"time"
2024-01-06 08:48:35 +00:00
"unicode/utf8"
2023-11-08 03:51:33 +00:00
)
2023-12-27 11:23:03 +00:00
const (
2024-04-17 01:37:02 +00:00
NoIMEICommodity = 1 // 非串码商品类型
SystemInventory = 1 // 系统入库
2024-03-16 08:19:12 +00:00
PurchaseInventory = 2 // 采购入库
2024-04-10 06:17:19 +00:00
ProductInventory = 3 // 产品入库
2024-04-17 01:37:02 +00:00
CheckInventory = 4 // 盘点入库
2023-12-27 11:23:03 +00:00
InStock = 1 // 在库
SoldOut = 2 // 已售
PurchaseReturn = 3 // 采购退货
2024-04-11 08:50:37 +00:00
InAllot = 4 // 调拨中(调入门店)
2024-04-29 10:10:48 +00:00
SystemOut = 5 // 系统出库
CheckOut = 6 // 盘点出库
OnSale = 7 // 销售锁定中
2023-12-27 11:23:03 +00:00
)
2023-11-23 12:38:11 +00:00
// ErpStock 库存列表
2023-11-08 03:51:33 +00:00
type ErpStock struct {
Model
2023-11-16 10:09:11 +00:00
StoreId uint32 ` json:"store_id" gorm:"index" ` // 门店编号
StoreName string ` json:"store_name" ` // 门店名称
ErpCommodityId uint32 ` json:"erp_commodity_id" gorm:"index" ` // 商品id
ErpCommodityName string ` json:"erp_commodity_name" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" gorm:"index" ` // 分类id
ErpCategoryName string ` json:"erp_category_name" ` // 分类名称
CommoditySerialNumber string ` json:"commodity_serial_number" gorm:"index" ` // 商品编码/串码
IMEIType uint32 ` json:"imei_type" ` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
2024-04-17 01:37:02 +00:00
RetailPrice float64 ` json:"retail_price" ` // 指导零售价
MinRetailPrice float64 ` json:"min_retail_price" ` // 最低零售价
2023-11-16 10:09:11 +00:00
Count uint32 ` json:"count" ` // 数量
2024-04-22 10:12:19 +00:00
DispatchCount uint32 ` json:"dispatch_count" ` // 调拨中数量(调拨中调入)
2023-11-16 10:09:11 +00:00
Commodities [ ] ErpStockCommodity ` json:"commodities" gorm:"-" `
2023-11-08 03:51:33 +00:00
}
2023-11-16 10:09:11 +00:00
// ErpStockCommodity 库存详情
2023-11-08 03:51:33 +00:00
type ErpStockCommodity struct {
Model
2023-11-16 10:09:11 +00:00
ErpStockId uint32 ` json:"erp_stock_id" gorm:"index" ` // 库存id
StoreId uint32 ` json:"store_id" gorm:"index" ` // 门店id
StoreName string ` json:"store_name" ` // 门店名称
ErpCommodityId uint32 ` json:"erp_commodity_id" gorm:"index" ` // 商品id
ErpCommodityName string ` json:"erp_commodity_name" ` // 商品名称
CommoditySerialNumber string ` json:"commodity_serial_number" gorm:"index" ` // 商品编号
ErpCategoryId uint32 ` json:"erp_category_id" gorm:"index" ` // 分类id
ErpCategoryName string ` json:"erp_category_name" ` // 分类名称
2024-01-06 08:48:35 +00:00
ErpBarcode string ` json:"erp_barcode" ` // 商品条码
2023-11-16 10:09:11 +00:00
IMEIType uint32 ` json:"imei_type" ` // 是否串码: 1-无串码 2-串码(系统生成) 3-串码(手动添加)
IMEI string ` json:"imei" ` // 商品串码
ErpSupplierId uint32 ` json:"erp_supplier_id" gorm:"index" ` // 供应商id
ErpSupplierName string ` json:"erp_supplier_name" ` // 供应商名称
StockTime time . Time ` json:"stock_time" ` // 最近入库时间
2024-04-17 01:37:02 +00:00
RetailPrice float64 ` json:"retail_price" ` // 指导零售价
MinRetailPrice float64 ` json:"min_retail_price" ` // 最低零售价
StaffCostPrice float64 ` json:"staff_cost_price" ` // 员工成本价加价( 如: 加价50, 不是加价后的价格)
WholesalePrice float64 ` json:"wholesale_price" ` // 指导采购价
2023-12-22 09:26:34 +00:00
MemberDiscount float64 ` json:"member_discount" ` // 会员优惠
2024-04-17 01:37:02 +00:00
State uint32 ` json:"state" ` // 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 6-产品出库 7-盘点出库
2023-11-16 10:09:11 +00:00
Count uint32 ` json:"count" ` // 数量
2024-04-17 01:37:02 +00:00
StorageType uint32 ` json:"storage_type" ` // 入库方式: 1-系统入库 2-采购入库 3-产品入库 4-盘点入库
2023-11-16 10:09:11 +00:00
FirstStockTime time . Time ` json:"first_stock_time" ` // 首次入库时间
2024-03-27 10:01:38 +00:00
StockSn string ` json:"stock_sn" ` // 库存订单编号(跟采购入库的入库编号关联)
2024-03-18 11:53:42 +00:00
OriginalSn string ` json:"original_sn" gorm:"index" ` // 首次入库订单编号(单据编号)
2023-11-16 10:09:11 +00:00
StockStartTime time . Time ` json:"stock_start_time" gorm:"-" ` // 最近入库开始时间
StockEndTime time . Time ` json:"stock_end_time" gorm:"-" ` // 最近入库结束时间
Age uint32 ` json:"age" gorm:"-" ` // 最近库龄
AllAge uint32 ` json:"all_age" gorm:"-" ` // 总库龄
2023-11-24 09:09:24 +00:00
Remark string ` json:"remark" ` // 备注
2024-03-27 10:01:38 +00:00
//ErpOrderCommodityId uint32 `json:"erp_order_commodity_id"` // 零售订单商品表的主键ID( 后端使用, 前端忽略)
2023-11-16 10:09:11 +00:00
//Commodity ErpCommodity `json:"commodity" gorm:"-"`
2023-11-08 03:51:33 +00:00
}
2023-11-16 10:09:11 +00:00
// ErpCommodity 商品表
2023-11-08 03:51:33 +00:00
type ErpCommodity struct {
Model
SerialNumber string ` json:"serial_number" ` // 商品编号
Number uint32 ` json:"number" ` // 商品数量
Name string ` json:"name" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" gorm:"index" ` // 商品分类id
ErpCategoryName string ` json:"erp_category_name" ` // 商品分类名称
2024-01-06 08:48:35 +00:00
ErpBarcode string ` json:"erp_barcode" ` // 商品条码
2023-11-24 09:09:24 +00:00
IsIMEI uint32 ` json:"is_imei" gorm:"-" ` // 是否串码: 1-串码类 2-非串码
2023-11-09 10:26:19 +00:00
IMEIType uint32 ` json:"imei_type" ` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
2023-11-08 03:51:33 +00:00
IMEI string ` json:"imei" ` // 串码
ErpSupplierId uint32 ` json:"erp_supplier_id" gorm:"index" ` // 主供应商id
ErpSupplierName string ` json:"erp_supplier_name" ` // 主供应商名称
2024-04-17 01:37:02 +00:00
RetailPrice float64 ` json:"retail_price" ` // 指导零售价
MinRetailPrice float64 ` json:"min_retail_price" ` // 最低零售价
StaffCostPrice float64 ` json:"staff_cost_price" ` // 员工成本价加价( 如: 加价50, 不是加价后的价格)
WholesalePrice float64 ` json:"wholesale_price" ` // 指导采购价
2023-11-08 03:51:33 +00:00
Brokerage1 float64 ` json:"brokerage_1" ` // 销售毛利提成
Brokerage2 float64 ` json:"brokerage_2" ` // 员工毛利提成
MemberDiscount float64 ` json:"member_discount" ` // 会员优惠
Origin string ` json:"origin" ` // 产地
Remark string ` json:"remark" gorm:"type:varchar(512)" ` // 备注
2024-03-27 10:01:38 +00:00
StockCount uint32 ` json:"stock_count" gorm:"-" ` // 库存数量
2023-11-08 03:51:33 +00:00
ErpCategory * ErpCategory ` json:"erp_category" gorm:"-" `
}
2023-11-23 12:38:11 +00:00
// ErpCategory 商品分类
2023-11-08 03:51:33 +00:00
type ErpCategory struct {
Model
Name string ` json:"name" ` // 名称
Priority string ` json:"priority" ` // 分类
2024-01-06 08:48:35 +00:00
Number string ` json:"number" `
2023-11-08 03:51:33 +00:00
FullNum uint32 ` json:"full_num" `
State uint32 ` json:"state" ` // 1-未使用 2-使用 3-隐藏
Level uint32 ` json:"level" ` // 分类层级
Pid uint32 ` json:"pid" gorm:"index" `
Sort uint32 ` json:"sort" `
SubCats [ ] ErpCategory ` json:"sub_cats" gorm:"-" ` // 子列表
// erp_category
}
2023-11-23 12:38:11 +00:00
// ErpSupplier 供应商
2023-11-08 03:51:33 +00:00
type ErpSupplier struct {
Model
Number string ` json:"number" gorm:"index" `
Name string ` json:"name" `
Contact string ` json:"contact" `
Tel string ` json:"tel" `
Address string ` json:"address" `
OpeningBank string ` json:"opening_bank" `
BankAccount string ` json:"bank_account" `
PaymentCycle uint32 ` json:"payment_cycle" `
TaxNumber string ` json:"tax_number" `
StoreIds string ` json:"store_ids" `
Landline string ` json:"landline" `
Email string ` json:"email" `
CompanyWebsite string ` json:"company_website" `
// erp_supplier
}
type ErpInventoryStock struct {
Model
2024-04-17 01:37:02 +00:00
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" `
2023-11-08 03:51:33 +00:00
//ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"`
//ErpSupplierName string `json:"erp_supplier_name"`
//IMEI string `json:"imei"`
//StockTime time.Time `json:"stock_time"`
//StaffCostPrice uint32 `json:"staff_cost_price"`
//WholesalePrice uint32 `json:"wholesale_price"`
// erp_inventory_stock
}
type ErpInventoryStockCommodity struct {
Model
ErpInventoryStockId uint32 ` json:"erp_inventory_stock_id" gorm:"index" `
ErpCommodityId uint32 ` json:"erp_commodity_id" gorm:"index" `
ErpCommodityName string ` json:"erp_commodity_name" `
CommoditySerialNumber string ` json:"commodity_serial_number" gorm:"index" `
2023-11-09 10:26:19 +00:00
IMEIType uint32 ` json:"imei_type" ` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
2023-11-08 03:51:33 +00:00
IMEI string ` json:"imei" `
ErpSupplierId uint32 ` json:"erp_supplier_id" gorm:"index" `
ErpSupplierName string ` json:"erp_supplier_name" `
StockTime time . Time ` json:"stock_time" `
2024-04-17 01:37:02 +00:00
RetailPrice float64 ` json:"retail_price" `
MinRetailPrice float64 ` json:"min_retail_price" `
StaffCostPrice float64 ` json:"staff_cost_price" `
WholesalePrice float64 ` json:"wholesale_price" `
2023-11-08 03:51:33 +00:00
Count uint32 ` json:"count" `
StorageType uint32 ` json:"storage_type" `
Sn string ` json:"sn" gorm:"index" `
//StoreId uint32 `json:"store_id" gorm:"index"`
//StoreName string `json:"store_name"`
//ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"`
//ErpCategoryName string `json:"erp_category_name"`
// erp_inventory_stock_commodity
}
2024-01-06 08:48:35 +00:00
// QueryCodeReq 查询商品串码或条码入参
type QueryCodeReq struct {
ScanCode string ` json:"scan_code" binding:"required" ` // 扫码枪扫码数据:串码/条码
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 页面条数
}
type QueryCodeResp struct {
List [ ] string ` json:"list" ` // 串码/条码
Total int ` json:"count" ` // 数据总条数
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 每页展示条数
}
2023-11-23 12:38:11 +00:00
// IdInit 新增/编辑商品时获取分类和供应商信息
2024-01-06 08:48:35 +00:00
func ( c * ErpCommodity ) IdInit ( ) error {
2023-11-08 03:51:33 +00:00
if c . ErpCategoryId != 0 {
if c . ErpCategory == nil {
category , err := GetErpCategory ( c . ErpCategoryId )
2024-01-06 08:48:35 +00:00
if err != nil || category . ID == 0 {
2023-11-08 03:51:33 +00:00
//logger.Error("get erp category err:", err)
2024-01-06 08:48:35 +00:00
return errors . New ( "商品分类信息不存在" )
2023-11-08 03:51:33 +00:00
}
c . ErpCategory = category
}
c . ErpCategoryName = c . ErpCategory . Name
}
if c . ErpSupplierId != 0 {
supplier , err := GetErpSupplier ( c . ErpSupplierId )
2024-01-06 08:48:35 +00:00
if err != nil || supplier . ID == 0 {
2023-11-08 03:51:33 +00:00
//logger.Error("get erp category err:", err)
2024-01-06 08:48:35 +00:00
return errors . New ( "供应商信息不存在" )
2023-11-08 03:51:33 +00:00
} else {
c . ErpSupplierName = supplier . Name
}
}
2024-01-06 08:48:35 +00:00
return nil
2023-11-08 03:51:33 +00:00
}
2023-11-23 12:38:11 +00:00
// GetErpCategory 根据id查询分类信息
2023-11-08 03:51:33 +00:00
func GetErpCategory ( id uint32 ) ( * ErpCategory , error ) {
category := new ( ErpCategory )
err := orm . Eloquent . Table ( "erp_category" ) . Where ( "id=?" , id ) . Find ( category ) . Error
if err != nil {
//logger.Error("category err:", err)
return category , err
}
return category , nil
}
2023-11-23 12:38:11 +00:00
// GetErpSupplier 根据id查询供应商
2023-11-08 03:51:33 +00:00
func GetErpSupplier ( id uint32 ) ( * ErpSupplier , error ) {
supplier := new ( ErpSupplier )
err := orm . Eloquent . Table ( "erp_supplier" ) . Where ( "id=?" , id ) . Find ( supplier ) . Error
if err != nil {
//logger.Error("category err:", err)
return supplier , err
}
return supplier , err
}
2023-11-23 12:38:11 +00:00
// SetErpCategory 新增/编辑商品时设置分类信息
2023-11-08 03:51:33 +00:00
func ( c * ErpCommodity ) SetErpCategory ( ) error {
if c . ErpCategoryId != 0 {
category , err := GetErpCategory ( c . ErpCategoryId )
if err != nil {
2024-01-06 08:48:35 +00:00
logger . Errorf ( "get erp category err:" , err )
2023-11-08 03:51:33 +00:00
return err
}
c . ErpCategory = category
return nil
}
return errors . New ( "erp category id null" )
}
type ErpCommodityListReq struct {
2023-11-09 10:26:19 +00:00
SerialNumber string ` json:"serial_number" ` // 商品编号
ErpCommodityName string ` json:"erp_commodity_name" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" ` // 商品分类id
IMEI string ` json:"imei" ` // 串码
2024-05-31 09:51:41 +00:00
ErpBarcode string ` json:"erp_barcode" ` // 商品条码
2023-11-09 10:26:19 +00:00
ErpSupplierId uint32 ` json:"erp_supplier_id" ` // 供应商id
2023-11-28 09:33:38 +00:00
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 每页展示数据条数
2023-11-09 10:26:19 +00:00
IsExport uint32 ` json:"is_export" ` // 1-导出
2023-11-08 03:51:33 +00:00
}
type ErpCommodityListResp struct {
List [ ] ErpCommodity ` json:"list" `
2024-02-02 06:33:45 +00:00
Total int ` json:"total" ` // 数据总条数
2023-11-28 09:33:38 +00:00
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 每页展示条数
2024-02-01 10:11:22 +00:00
ExportUrl string ` json:"export_url" ` // 文件路径
2023-11-08 03:51:33 +00:00
}
func ( m * ErpCommodityListReq ) List ( ) ( * ErpCommodityListResp , error ) {
resp := & ErpCommodityListResp {
2023-11-28 09:33:38 +00:00
PageIndex : m . PageIndex ,
PageSize : m . PageSize ,
2023-11-08 03:51:33 +00:00
}
2023-11-28 09:33:38 +00:00
page := m . PageIndex - 1
2023-11-08 03:51:33 +00:00
if page < 0 {
page = 0
}
if m . PageSize == 0 {
m . PageSize = 10
}
qs := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
if m . SerialNumber != "" {
qs = qs . Where ( "serial_number=?" , m . SerialNumber )
}
if m . ErpCommodityName != "" {
qs = qs . Where ( "name Like '%" + m . ErpCommodityName + "%'" )
//qs = qs.Where("name LIKE ?", m.Name)
}
if m . IMEI != "" {
qs = qs . Where ( "imei=?" , m . IMEI )
}
if m . ErpCategoryId != 0 {
2024-03-27 10:01:38 +00:00
categoryInfo , err := GetErpCategory ( m . ErpCategoryId )
if err != nil {
return nil , err
}
qs = qs . Where ( "serial_number like ?" , categoryInfo . Number + "%" )
2023-11-08 03:51:33 +00:00
}
if m . ErpSupplierId != 0 {
qs = qs . Where ( "erp_supplier_id=?" , m . ErpSupplierId )
}
2024-05-31 09:51:41 +00:00
if m . ErpBarcode != "" {
qs = qs . Where ( "erp_barcode=?" , m . ErpBarcode )
}
2023-11-08 03:51:33 +00:00
var count int64
err := qs . Count ( & count ) . Error
if err != nil {
//logger.Error("count err:", err)
return resp , err
}
2024-05-10 01:54:37 +00:00
2023-11-08 03:51:33 +00:00
var commodities [ ] ErpCommodity
2024-05-10 01:54:37 +00:00
err = qs . Order ( "id DESC" ) . Find ( & commodities ) . Error
if err != nil && err != RecordNotFound {
//logger.Error("dailys err:", err)
return resp , err
}
2023-11-08 03:51:33 +00:00
2024-05-10 01:54:37 +00:00
// 按商品编号进行排序
SortCommodities ( commodities )
2023-11-08 03:51:33 +00:00
2024-05-10 01:54:37 +00:00
if m . IsExport == 1 {
2023-11-08 03:51:33 +00:00
listExport , err := ErpCommodityListExport ( commodities )
if err != nil {
//logger.Error("list export err:", err)
}
resp . ExportUrl = listExport
} else {
2024-05-10 01:54:37 +00:00
for i , v := range commodities {
if v . IMEIType == 1 { //无串码
commodities [ i ] . IsIMEI = 2 // 非串码
} else {
commodities [ i ] . IsIMEI = 1 // 串码
}
// 查询库存数量
var stockCount int64
err = orm . Eloquent . Table ( "erp_stock_commodity" ) . Where ( "erp_commodity_id = ? and state = ?" ,
v . ID , InStock ) . Count ( & stockCount ) . Error
if err != nil {
return nil , err
}
commodities [ i ] . StockCount = uint32 ( stockCount )
2023-11-08 03:51:33 +00:00
}
2024-05-10 01:54:37 +00:00
// 计算分页所需的切片索引
startIndex := page * m . PageSize
endIndex := ( page + 1 ) * m . PageSize
if endIndex > len ( commodities ) {
endIndex = len ( commodities )
}
resp . List = commodities [ startIndex : endIndex ]
//跟之前保持一致
resp . Total = int ( count )
resp . PageIndex = page + 1
resp . PageSize = m . PageSize
2023-11-08 03:51:33 +00:00
}
2024-05-10 01:54:37 +00:00
return resp , nil
}
// SortStockCommodities 对库存商品数组进行排序
func SortStockCommodities ( commodities [ ] ErpStock ) {
// 定义排序函数
less := func ( i , j int ) bool {
// 解析商品编号,提取分类编号和商品编号的数字部分
catNumI , subCatNumI , threeSubCatNumI , itemNumI := parseSerialNumber ( commodities [ i ] . CommoditySerialNumber )
catNumJ , subCatNumJ , threeSubCatNumJ , itemNumJ := parseSerialNumber ( commodities [ j ] . CommoditySerialNumber )
// 按照分类编号从小到大排序
if catNumI != catNumJ {
return catNumI < catNumJ
2023-11-24 09:09:24 +00:00
}
2024-03-27 10:01:38 +00:00
2024-05-10 01:54:37 +00:00
// 如果分类编号相同,按照具体分类下的商品编号递增排序
if subCatNumI != subCatNumJ {
return subCatNumI < subCatNumJ
}
if threeSubCatNumI != threeSubCatNumJ {
return threeSubCatNumI < threeSubCatNumJ
2024-03-27 10:01:38 +00:00
}
2024-05-10 01:54:37 +00:00
// 如果具体分类编号也相同,按照商品编号递增排序
return itemNumI < itemNumJ
2023-11-24 09:09:24 +00:00
}
2024-05-10 01:54:37 +00:00
// 调用排序函数进行排序
sort . SliceStable ( commodities , less )
}
2023-11-28 09:33:38 +00:00
2024-05-10 01:54:37 +00:00
// SortCommodities 对商品数组进行排序
func SortCommodities ( commodities [ ] ErpCommodity ) {
// 定义排序函数
less := func ( i , j int ) bool {
// 解析商品编号,提取分类编号和商品编号的数字部分
catNumI , subCatNumI , threeSubCatNumI , itemNumI := parseSerialNumber ( commodities [ i ] . SerialNumber )
catNumJ , subCatNumJ , threeSubCatNumJ , itemNumJ := parseSerialNumber ( commodities [ j ] . SerialNumber )
// 按照分类编号从小到大排序
if catNumI != catNumJ {
return catNumI < catNumJ
}
// 如果分类编号相同,按照具体分类下的商品编号递增排序
if subCatNumI != subCatNumJ {
return subCatNumI < subCatNumJ
}
if threeSubCatNumI != threeSubCatNumJ {
return threeSubCatNumI < threeSubCatNumJ
}
// 如果具体分类编号也相同,按照商品编号递增排序
return itemNumI < itemNumJ
}
// 调用排序函数进行排序
sort . SliceStable ( commodities , less )
}
2024-05-31 09:51:41 +00:00
// SortReportByAllotDataCommodities 对商品数组进行排序
func SortReportByAllotDataCommodities ( commodities [ ] ReportByAllotData ) {
// 定义排序函数
less := func ( i , j int ) bool {
// 解析商品编号,提取分类编号和商品编号的数字部分
catNumI , subCatNumI , threeSubCatNumI , itemNumI := parseSerialNumber ( commodities [ i ] . CommoditySerialNumber )
catNumJ , subCatNumJ , threeSubCatNumJ , itemNumJ := parseSerialNumber ( commodities [ j ] . CommoditySerialNumber )
// 按照分类编号从小到大排序
if catNumI != catNumJ {
return catNumI < catNumJ
}
// 如果分类编号相同,按照具体分类下的商品编号递增排序
if subCatNumI != subCatNumJ {
return subCatNumI < subCatNumJ
}
if threeSubCatNumI != threeSubCatNumJ {
return threeSubCatNumI < threeSubCatNumJ
}
// 如果具体分类编号也相同,按照商品编号递增排序
return itemNumI < itemNumJ
}
// 调用排序函数进行排序
sort . SliceStable ( commodities , less )
}
// SortReportByOtherDataCommodities 对商品数组进行排序
func SortReportByOtherDataCommodities ( commodities [ ] ReportByOtherData ) {
// 定义排序函数
less := func ( i , j int ) bool {
// 解析商品编号,提取分类编号和商品编号的数字部分
catNumI , subCatNumI , threeSubCatNumI , itemNumI := parseSerialNumber ( commodities [ i ] . CommoditySerialNumber )
catNumJ , subCatNumJ , threeSubCatNumJ , itemNumJ := parseSerialNumber ( commodities [ j ] . CommoditySerialNumber )
// 按照分类编号从小到大排序
if catNumI != catNumJ {
return catNumI < catNumJ
}
// 如果分类编号相同,按照具体分类下的商品编号递增排序
if subCatNumI != subCatNumJ {
return subCatNumI < subCatNumJ
}
if threeSubCatNumI != threeSubCatNumJ {
return threeSubCatNumI < threeSubCatNumJ
}
// 如果具体分类编号也相同,按照商品编号递增排序
return itemNumI < itemNumJ
}
// 调用排序函数进行排序
sort . SliceStable ( commodities , less )
}
2024-05-10 01:54:37 +00:00
// parseSerialNumber 解析商品编号,提取分类编号、具体分类编号和商品编号的数字部分
func parseSerialNumber ( serialNumber string ) ( catNum , subCatNum , threeSubCatNum , itemNum int ) {
if len ( serialNumber ) < 3 {
return 0 , 0 , 0 , 0 // 如果商品编号长度不足3位, 则返回默认值
}
a := serialNumber [ : 3 ]
fmt . Println ( a )
catNum , _ = strconv . Atoi ( serialNumber [ : 3 ] )
switch len ( serialNumber ) {
case 7 : // 一级分类
subCatNum , _ = strconv . Atoi ( serialNumber [ 3 : 7 ] )
case 10 : // 二级分类
b := serialNumber [ 3 : 6 ]
fmt . Println ( b )
subCatNum , _ = strconv . Atoi ( serialNumber [ 3 : 6 ] )
threeSubCatNum = 0
c := serialNumber [ 6 : ]
fmt . Println ( c )
itemNum , _ = strconv . Atoi ( serialNumber [ 6 : ] )
case 13 : // 三级分类
subCatNum , _ = strconv . Atoi ( serialNumber [ 3 : 6 ] )
d := serialNumber [ 6 : 9 ]
fmt . Println ( d )
threeSubCatNum , _ = strconv . Atoi ( serialNumber [ 6 : 9 ] )
e := serialNumber [ 9 : ]
fmt . Println ( e )
itemNum , _ = strconv . Atoi ( serialNumber [ 9 : ] )
}
return catNum , subCatNum , threeSubCatNum , itemNum
2023-11-08 03:51:33 +00:00
}
type ErpCategoryListReq struct {
ErpCategoryId uint32 ` json:"erp_category_id" `
Pid uint32 ` json:"pid" `
Level uint32 ` json:"level" ` // 分类层级
State uint32 ` json:"state" ` // 1-未使用 2-使用 3-隐藏
PageNum int ` json:"page_num" `
PageSize int ` json:"page_size" `
IsExport uint32 ` json:"is_export" ` // 1-导出
}
type ErpCategoryListResp struct {
List [ ] ErpCategory ` json:"list" `
Total int ` json:"total" `
PageNum int ` json:"page_num" `
PageSize int ` json:"page_size" `
ExportUrl string ` json:"export_url" `
}
func ( m * ErpCategoryListReq ) List ( ) ( * ErpCategoryListResp , error ) {
resp := & ErpCategoryListResp {
PageNum : m . PageNum ,
PageSize : m . PageSize ,
}
//page := m.PageNum - 1
//if page < 0 {
// page = 0
//}
//if m.PageSize == 0 {
// m.PageSize = 10
//}
//qs := orm.Eloquent.Table("erp_category")
//if m.Level != 0 {
// qs = qs.Where("level=?", m.Level)
//}
////if m.ErpCategoryId != 0 {
//// qs = qs.IDEq(m.ErpCategoryId)
////}
//if m.Pid != 0 {
// qs = qs.Where("pid", m.Pid)
//}
//var count int64
2024-05-31 09:51:41 +00:00
//err := qs.Total(&count).Error
2023-11-08 03:51:33 +00:00
//if err != nil {
// logger.Error("count err:", err)
// return resp, err
//}
//resp.Total = int(count)/m.PageSize + 1
//var categories []ErpCategory
//err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&categories).Error
//if err != nil && err != RecordNotFound {
// logger.Error("erp commodity list err:", err)
// return resp, err
//}
var categories [ ] ErpCategory
qs := orm . Eloquent . Table ( "erp_category" ) . Where ( "level=?" , 1 )
if m . Pid != 0 {
qs = qs . Where ( "id=?" , m . Pid )
}
if m . State != 0 {
qs . Where ( "state=?" , m . State )
}
err := qs . Order ( "sort DESC" ) . Find ( & categories ) . Error
if err != nil {
//logger.Error("erp commodity list err:", err)
return resp , err
}
pids := make ( [ ] uint32 , 0 )
for i , _ := range categories {
pids = append ( pids , categories [ i ] . ID )
}
var subCat [ ] ErpCategory
subQs := orm . Eloquent . Table ( "erp_category" ) . Where ( "pid in (?)" , pids )
if m . State != 0 {
subQs . Where ( "state=?" , m . State )
}
err = subQs . Order ( "sort DESC" ) . Find ( & subCat ) . Error
if err != nil {
logger . Errorf ( "pCat err:%#v" , err )
return resp , err
}
pCatMap := make ( map [ uint32 ] [ ] ErpCategory , 0 )
for i , _ := range subCat {
pCatMap [ subCat [ i ] . Pid ] = append ( pCatMap [ subCat [ i ] . Pid ] , subCat [ i ] )
}
for i , _ := range categories {
v , ok := pCatMap [ categories [ i ] . ID ]
if ok {
categories [ i ] . SubCats = v
}
}
if m . IsExport == 1 {
listExport , err := ErpCategoryListExport ( categories )
if err != nil {
//logger.Error("list export err:", err)
}
resp . ExportUrl = listExport
}
resp . List = categories
return resp , nil
}
type CommodityNumberCount struct {
NumberMap map [ uint32 ] uint32 ` json:"number_map" `
}
func ( m * CommodityNumberCount ) GetErpCommodityNumberByCategoryId ( categoryId uint32 ) ( uint32 , error ) {
v , ok := m . NumberMap [ categoryId ]
if ok {
m . NumberMap [ categoryId ] = v + 1
return v + 1 , nil
}
var commodity ErpCommodity
err := orm . Eloquent . Raw ( fmt . Sprintf (
"SELECT number FROM erp_commodity WHERE erp_category_id=%d ORDER BY id DESC LIMIT 0,1;" , categoryId ) ) . Scan ( & commodity ) . Error
if err != nil {
//logger.Error("all categories map err:", err)
return 0 , err
}
m . NumberMap [ categoryId ] = commodity . Number + 1
return commodity . Number + 1 , nil
}
var EsStockLock sync . Mutex
type StockImporter struct {
CensusMap map [ uint32 ] map [ uint32 ] uint32
CommodityMap map [ uint32 ] * ErpCommodity
StoreMap map [ uint32 ] string
Inventories [ ] * ErpInventoryStock
}
type ErpStockFileExcel struct {
StockTimeString string ` json:"stock_time_string" `
IsIMEI string ` json:"is_imei" `
RetailPriceString string ` json:"retail_price_string" `
MinRetailPriceString string ` json:"min_retail_price_string" `
2023-11-23 12:38:11 +00:00
StaffCostPriceString string ` json:"staff_cost_price_string" ` // 员工成本价加价
WholesalePriceString string ` json:"wholesale_price_string" ` // 指导采购价
CountString string ` json:"count_string" ` // 数量
2023-11-08 03:51:33 +00:00
//StoreName string `json:"store_name"`
//ErpCommodityName string `json:"erp_commodity_name"`
//ErpCategoryName string `json:"erp_category_name"`
//SerialNumber string `json:"serial_number"`
//IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
//IMEI string `json:"imei"`
//ErpSupplierName string `json:"erp_supplier_name"`
ErpStockCommodity
}
func ( e * ErpStockFileExcel ) Processing ( ) {
e . Count = IntStringToUin32 ( e . CountString )
if e . IsIMEI == "是" {
e . IMEIType = 2
e . Count = 1
} else if e . IsIMEI == "否" {
e . IMEIType = 1
}
//parseTime, err := time.Parse(DateTimeFormat, e.StockTimeString)
//fmt.Println("StockTimeString:", e.StockTimeString)
//parseTime, err := time.Parse("01-02-06", e.StockTimeString)
format := "2006/01/02"
parseTime , err := time . Parse ( format , e . StockTimeString )
if err != nil {
//logger.Error("parse err:", err)
parseTime = time . Now ( )
}
e . StockTime = parseTime
2024-04-17 01:37:02 +00:00
e . RetailPrice = PercentFloatStringToFloat64 ( e . RetailPriceString )
e . MinRetailPrice = PercentFloatStringToFloat64 ( e . MinRetailPriceString )
e . StaffCostPrice = PercentFloatStringToFloat64 ( e . StaffCostPriceString )
e . WholesalePrice = PercentFloatStringToFloat64 ( e . WholesalePriceString )
2023-11-08 03:51:33 +00:00
}
2023-11-24 09:09:24 +00:00
// ImportStockData 库存导入
// 更新库存表和商品表
// 库存表:插入对应的库存数据
// 库存商品表:插入对应库存商品的数据;供应商只需判断是否在供应商列表即可 todo 库存商品表未插入库存id
func ( m * StockImporter ) ImportStockData ( colsMap [ ] map [ string ] interface { } ) error {
2023-11-23 12:38:11 +00:00
list , err := transStockData ( colsMap )
if err != nil {
return err
}
var erpStockCommodity [ ] ErpStockCommodity
2023-11-08 03:51:33 +00:00
storeNameMap := make ( map [ string ] uint32 , 0 )
erpCommodityMap := make ( map [ string ] * ErpCommodity , 0 )
erpSupplierNameMap := make ( map [ string ] uint32 , 0 )
storeNames := make ( [ ] string , 0 , len ( list ) )
erpCommodityNames := make ( [ ] string , 0 , len ( list ) )
erpSupplierNames := make ( [ ] string , 0 , len ( list ) )
for i , _ := range list {
_ , ok1 := storeNameMap [ list [ i ] . StoreName ]
if ! ok1 {
storeNames = append ( storeNames , list [ i ] . StoreName )
}
2023-11-23 12:38:11 +00:00
_ , ok2 := erpCommodityMap [ list [ i ] . Name ]
2023-11-08 03:51:33 +00:00
if ! ok2 {
2023-12-13 12:05:53 +00:00
if list [ i ] . Name == "" {
//如果商品名称为空,则需要补全
commodityName , err := getCommodityNameBySerialNum ( list [ i ] . SerialNum )
if err != nil {
logger . Errorf ( "getCommodityNameBySerialNum err:" , logger . Field ( "err" , err ) )
return err
}
list [ i ] . Name = commodityName
}
2023-11-23 12:38:11 +00:00
erpCommodityNames = append ( erpCommodityNames , list [ i ] . Name )
2023-12-13 12:05:53 +00:00
2023-11-08 03:51:33 +00:00
}
2023-11-23 12:38:11 +00:00
_ , ok3 := erpSupplierNameMap [ list [ i ] . SupplierName ]
2023-11-08 03:51:33 +00:00
if ! ok3 {
2023-11-23 12:38:11 +00:00
erpSupplierNames = append ( erpSupplierNames , list [ i ] . SupplierName )
2023-11-08 03:51:33 +00:00
}
storeNameMap [ list [ i ] . StoreName ] = uint32 ( 0 )
2023-11-23 12:38:11 +00:00
erpCommodityMap [ list [ i ] . Name ] = nil
erpSupplierNameMap [ list [ i ] . SupplierName ] = uint32 ( 0 )
2023-11-08 03:51:33 +00:00
}
var stores [ ] Store
2023-11-23 12:38:11 +00:00
err = orm . Eloquent . Table ( "store" ) . Where ( "name IN (?)" , storeNames ) . Find ( & stores ) . Error
2023-11-08 03:51:33 +00:00
if err != nil {
//logger.Error("stores err:", err)
return err
}
var erpCommodities [ ] ErpCommodity
err = orm . Eloquent . Table ( "erp_commodity" ) . Where ( "name IN (?)" , erpCommodityNames ) . Find ( & erpCommodities ) . Error
if err != nil {
//logger.Error("stores err:", err)
return err
}
var erpSuppliers [ ] ErpSupplier
err = orm . Eloquent . Table ( "erp_supplier" ) . Debug ( ) . Where ( "name IN (?)" , erpSupplierNames ) . Find ( & erpSuppliers ) . Error
2023-11-23 12:38:11 +00:00
if err != nil && ! errors . Is ( err , RecordNotFound ) {
2023-11-08 03:51:33 +00:00
//logger.Error("stores err:", err)
return err
}
for i , _ := range stores {
storeNameMap [ stores [ i ] . Name ] = stores [ i ] . ID
m . StoreMap [ stores [ i ] . ID ] = stores [ i ] . Name
}
for i , _ := range erpCommodities {
erpCommodityMap [ erpCommodities [ i ] . Name ] = & erpCommodities [ i ]
m . CommodityMap [ erpCommodities [ i ] . ID ] = & erpCommodities [ i ]
}
for i , _ := range erpSuppliers {
erpSupplierNameMap [ erpSuppliers [ i ] . Name ] = erpSuppliers [ i ] . ID
}
nowTime := time . Now ( )
for i , _ := range list {
v1 , ok1 := storeNameMap [ list [ i ] . StoreName ]
if ! ok1 {
logger . Error ( "store name err" )
return errors . New ( "store name err" )
}
2023-11-23 12:38:11 +00:00
v2 , ok2 := erpCommodityMap [ list [ i ] . Name ]
if ! ok2 || v2 == nil {
2023-11-08 03:51:33 +00:00
logger . Error ( "erp commodity name err" )
return errors . New ( "erp commodity name err" )
}
2023-11-23 12:38:11 +00:00
v3 , ok3 := erpSupplierNameMap [ list [ i ] . SupplierName ]
2023-11-08 03:51:33 +00:00
if ! ok3 {
logger . Error ( "erp supplier name err" )
return errors . New ( "erp supplier name err" )
}
2023-11-23 12:38:11 +00:00
// 注意:表格导入是员工成本价,数据库存储是员工成本价加价=员工成本价-指导采购价
2024-04-17 01:37:02 +00:00
nStaffCostPrice , err := strconv . ParseFloat ( list [ i ] . StaffCostPrice , 64 )
2023-11-23 12:38:11 +00:00
if err != nil {
return fmt . Errorf ( "员工成本价转换有误:[%v]" , err )
}
2024-04-17 01:37:02 +00:00
nWholesalePrice , err := strconv . ParseFloat ( list [ i ] . WholesalePrice , 64 ) // 指导采购价
2023-11-23 12:38:11 +00:00
if err != nil {
return fmt . Errorf ( "指导采购价转换有误:[%v]" , err )
}
if nStaffCostPrice < nWholesalePrice {
2024-04-22 01:51:41 +00:00
return fmt . Errorf ( "导入价格有误,员工成本价低于采购价" )
2023-11-23 12:38:11 +00:00
}
nCount , err := strconv . ParseUint ( list [ i ] . Count , 10 , 32 )
if err != nil {
return fmt . Errorf ( "数量转换有误:[%v]" , err )
}
2023-11-24 09:09:24 +00:00
for j := 0 ; j < int ( nCount ) ; j ++ { // 商品库存表都是单笔数据,如果非串码商品有多个,需要插入多条数据
stockCommodity := ErpStockCommodity {
StoreId : v1 ,
StoreName : list [ i ] . StoreName ,
ErpCommodityId : v2 . ID ,
ErpCommodityName : v2 . Name ,
2023-12-11 08:21:21 +00:00
CommoditySerialNumber : v2 . SerialNumber ,
2023-11-24 09:09:24 +00:00
ErpCategoryId : v2 . ErpCategoryId ,
ErpCategoryName : v2 . ErpCategoryName ,
ErpSupplierId : v3 ,
ErpSupplierName : list [ i ] . SupplierName ,
2024-04-17 01:37:02 +00:00
StaffCostPrice : tools . RoundToTwoDecimalPlaces ( nStaffCostPrice - nWholesalePrice ) ,
WholesalePrice : tools . RoundToTwoDecimalPlaces ( nWholesalePrice ) ,
State : InStock ,
StorageType : SystemInventory ,
2023-11-24 09:09:24 +00:00
FirstStockTime : nowTime ,
StockTime : nowTime ,
Count : 1 ,
2024-01-06 08:48:35 +00:00
ErpBarcode : v2 . ErpBarcode , // 240106新增商品条码
2023-11-24 09:09:24 +00:00
IMEIType : v2 . IMEIType ,
2023-12-13 12:05:53 +00:00
IMEI : "" ,
2023-11-24 09:09:24 +00:00
Remark : "" ,
2023-12-22 09:26:34 +00:00
MemberDiscount : v2 . MemberDiscount ,
2023-12-27 11:23:03 +00:00
MinRetailPrice : v2 . MinRetailPrice ,
RetailPrice : v2 . RetailPrice ,
} // todo 首次入库订单编号、订单编号还未赋值
2023-12-11 08:21:21 +00:00
if list [ i ] . StockTime != "" { //导入时间不为空
2023-12-13 12:05:53 +00:00
local , _ := time . LoadLocation ( "Local" )
parsedTime , _ := time . ParseInLocation ( "2006/1/2" , list [ i ] . StockTime , local )
//parsedTime, _ := time.Parse("2006/1/2", list[i].StockTime)
2023-12-11 08:21:21 +00:00
stockCommodity . FirstStockTime = parsedTime
2023-12-13 12:05:53 +00:00
stockCommodity . StockTime = parsedTime
2023-12-11 08:21:21 +00:00
}
2023-12-19 10:21:44 +00:00
//if list[i].SysGenerate != "" && v2.IMEIType == 3 { //导入串码不为空, 则默认为3手动添加
// stockCommodity.IMEIType = 3
// stockCommodity.IMEI = list[i].SysGenerate
//} else if v2.IMEIType == 2 { // 如果该商品串码类型是: 2-串码(系统生成),则系统自动生成
// stockCommodity.IMEIType = 2
// serialCode, err := generateSerialCode(v2.ErpCategoryId)
// if err != nil {
// return err
// }
// stockCommodity.IMEI = serialCode
//}
if list [ i ] . SysGenerate != "" && v2 . IMEIType != 1 { // 商品为串码商品,且导入串码不为空
stockCommodity . IMEIType = v2 . IMEIType
2023-11-24 09:09:24 +00:00
stockCommodity . IMEI = list [ i ] . SysGenerate
}
2023-12-13 12:05:53 +00:00
2023-11-24 09:09:24 +00:00
erpStockCommodity = append ( erpStockCommodity , stockCommodity )
2023-11-08 03:51:33 +00:00
2023-11-24 09:09:24 +00:00
_ , ok4 := m . CensusMap [ stockCommodity . StoreId ]
if ok4 {
m . CensusMap [ stockCommodity . StoreId ] [ stockCommodity . ErpCommodityId ] += stockCommodity . Count
} else {
m . CensusMap [ stockCommodity . StoreId ] = map [ uint32 ] uint32 { stockCommodity . ErpCommodityId : stockCommodity . Count }
}
2023-11-23 12:38:11 +00:00
}
}
if err = m . processErpStocks ( erpStockCommodity ) ; err != nil {
return err
}
return nil
}
2023-12-13 12:05:53 +00:00
// 获取商品名称
func getCommodityNameBySerialNum ( serialNumber string ) ( string , error ) {
var commodity ErpCommodity
err := orm . Eloquent . Table ( "erp_commodity" ) . Where ( "serial_number=?" , serialNumber ) . Find ( & commodity ) . Error
if err != nil {
return "" , err
}
return commodity . Name , nil
}
2024-02-20 09:59:43 +00:00
// GenerateSerialCode 生成商品串码
func GenerateSerialCode ( categoryID uint32 ) ( string , error ) {
max := 1
for {
if max > 5 {
logger . Error ( "generate SerialCode err" )
return "" , errors . New ( "generate SerialCode err" )
}
// 生成年月日6位数
dateStr := time . Now ( ) . Format ( "060102" )
2023-12-13 12:05:53 +00:00
2024-02-20 09:59:43 +00:00
// 生成四位随机数
rand . Seed ( time . Now ( ) . UnixNano ( ) )
randomNumber := rand . Intn ( 10000 )
randomStr := fmt . Sprintf ( "%04d" , randomNumber )
// 获取商品分类编号前3位
categoryStr , err := getCategoryCode ( categoryID )
if err != nil {
logger . Errorf ( "getCategoryCode err:" , logger . Field ( "err" , err ) )
return "" , err
}
// 拼接串码
serialCode := categoryStr + dateStr + randomStr
2024-03-27 10:01:38 +00:00
// 检查生成的串码是否已存在 todo 是否需要判断状态,采购退货的可以重复?
exist , err := QueryRecordExist ( fmt . Sprintf ( "SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET(%s, imei) > 0 " , serialCode ) )
2024-02-20 09:59:43 +00:00
if err != nil {
logger . Error ( "exist sn err" )
}
if ! exist {
return serialCode , nil
}
}
2023-12-13 12:05:53 +00:00
}
// getCategoryCode 根据商品分类ID查询分类编号前3位
func getCategoryCode ( categoryID uint32 ) ( string , error ) {
// 这里模拟查询数据库,实际中你需要连接数据库进行查询
// 假设这里的数据是从数据库中查询得到的
categoryInfo , err := GetCategoryById ( categoryID )
if err != nil {
logger . Errorf ( "GetCategoryById err:" , logger . Field ( "err" , err ) )
return "" , err
}
// 取前3位字符串
return categoryInfo . Number [ : 3 ] , nil
}
2023-11-23 12:38:11 +00:00
func ( m * StockImporter ) processErpStocks ( erpStocks [ ] ErpStockCommodity ) error {
begin := orm . Eloquent . Begin ( )
total := len ( erpStocks )
size := 200
page := ( total + size - 1 ) / size
errGroup := errgroup . Group { }
for i := 0 ; i < page ; i ++ {
start := i * size
end := ( i + 1 ) * size
if end > total {
end = total
2023-11-08 03:51:33 +00:00
}
2023-11-23 12:38:11 +00:00
stockList := erpStocks [ start : end ]
errGroup . Go ( func ( ) error {
2023-12-11 08:21:21 +00:00
return createStockList ( begin , stockList ) //插入库存商品详情
2023-11-23 12:38:11 +00:00
} )
}
2023-12-11 08:21:21 +00:00
err := m . ErpStockCountUpdate ( begin ) //更新or插入库存表
2023-11-23 12:38:11 +00:00
if err != nil {
begin . Rollback ( )
return err
}
err = errGroup . Wait ( )
if err != nil {
begin . Rollback ( )
return err
}
err = begin . Commit ( ) . Error
if err != nil {
begin . Rollback ( )
return err
}
return nil
}
func createStockList ( begin * gorm . DB , stockList [ ] ErpStockCommodity ) error {
2023-12-13 12:05:53 +00:00
err := begin . Debug ( ) . Create ( & stockList ) . Error
2023-11-23 12:38:11 +00:00
if err != nil {
begin . Rollback ( )
return err
2023-11-08 03:51:33 +00:00
}
return nil
}
func ( m * StockImporter ) ErpStockCountUpdate ( gdb * gorm . DB ) error {
for k1 , v1 := range m . CensusMap {
for k2 , v2 := range v1 {
exist , err := QueryRecordExist ( fmt . Sprintf ( "SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d" , k1 , k2 ) )
if err != nil {
//logger.Error("exist err:", err)
return err
}
v , ok := m . CommodityMap [ k2 ]
fmt . Println ( "CommodityMap" , m . CommodityMap )
fmt . Println ( "ok" , ok )
fmt . Println ( "v" , v )
if exist {
err = gdb . Exec ( fmt . Sprintf (
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;" , v2 , k1 , k2 ) ) . Error
if err != nil {
//logger.Error("update stock err:", err)
return err
}
} else {
if ok && v != nil {
stock := & ErpStock {
StoreId : k1 ,
StoreName : m . StoreMap [ k1 ] ,
ErpCommodityId : v . ID ,
ErpCommodityName : v . Name ,
ErpCategoryId : v . ErpCategoryId ,
ErpCategoryName : v . ErpCategoryName ,
CommoditySerialNumber : v . SerialNumber ,
IMEIType : v . IMEIType ,
RetailPrice : v . RetailPrice ,
MinRetailPrice : v . MinRetailPrice ,
Count : v2 ,
DispatchCount : 0 ,
}
err = gdb . Create ( stock ) . Error
if err != nil {
//logger.Error("create stock err:", err)
return err
}
}
}
if ok && v != nil {
inventoryStock := & ErpInventoryStock {
StoreId : k1 ,
StoreName : m . StoreMap [ k1 ] ,
ErpCommodityId : v . ID ,
ErpCommodityName : v . Name ,
ErpCategoryId : v . ErpCategoryId ,
ErpCategoryName : v . ErpCategoryName ,
CommoditySerialNumber : v . SerialNumber ,
IMEIType : v . IMEIType ,
RetailPrice : v . RetailPrice ,
MinRetailPrice : v . MinRetailPrice ,
Count : v2 ,
}
fmt . Println ( "inventoryStock" , inventoryStock . Count )
m . Inventories = append ( m . Inventories , inventoryStock )
}
2023-12-11 08:21:21 +00:00
}
}
2023-11-08 03:51:33 +00:00
2023-12-11 08:21:21 +00:00
return nil
}
// 查询库存详情时同步库存id
func updateCommodityStock ( id uint32 ) error {
var stock ErpStock
err := orm . Eloquent . Table ( "erp_stock" ) . Raw ( "SELECT * FROM erp_stock WHERE id = ?" , id ) . Scan ( & stock ) . Error
if err != nil {
return err
}
if stock . ID != 0 {
err = orm . Eloquent . Debug ( ) . Exec ( fmt . Sprintf (
"UPDATE erp_stock_commodity SET erp_stock_id = %d WHERE erp_commodity_name = '%s' AND erp_stock_id = 0;" ,
stock . ID , stock . ErpCommodityName ) ) . Error
if err != nil {
return err
2023-11-08 03:51:33 +00:00
}
}
return nil
}
2023-11-23 12:38:11 +00:00
func ( m * StockImporter ) ErpInventoryStockCreate ( gdb * gorm . DB , list [ ] ErpStockCommodity ) error {
2023-11-08 03:51:33 +00:00
defer func ( ) {
if err := recover ( ) ; err != nil {
//logger.Error("err:", err)
return
}
} ( )
inventoryStockIdMap := make ( map [ string ] uint32 , 0 )
for _ , inventory := range m . Inventories {
2023-11-17 10:07:01 +00:00
//err := gdb.Create(inventorymanage).Error
2023-11-08 03:51:33 +00:00
err := orm . Eloquent . Create ( inventory ) . Error
if err != nil {
2023-11-17 10:07:01 +00:00
//logger.Error("create erp inventorymanage stock err:", err)
2023-11-08 03:51:33 +00:00
return err
}
inventoryStockIdMap [ fmt . Sprintf ( "%d_%d" , inventory . StoreId , inventory . ErpCommodityId ) ] = inventory . ID
}
begin := orm . Eloquent . Begin ( )
total := len ( list )
size := 500
page := total / size
if total % size != 0 {
page += 1
}
errGroup := errgroup . Group { }
for i := 0 ; i < page ; i ++ {
if i == page - 1 {
stockList := ErpStockCommodityToInventory ( inventoryStockIdMap , list [ i * size : ] )
err := begin . Create ( & stockList ) . Error
if err != nil {
begin . Rollback ( )
//logger.Error("create commodity err:", err)
return err
}
} else {
errGroup . Go ( func ( ) error {
//stockList := list[i*size : (i+1)*size]
stockList := ErpStockCommodityToInventory ( inventoryStockIdMap , list [ i * size : ( i + 1 ) * size ] )
err := begin . Create ( & stockList ) . Error
if err != nil {
begin . Rollback ( )
//logger.Error("create commodity err:", err)
return err
}
return nil
} )
}
}
err := errGroup . Wait ( )
if err != nil {
//logger.Error("wait err:", err)
return err
}
err = begin . Commit ( ) . Error
if err != nil {
//logger.Error("commit err:", err)
return err
}
return nil
}
2023-11-23 12:38:11 +00:00
func ErpStockCommodityToInventory ( inventoryStockIdMap map [ string ] uint32 , list [ ] ErpStockCommodity ) [ ] * ErpInventoryStockCommodity {
2023-11-08 03:51:33 +00:00
inventoryList := make ( [ ] * ErpInventoryStockCommodity , 0 , len ( list ) )
for i , _ := range list {
v , ok := inventoryStockIdMap [ fmt . Sprintf ( "%d_%d" , list [ i ] . StoreId , list [ i ] . ErpCommodityId ) ]
if ok {
inventoryCommodity := & ErpInventoryStockCommodity {
ErpInventoryStockId : v ,
ErpCommodityId : list [ i ] . ErpCommodityId ,
ErpCommodityName : list [ i ] . ErpCommodityName ,
CommoditySerialNumber : list [ i ] . CommoditySerialNumber ,
IMEIType : list [ i ] . IMEIType ,
IMEI : list [ i ] . IMEI ,
ErpSupplierId : list [ i ] . ErpSupplierId ,
ErpSupplierName : list [ i ] . ErpSupplierName ,
StockTime : list [ i ] . StockTime ,
RetailPrice : list [ i ] . RetailPrice ,
MinRetailPrice : list [ i ] . MinRetailPrice ,
StaffCostPrice : list [ i ] . StaffCostPrice ,
WholesalePrice : list [ i ] . WholesalePrice ,
Count : list [ i ] . Count ,
}
//err := gdb.Create(inventoryCommodity).Error
inventoryList = append ( inventoryList , inventoryCommodity )
//err := orm.Eloquent.Create(inventoryCommodity).Error
//if err != nil {
2023-11-17 10:07:01 +00:00
// logger.Error("create erp inventorymanage stock commodity err:", err)
2023-11-08 03:51:33 +00:00
// return inventoryList
//}
}
}
return inventoryList
}
2023-11-23 12:38:11 +00:00
// ErpCommodityListExport 导出商品列表
2023-11-08 03:51:33 +00:00
func ErpCommodityListExport ( list [ ] ErpCommodity ) ( string , error ) {
file := excelize . NewFile ( )
streamWriter , err := file . NewStreamWriter ( "Sheet1" )
if err != nil {
fmt . Println ( err )
}
2023-12-13 12:05:53 +00:00
url := ExportUrl
2023-11-08 03:51:33 +00:00
fileName := time . Now ( ) . Format ( TimeFormat ) + "商品" + ".xlsx"
//title := []interface{}{"供应商编号", "供应商名称", "联系人", "手机号", "地址", "开户银行", "银行账号", "付款周期/天"}
title := [ ] interface { } { "商品编号" , "商品名称" , "商品分类" , "是否串码" , "主供应商" , "零售价" , "最低零售价" , "员工成本价" ,
"采购价" , "提成等级1" , "提成等级2" , "产地" , "备注" , "会员折扣(零售价的百分比)" }
cell , _ := excelize . CoordinatesToCellName ( 1 , 1 )
if err = streamWriter . SetRow ( cell , title ) ; err != nil {
fmt . Println ( err )
}
var row [ ] interface { }
for rowId := 0 ; rowId < len ( list ) ; rowId ++ {
isIMEI := "否"
if list [ rowId ] . IMEIType == 2 {
isIMEI = "是"
}
row = [ ] interface { } { list [ rowId ] . SerialNumber , list [ rowId ] . Name , list [ rowId ] . ErpCategoryName ,
isIMEI , list [ rowId ] . ErpSupplierName , list [ rowId ] . RetailPrice ,
list [ rowId ] . MinRetailPrice , list [ rowId ] . StaffCostPrice , list [ rowId ] . WholesalePrice , list [ rowId ] . Brokerage1 ,
list [ rowId ] . Brokerage2 , list [ rowId ] . Origin , list [ rowId ] . Remark , list [ rowId ] . MemberDiscount }
cell , _ := excelize . CoordinatesToCellName ( 1 , rowId + 2 )
if err := streamWriter . SetRow ( cell , row ) ; err != nil {
fmt . Println ( err )
}
}
if err := streamWriter . Flush ( ) ; err != nil {
fmt . Println ( err )
}
if err := file . SaveAs ( "/www/server/images/export/" + fileName ) ; err != nil {
//if err := file.SaveAs("./" + fileName); err != nil {
fmt . Println ( err )
}
return url + fileName , nil
}
2023-11-23 12:38:11 +00:00
// InventoryDetailListExport 导出库存商品列表
func InventoryDetailListExport ( list [ ] ErpStockCommodity ) ( string , error ) {
file := excelize . NewFile ( )
streamWriter , err := file . NewStreamWriter ( "Sheet1" )
if err != nil {
fmt . Println ( err )
}
2023-12-13 12:05:53 +00:00
url := ExportUrl
2023-11-23 12:38:11 +00:00
fileName := time . Now ( ) . Format ( TimeFormat ) + "商品" + ".xlsx"
fmt . Println ( "url fileName:" , url + fileName )
title := [ ] interface { } { "商品编号" , "商品名称" , "商品分类" , "是否串码" , "商品串码" , "所属门店" , "供应商" , "首次入库时间" , "首次入库方式" ,
"首次入库订单编号" , "最近入库时间" , "入库采购价" , "入库员工成本价" , "最近库龄" , "总库龄" , "当前状态" , "备注" }
cell , _ := excelize . CoordinatesToCellName ( 1 , 1 )
if err = streamWriter . SetRow ( cell , title ) ; err != nil {
fmt . Println ( err )
}
var row [ ] interface { }
for rowId := 0 ; rowId < len ( list ) ; rowId ++ {
isIMEIType := "是"
if list [ rowId ] . IMEIType == 1 {
isIMEIType = "否"
}
storageType := "系统入库"
if list [ rowId ] . StorageType == 2 {
storageType = "采购入库"
}
state := "库存中"
switch list [ rowId ] . State {
case 1 :
state = "库存中"
case 2 :
state = "已售"
case 3 :
state = "采购退货"
case 4 :
state = "调拨中"
}
row = [ ] interface { } {
list [ rowId ] . CommoditySerialNumber ,
list [ rowId ] . ErpCommodityName ,
list [ rowId ] . ErpCategoryName ,
isIMEIType ,
list [ rowId ] . IMEI ,
list [ rowId ] . StoreName ,
list [ rowId ] . ErpSupplierName ,
list [ rowId ] . FirstStockTime ,
storageType ,
2024-03-27 10:01:38 +00:00
list [ rowId ] . OriginalSn ,
2023-11-23 12:38:11 +00:00
list [ rowId ] . StockTime ,
list [ rowId ] . WholesalePrice ,
2024-03-27 10:01:38 +00:00
list [ rowId ] . WholesalePrice + list [ rowId ] . StaffCostPrice ,
2023-11-23 12:38:11 +00:00
list [ rowId ] . Age ,
list [ rowId ] . AllAge ,
state ,
list [ rowId ] . Remark }
cell , _ := excelize . CoordinatesToCellName ( 1 , rowId + 2 )
if err := streamWriter . SetRow ( cell , row ) ; err != nil {
fmt . Println ( err )
}
}
if err := streamWriter . Flush ( ) ; err != nil {
fmt . Println ( err )
}
fmt . Println ( "save fileName:" , config . ExportConfig . Path + fileName )
if err := file . SaveAs ( config . ExportConfig . Path + fileName ) ; err != nil {
fmt . Println ( err )
}
return url + fileName , nil
}
// ErpCategoryListExport 导出商品分类
2023-11-08 03:51:33 +00:00
func ErpCategoryListExport ( list [ ] ErpCategory ) ( string , error ) {
file := excelize . NewFile ( )
streamWriter , err := file . NewStreamWriter ( "Sheet1" )
if err != nil {
fmt . Println ( err )
}
2023-12-13 12:05:53 +00:00
url := ExportUrl
2023-11-08 03:51:33 +00:00
fileName := time . Now ( ) . Format ( TimeFormat ) + "分类列表数据" + ".xlsx"
//title := []interface{}{"门店", "用户ID", "订单编号", "下单时间", "卡带", "说明", "回收价", "闲麦价", "审核时间", "审核人", "操作", "复核时间", "复核状态"}
title := [ ] interface { } { "一级分类" , "二级分类" }
cell , _ := excelize . CoordinatesToCellName ( 1 , 1 )
if err = streamWriter . SetRow ( cell , title ) ; err != nil {
fmt . Println ( err )
}
rowIdx := 2
var row [ ] interface { }
for rowId := 0 ; rowId < len ( list ) ; rowId ++ {
cats := list [ rowId ] . SubCats
for i := 0 ; i < len ( cats ) ; i ++ {
rowName := list [ rowId ] . Name
if i != 0 {
rowName = ""
}
row = [ ] interface { } { rowName , cats [ i ] . Name }
cell , _ := excelize . CoordinatesToCellName ( 1 , rowIdx )
if err := streamWriter . SetRow ( cell , row ) ; err != nil {
fmt . Println ( err )
}
rowIdx ++
}
}
if err := streamWriter . Flush ( ) ; err != nil {
fmt . Println ( err )
}
if err := file . SaveAs ( "/www/server/images/export/" + fileName ) ; err != nil {
//if err := file.SaveAs("./" + fileName); err != nil {
fmt . Println ( err )
}
return url + fileName , nil
}
type ErpStockListReq struct {
2023-11-16 10:09:11 +00:00
SerialNumber string ` json:"serial_number" ` // 商品编号
CommodityName string ` json:"commodity_name" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" ` // 商品分类
StockType uint32 ` json:"stock_type" ` // 库存情况:1-全部 2-有库存 3-无库存
StoreId uint32 ` json:"store_id" ` // 门店编号
2023-11-28 09:33:38 +00:00
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 页面条数
2023-11-16 10:09:11 +00:00
//IsExport uint32 `json:"is_export"` // 1-导出
2023-11-08 03:51:33 +00:00
}
2023-11-23 12:38:11 +00:00
2023-11-08 03:51:33 +00:00
type ErpStockListResp struct {
List [ ] ErpStock ` json:"list" `
2024-02-02 06:33:45 +00:00
Total int ` json:"total" ` // 数据总条数
2023-11-28 09:33:38 +00:00
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 每页展示条数
2023-11-08 03:51:33 +00:00
ExportUrl string ` json:"export_url" `
}
func ( m * ErpStockListReq ) List ( ) ( * ErpStockListResp , error ) {
resp := & ErpStockListResp {
2023-11-28 09:33:38 +00:00
PageIndex : m . PageIndex ,
PageSize : m . PageSize ,
2023-11-08 03:51:33 +00:00
}
2023-11-28 09:33:38 +00:00
page := m . PageIndex - 1
2023-11-08 03:51:33 +00:00
if page < 0 {
page = 0
}
if m . PageSize == 0 {
m . PageSize = 10
}
2023-12-11 08:21:21 +00:00
qs := orm . Eloquent . Table ( "erp_stock" ) .
Joins ( "JOIN erp_category c ON erp_stock.erp_category_id = c.id" )
2023-11-08 03:51:33 +00:00
if m . SerialNumber != "" {
qs = qs . Where ( "commodity_serial_number=?" , m . SerialNumber )
}
if m . CommodityName != "" {
2023-11-17 10:07:01 +00:00
qs = qs . Where ( "erp_commodity_name LIKE ?" , "%" + m . CommodityName + "%" )
2023-11-08 03:51:33 +00:00
}
if m . ErpCategoryId != 0 {
qs = qs . Where ( "erp_category_id=?" , m . ErpCategoryId )
}
2023-11-16 10:09:11 +00:00
if m . StoreId != 0 {
qs = qs . Where ( "store_id=?" , m . StoreId )
2023-11-08 03:51:33 +00:00
}
2023-11-16 10:09:11 +00:00
switch m . StockType {
case 2 :
qs = qs . Where ( "count > 0" )
case 3 :
qs = qs . Where ( "count = 0" )
}
2023-12-11 08:21:21 +00:00
// SQL Order By Clause
qs = qs . Order ( "CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) ELSE " +
"CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END" ) .
Order ( "CAST(c.pid AS SIGNED)" ) .
Order ( "CAST(SUBSTRING(erp_stock.commodity_serial_number, -4) AS SIGNED)" )
2023-11-08 03:51:33 +00:00
var count int64
2023-11-16 10:09:11 +00:00
if err := qs . Count ( & count ) . Error ; err != nil {
2023-11-08 03:51:33 +00:00
//logger.Error("count err:", err)
return resp , err
}
2023-11-16 10:09:11 +00:00
var commodities [ ] ErpStock
2023-12-11 08:21:21 +00:00
err := qs . Offset ( page * m . PageSize ) . Limit ( m . PageSize ) . Find ( & commodities ) . Error
2023-11-16 10:09:11 +00:00
if err != nil && ! errors . Is ( err , RecordNotFound ) {
//logger.Error("erp commodity list err:", err)
return resp , err
2023-11-08 03:51:33 +00:00
}
2023-11-16 10:09:11 +00:00
resp . List = commodities
2023-11-08 03:51:33 +00:00
2023-11-28 09:33:38 +00:00
//跟之前保持一致
resp . Total = int ( count )
resp . PageIndex = page + 1
resp . PageSize = m . PageSize
2023-11-08 03:51:33 +00:00
return resp , nil
}
2023-12-11 08:21:21 +00:00
// StockList
// 1、如果筛选条件有: 库存情况筛选; 则以库存表为准, 查库存表即可
// ( 1) 没门店, 则查所有库存情况并排序
// ( 2) 有门店, 则查门店对应的库存情况并排序
// 2、如果筛选条件没有库存情况,
// ( 1) 先查询商品资料, 并排序; 支持筛选条件: 商品编号、商品分类、商品名称
// ( 2) 然后查询每个商品资料的库存情况, 没传门店id, 则查所有库存; 否则查当前门店的库存情况
2024-04-17 09:44:43 +00:00
func ( m * ErpStockListReq ) StockList ( c * gin . Context ) ( * ErpStockListResp , error ) {
2023-12-11 08:21:21 +00:00
switch m . StockType {
case 2 : // 有库存
2024-04-17 09:44:43 +00:00
return m . stockNoEmptyList ( c )
2023-12-11 08:21:21 +00:00
case 3 : // 无库存,连表查询商品明细和库存表
2024-04-17 09:44:43 +00:00
return m . stockIsEmptyList ( c )
2023-12-11 08:21:21 +00:00
default : // 0和1, 以及其他值, 表示无库存情况筛选
2024-04-17 09:44:43 +00:00
return m . allCommodityList ( c )
2023-12-11 08:21:21 +00:00
}
}
// stockIsEmptyList 库存列表-无库存查询
// 无库存,要连表查询(商品明细、库存表)
2024-04-17 09:44:43 +00:00
func ( m * ErpStockListReq ) stockIsEmptyList ( c * gin . Context ) ( * ErpStockListResp , error ) {
2023-12-11 08:21:21 +00:00
resp := & ErpStockListResp {
PageIndex : m . PageIndex ,
PageSize : m . PageSize ,
}
page := m . PageIndex - 1
if page < 0 {
page = 0
}
if m . PageSize == 0 {
m . PageSize = 10
}
//以下代码组合了2个连表查询
//( 1) 查询无库存的商品资料
/ * * *
SELECT erp_commodity . * ,
COALESCE ( erp_stock . count , 0 ) AS count
FROM erp_commodity
LEFT JOIN (
SELECT erp_commodity_id , SUM ( count ) AS count
FROM erp_stock
GROUP BY erp_commodity_id
) erp_stock ON erp_commodity . id = erp_stock . erp_commodity_id
WHERE erp_stock . count IS NULL OR erp_stock . count = 0 ;
* * * /
//( 2) 按商品编号排序
/ * * *
SELECT e . *
FROM erp_stock e
JOIN erp_category c ON e . erp_category_id = c . id
ORDER BY
CASE WHEN c . pid = 0 THEN CAST ( c . number AS SIGNED ) ELSE CAST ( SUBSTRING ( c . number , 1 , 3 ) AS SIGNED ) END ,
CAST ( c . pid AS SIGNED ) ,
CAST ( SUBSTRING ( e . commodity_serial_number , - 4 ) AS SIGNED ) ;
* * * /
qs := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
2024-04-01 03:00:22 +00:00
es := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
2024-04-17 09:44:43 +00:00
// 非管理员才判断所属门店
var storeList [ ] uint32
if ! ( tools . GetRoleName ( c ) == "admin" || tools . GetRoleName ( c ) == "系统管理员" ) {
sysUser , err := GetSysUserByCtx ( c )
if err != nil {
return nil , err
}
// 返回sysUser未过期的门店id列表
storeList = GetValidStoreIDs ( sysUser . StoreData )
if m . StoreId != 0 {
if ! Contains ( storeList , m . StoreId ) {
return nil , errors . New ( "您没有该门店权限" )
}
} else {
if len ( storeList ) == 0 {
return nil , errors . New ( "用户未绑定门店" )
}
}
}
2023-12-11 08:21:21 +00:00
if m . StoreId != 0 { // 传门店id
2024-04-29 10:10:48 +00:00
qs = qs . Select ( "erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count," +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count" ) .
2024-04-01 03:00:22 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id AND erp_stock.store_id = ?" , m . StoreId ) .
//Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
Joins ( "LEFT JOIN erp_category c ON erp_commodity.erp_category_id = c.id" ) .
2024-05-23 07:30:20 +00:00
Group ( "erp_commodity.id" ) .
2024-04-01 03:00:22 +00:00
//Where("erp_stock.count = 0 AND erp_stock.store_id = ?", m.StoreId).
Order ( "CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
"CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2024-04-29 10:10:48 +00:00
es = es . Select ( "erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count" ) .
2024-04-01 03:00:22 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id AND erp_stock.store_id = ?" , m . StoreId ) .
//Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
Joins ( "LEFT JOIN erp_category c ON erp_commodity.erp_category_id = c.id" ) .
2024-05-23 07:30:20 +00:00
Group ( "erp_commodity.id" ) .
2024-04-01 03:00:22 +00:00
//Where("erp_stock.count = 0 AND erp_stock.store_id = ?", m.StoreId).
2023-12-11 08:21:21 +00:00
Order ( "CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
"CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2024-05-27 03:08:39 +00:00
} else {
qs = qs . Select ( "erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count," +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count" ) .
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id" ) .
//Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
Joins ( "LEFT JOIN erp_category c ON erp_commodity.erp_category_id = c.id" ) .
Group ( "erp_commodity.id" ) .
//Where("erp_stock.count = 0 AND erp_stock.store_id = ?", m.StoreId).
Order ( "CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
"CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
es = es . Select ( "erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count" ) .
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id" ) .
//Joins("LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
Joins ( "LEFT JOIN erp_category c ON erp_commodity.erp_category_id = c.id" ) .
Group ( "erp_commodity.id" ) .
//Where("erp_stock.count = 0 AND erp_stock.store_id = ?", m.StoreId).
Order ( "CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
"CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2023-12-11 08:21:21 +00:00
}
2024-05-27 03:08:39 +00:00
//} else { // 没传门店id, 则子查询先求库存表中erp_commodity_id相同的count之和
// if len(storeList) == 0 {
// qs = qs.Select("erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count, " +
// "COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count").
// Joins("LEFT JOIN (SELECT erp_commodity_id, SUM(count) AS count, SUM(dispatch_count) AS dispatch_count FROM erp_stock GROUP BY erp_commodity_id) " +
// "erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
// Joins("JOIN erp_category c ON erp_commodity.erp_category_id = c.id").
// Where("erp_stock.count IS NULL OR erp_stock.count = 0").
// Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
// "ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
// "CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
// es = es.Select("erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count, " +
// "COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count").
// Joins("LEFT JOIN (SELECT erp_commodity_id, SUM(count) AS count, SUM(dispatch_count) AS dispatch_count FROM erp_stock GROUP BY erp_commodity_id) " +
// "erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id").
// Joins("JOIN erp_category c ON erp_commodity.erp_category_id = c.id").
// Where("erp_stock.count IS NULL OR erp_stock.count = 0").
// Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
// "ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
// "CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
// } else {
// qs = qs.Select("erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count, "+
// "COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count").
// Joins("LEFT JOIN (SELECT erp_commodity_id, SUM(count) AS count, SUM(dispatch_count) AS dispatch_count FROM erp_stock WHERE store_id IN (?) GROUP BY erp_commodity_id) "+
// "erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id", storeList).
// Joins("JOIN erp_category c ON erp_commodity.erp_category_id = c.id").
// Where("erp_stock.count IS NULL OR erp_stock.count = 0").
// Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
// "ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
// "CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
// es = es.Select("erp_commodity.*, COALESCE(erp_stock.count, 0) AS total_count, "+
// "COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count").
// Joins("LEFT JOIN (SELECT erp_commodity_id, SUM(count) AS count, SUM(dispatch_count) AS dispatch_count FROM erp_stock WHERE store_id IN (?) GROUP BY erp_commodity_id) "+
// "erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id", storeList).
// Joins("JOIN erp_category c ON erp_commodity.erp_category_id = c.id").
// Where("erp_stock.count IS NULL OR erp_stock.count = 0").
// Order("CASE WHEN c.pid = 0 THEN CAST(c.number AS SIGNED) " +
// "ELSE CAST(SUBSTRING(c.number, 1, 3) AS SIGNED) END, " +
// "CAST(c.pid AS SIGNED), CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)")
// }
//}
2023-12-11 08:21:21 +00:00
if m . SerialNumber != "" {
qs = qs . Where ( "erp_commodity.serial_number=?" , m . SerialNumber )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.serial_number=?" , m . SerialNumber )
2023-12-11 08:21:21 +00:00
}
if m . CommodityName != "" {
qs = qs . Where ( "erp_commodity.name Like '%" + m . CommodityName + "%'" )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.name Like '%" + m . CommodityName + "%'" )
2023-12-11 08:21:21 +00:00
//qs = qs.Where("name LIKE ?", m.Name)
}
if m . ErpCategoryId != 0 {
qs = qs . Where ( "erp_commodity.erp_category_id=?" , m . ErpCategoryId )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.erp_category_id=?" , m . ErpCategoryId )
2023-12-11 08:21:21 +00:00
}
var count int64
2024-04-01 03:00:22 +00:00
err := es . Count ( & count ) . Error
2023-12-11 08:21:21 +00:00
if err != nil {
logger . Error ( "查询无库存列表数量失败" , logger . Field ( "err" , err ) )
return nil , err
}
2024-04-01 03:00:22 +00:00
var commodities [ ] struct {
ErpCommodity
2024-04-29 10:10:48 +00:00
TotalCount int
TotalDispatchCount int
2024-04-01 03:00:22 +00:00
}
//err = qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
err = qs . Find ( & commodities ) . Error
if err != nil && err != RecordNotFound {
logger . Error ( "查询无库存列表失败" , logger . Field ( "err" , err ) )
return nil , err
}
2023-12-11 08:21:21 +00:00
//遍历商品资料,转换为库存列表数据
var stockList [ ] ErpStock
for _ , commodity := range commodities {
2024-04-01 03:00:22 +00:00
if commodity . TotalCount == 0 {
var stock ErpStock
stock . ErpCommodityId = commodity . ID
stock . ErpCommodityName = commodity . Name
stock . ErpCategoryId = commodity . ErpCategoryId
stock . ErpCategoryName = commodity . ErpCategoryName
stock . CommoditySerialNumber = commodity . SerialNumber
stock . IMEIType = commodity . IMEIType
stock . RetailPrice = commodity . RetailPrice
stock . MinRetailPrice = commodity . MinRetailPrice
stock . Count = 0
stock . DispatchCount = 0
stockList = append ( stockList , stock )
}
}
2023-12-11 08:21:21 +00:00
2024-05-10 01:54:37 +00:00
SortStockCommodities ( stockList )
2024-04-01 03:00:22 +00:00
// Paginate results
startIndex := page * m . PageSize
endIndex := startIndex + m . PageSize
if endIndex > len ( stockList ) {
endIndex = len ( stockList )
2023-12-11 08:21:21 +00:00
}
2024-04-01 03:00:22 +00:00
// Slice the users based on pagination
pagedList := stockList [ startIndex : endIndex ]
2023-12-11 08:21:21 +00:00
//跟之前保持一致
2024-04-01 03:00:22 +00:00
resp . Total = len ( stockList )
2023-12-11 08:21:21 +00:00
resp . PageIndex = page + 1
resp . PageSize = m . PageSize
2024-04-01 03:00:22 +00:00
resp . List = pagedList
2023-12-11 08:21:21 +00:00
return resp , nil
}
2024-04-17 09:44:43 +00:00
func ( m * ErpStockListReq ) stockNoEmptyList ( c * gin . Context ) ( * ErpStockListResp , error ) {
2023-12-11 08:21:21 +00:00
resp := & ErpStockListResp {
PageIndex : m . PageIndex ,
PageSize : m . PageSize ,
}
page := m . PageIndex - 1
if page < 0 {
page = 0
}
if m . PageSize == 0 {
m . PageSize = 10
}
/ * * *
//组合查询
SELECT
ec . * ,
COALESCE ( SUM ( es . count ) , 0 ) AS total_count
FROM
erp_commodity ec
LEFT JOIN
erp_stock es ON ec . id = es . erp_commodity_id
GROUP BY
ec . id
ORDER BY
CASE
WHEN ec . erp_category_id IN ( SELECT id FROM erp_category WHERE pid = 0 ) THEN CAST ( ( SELECT number FROM erp_category WHERE id = ec . erp_category_id ) AS SIGNED )
ELSE CAST ( SUBSTRING ( ( SELECT number FROM erp_category WHERE id = ( SELECT pid FROM erp_category WHERE id = ec . erp_category_id ) ) , 1 , 3 ) AS SIGNED )
END ,
CAST ( ( SELECT pid FROM erp_category WHERE id = ec . erp_category_id ) AS SIGNED ) ,
CAST ( SUBSTRING ( ec . serial_number , - 4 ) AS SIGNED ) ;
* * * /
qs := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
2024-04-01 03:00:22 +00:00
es := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
2024-04-17 09:44:43 +00:00
// 非管理员才判断所属门店
if ! ( tools . GetRoleName ( c ) == "admin" || tools . GetRoleName ( c ) == "系统管理员" ) {
sysUser , err := GetSysUserByCtx ( c )
if err != nil {
return nil , err
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs ( sysUser . StoreData )
if m . StoreId != 0 {
if ! Contains ( storeList , m . StoreId ) {
return nil , errors . New ( "您没有该门店权限" )
}
} else {
if len ( storeList ) > 0 {
2024-05-27 11:01:04 +00:00
if len ( storeList ) == 1 {
qs = qs . Where ( "store_id = ?" , storeList [ 0 ] )
es = es . Where ( "store_id = ?" , storeList [ 0 ] )
} else {
qs = qs . Where ( "store_id IN (?)" , storeList )
es = es . Where ( "store_id IN (?)" , storeList )
}
2024-04-17 09:44:43 +00:00
} else {
return nil , errors . New ( "用户未绑定门店" )
}
}
}
2023-12-11 08:21:21 +00:00
if m . StoreId == 0 { // 没指定门店,连表查询并计算总数量
2024-04-29 10:10:48 +00:00
qs = qs . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2023-12-11 08:21:21 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id AND erp_stock.count != 0" ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_commodity.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) " +
"THEN CAST((SELECT number FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED) " +
"ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id)), 1, 3) AS SIGNED) " +
"END, CAST((SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2024-04-29 10:10:48 +00:00
es = es . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2024-04-01 03:00:22 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id AND erp_stock.count != 0" ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_commodity.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) " +
"THEN CAST((SELECT number FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED) " +
"ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id)), 1, 3) AS SIGNED) " +
"END, CAST((SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2023-12-11 08:21:21 +00:00
} else { // 指定了门店, 连表查询指定store_id的count
2024-04-29 10:10:48 +00:00
qs = qs . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2023-12-11 08:21:21 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id " +
"AND erp_stock.count != 0 AND erp_stock.store_id = ?" , m . StoreId ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_category.pid = 0 THEN CAST(erp_category.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(erp_category.number, 1, 3) AS SIGNED) END, " +
"CAST(erp_category.pid AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" ) .
Joins ( "JOIN erp_category ON erp_commodity.erp_category_id = erp_category.id" )
2024-04-29 10:10:48 +00:00
es = es . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2024-04-01 03:00:22 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id " +
"AND erp_stock.count != 0 AND erp_stock.store_id = ?" , m . StoreId ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_category.pid = 0 THEN CAST(erp_category.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(erp_category.number, 1, 3) AS SIGNED) END, " +
"CAST(erp_category.pid AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" ) .
Joins ( "JOIN erp_category ON erp_commodity.erp_category_id = erp_category.id" )
2023-12-11 08:21:21 +00:00
}
if m . SerialNumber != "" {
qs = qs . Where ( "erp_commodity.serial_number=?" , m . SerialNumber )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.serial_number=?" , m . SerialNumber )
2023-12-11 08:21:21 +00:00
}
if m . CommodityName != "" {
qs = qs . Where ( "erp_commodity.name Like '%" + m . CommodityName + "%'" )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.name Like '%" + m . CommodityName + "%'" )
2023-12-11 08:21:21 +00:00
}
if m . ErpCategoryId != 0 {
qs = qs . Where ( "erp_commodity.erp_category_id=?" , m . ErpCategoryId )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.erp_category_id=?" , m . ErpCategoryId )
2023-12-11 08:21:21 +00:00
}
var commodities [ ] struct {
ErpCommodity
2024-04-29 10:10:48 +00:00
TotalCount int
ErpStockId int
TotalDispatchCount int
2023-12-11 08:21:21 +00:00
}
var count int64
2024-04-01 03:00:22 +00:00
err := es . Count ( & count ) . Error
2023-12-11 08:21:21 +00:00
if err != nil {
logger . Error ( "commodityList count err" , logger . Field ( "err" , err ) )
return resp , err
}
2024-04-01 03:00:22 +00:00
//err = qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
err = qs . Find ( & commodities ) . Error
if err != nil && err != RecordNotFound {
logger . Error ( "commodityList err" , logger . Field ( "err" , err ) )
return resp , err
}
2023-12-11 08:21:21 +00:00
//遍历商品资料,转换为库存列表数据
var stockList [ ] ErpStock
for _ , commodity := range commodities {
if commodity . TotalCount != 0 {
var stock ErpStock
stock . ID = uint32 ( commodity . ErpStockId )
stock . ErpCommodityId = commodity . ID
stock . ErpCommodityName = commodity . Name
stock . ErpCategoryId = commodity . ErpCategoryId
stock . ErpCategoryName = commodity . ErpCategoryName
stock . CommoditySerialNumber = commodity . SerialNumber
2024-03-27 10:01:38 +00:00
stock . IMEIType = commodity . IMEIType
2023-12-11 08:21:21 +00:00
stock . RetailPrice = commodity . RetailPrice
stock . MinRetailPrice = commodity . MinRetailPrice
stock . Count = uint32 ( commodity . TotalCount )
2024-04-29 10:10:48 +00:00
stock . DispatchCount = uint32 ( commodity . TotalDispatchCount )
2023-12-11 08:21:21 +00:00
stockList = append ( stockList , stock )
}
2024-04-01 03:00:22 +00:00
}
2023-12-11 08:21:21 +00:00
2024-05-10 01:54:37 +00:00
SortStockCommodities ( stockList )
2024-04-01 03:00:22 +00:00
// Paginate results
startIndex := page * m . PageSize
endIndex := startIndex + m . PageSize
if endIndex > len ( stockList ) {
endIndex = len ( stockList )
2023-12-11 08:21:21 +00:00
}
2024-04-01 03:00:22 +00:00
// Slice the users based on pagination
pagedList := stockList [ startIndex : endIndex ]
2023-12-11 08:21:21 +00:00
//跟之前保持一致
resp . Total = len ( stockList )
resp . PageIndex = page + 1
resp . PageSize = m . PageSize
2024-04-01 03:00:22 +00:00
resp . List = pagedList
2023-12-11 08:21:21 +00:00
return resp , nil
}
// 筛选条件无:库存情况筛选
// ( 1) 先查询商品资料, 并排序; 支持筛选条件: 商品编号、商品分类、商品名称
// ( 2) 然后查询每个商品资料的库存情况, 没传门店id, 则查所有库存; 否则查当前门店的库存情况
2024-04-17 09:44:43 +00:00
func ( m * ErpStockListReq ) allCommodityList ( c * gin . Context ) ( * ErpStockListResp , error ) {
2023-12-11 08:21:21 +00:00
resp := & ErpStockListResp {
PageIndex : m . PageIndex ,
PageSize : m . PageSize ,
}
page := m . PageIndex - 1
if page < 0 {
page = 0
}
if m . PageSize == 0 {
m . PageSize = 10
}
/ * * *
//组合查询
SELECT
ec . * ,
COALESCE ( SUM ( es . count ) , 0 ) AS total_count
FROM
erp_commodity ec
LEFT JOIN
erp_stock es ON ec . id = es . erp_commodity_id
GROUP BY
ec . id
ORDER BY
CASE
WHEN ec . erp_category_id IN ( SELECT id FROM erp_category WHERE pid = 0 ) THEN CAST ( ( SELECT number FROM erp_category WHERE id = ec . erp_category_id ) AS SIGNED )
ELSE CAST ( SUBSTRING ( ( SELECT number FROM erp_category WHERE id = ( SELECT pid FROM erp_category WHERE id = ec . erp_category_id ) ) , 1 , 3 ) AS SIGNED )
END ,
CAST ( ( SELECT pid FROM erp_category WHERE id = ec . erp_category_id ) AS SIGNED ) ,
CAST ( SUBSTRING ( ec . serial_number , - 4 ) AS SIGNED ) ;
* * * /
qs := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
2024-04-01 03:00:22 +00:00
es := orm . Eloquent . Debug ( ) . Table ( "erp_commodity" )
2023-12-11 08:21:21 +00:00
if m . SerialNumber != "" {
qs = qs . Where ( "erp_commodity.serial_number=?" , m . SerialNumber )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.serial_number=?" , m . SerialNumber )
2023-12-11 08:21:21 +00:00
}
if m . CommodityName != "" {
qs = qs . Where ( "erp_commodity.name Like '%" + m . CommodityName + "%'" )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.name Like '%" + m . CommodityName + "%'" )
2023-12-11 08:21:21 +00:00
}
if m . ErpCategoryId != 0 {
qs = qs . Where ( "erp_commodity.erp_category_id=?" , m . ErpCategoryId )
2024-04-01 03:00:22 +00:00
es = es . Where ( "erp_commodity.erp_category_id=?" , m . ErpCategoryId )
2023-12-11 08:21:21 +00:00
}
2024-04-17 09:44:43 +00:00
// 非管理员才判断所属门店
if ! ( tools . GetRoleName ( c ) == "admin" || tools . GetRoleName ( c ) == "系统管理员" ) {
sysUser , err := GetSysUserByCtx ( c )
if err != nil {
return nil , err
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs ( sysUser . StoreData )
if m . StoreId != 0 {
if ! Contains ( storeList , m . StoreId ) {
return nil , errors . New ( "您没有该门店权限" )
}
} else {
if len ( storeList ) > 0 {
2024-05-27 11:01:04 +00:00
if len ( storeList ) == 1 {
qs = qs . Where ( "store_id = ?" , storeList [ 0 ] )
es = es . Where ( "store_id = ?" , storeList [ 0 ] )
} else {
qs = qs . Where ( "store_id IN (?)" , storeList )
es = es . Where ( "store_id IN (?)" , storeList )
}
2024-04-17 09:44:43 +00:00
} else {
return nil , errors . New ( "用户未绑定门店" )
}
}
}
2023-12-11 08:21:21 +00:00
if m . StoreId == 0 { // 没指定门店,连表查询并计算总数量
2024-04-29 10:10:48 +00:00
qs = qs . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2023-12-11 08:21:21 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id" ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_commodity.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) " +
"THEN CAST((SELECT number FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED) " +
"ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id)), 1, 3) AS SIGNED) " +
"END, CAST((SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2024-04-29 10:10:48 +00:00
es = es . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2024-04-01 03:00:22 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id" ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_commodity.erp_category_id IN (SELECT id FROM erp_category WHERE pid = 0) " +
"THEN CAST((SELECT number FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED) " +
"ELSE CAST(SUBSTRING((SELECT number FROM erp_category WHERE id = (SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id)), 1, 3) AS SIGNED) " +
"END, CAST((SELECT pid FROM erp_category WHERE id = erp_commodity.erp_category_id) AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" )
2023-12-11 08:21:21 +00:00
} else { // 指定了门店, 连表查询指定store_id的count
2024-04-29 10:10:48 +00:00
qs = qs . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2023-12-11 08:21:21 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id " +
"AND erp_stock.store_id = ?" , m . StoreId ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_category.pid = 0 THEN CAST(erp_category.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(erp_category.number, 1, 3) AS SIGNED) END, " +
"CAST(erp_category.pid AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" ) .
Joins ( "JOIN erp_category ON erp_commodity.erp_category_id = erp_category.id" )
2024-04-29 10:10:48 +00:00
es = es . Select ( "erp_commodity.*, COALESCE(SUM(erp_stock.count), 0) AS total_count, " +
"COALESCE(SUM(erp_stock.dispatch_count), 0) AS total_dispatch_count, erp_stock.id AS erp_stock_id" ) .
2024-04-01 03:00:22 +00:00
Joins ( "LEFT JOIN erp_stock ON erp_commodity.id = erp_stock.erp_commodity_id " +
"AND erp_stock.store_id = ?" , m . StoreId ) .
Group ( "erp_commodity.id" ) .
Order ( "CASE WHEN erp_category.pid = 0 THEN CAST(erp_category.number AS SIGNED) " +
"ELSE CAST(SUBSTRING(erp_category.number, 1, 3) AS SIGNED) END, " +
"CAST(erp_category.pid AS SIGNED), " +
"CAST(SUBSTRING(erp_commodity.serial_number, -4) AS SIGNED)" ) .
Joins ( "JOIN erp_category ON erp_commodity.erp_category_id = erp_category.id" )
2023-12-11 08:21:21 +00:00
}
var commodities [ ] struct {
ErpCommodity
2024-04-29 10:10:48 +00:00
TotalCount int
ErpStockId int
TotalDispatchCount int
2023-12-11 08:21:21 +00:00
}
var count int64
2024-05-27 03:08:39 +00:00
err := orm . Eloquent . Debug ( ) . Table ( "(?) AS subquery" , es ) . Count ( & count ) . Error
2024-05-31 09:51:41 +00:00
//err := es.Total(&count).Error
2023-12-11 08:21:21 +00:00
if err != nil {
logger . Error ( "commodityList count err" , logger . Field ( "err" , err ) )
return resp , err
}
2024-04-01 03:00:22 +00:00
err = qs . Offset ( page * m . PageSize ) . Limit ( m . PageSize ) . Find ( & commodities ) . Error
if err != nil && err != RecordNotFound {
logger . Error ( "commodityList err" , logger . Field ( "err" , err ) )
return resp , err
}
2023-12-11 08:21:21 +00:00
//遍历商品资料,转换为库存列表数据
var stockList [ ] ErpStock
for _ , commodity := range commodities {
var stock ErpStock
stock . ID = uint32 ( commodity . ErpStockId )
stock . ErpCommodityId = commodity . ID
stock . ErpCommodityName = commodity . Name
stock . ErpCategoryId = commodity . ErpCategoryId
stock . ErpCategoryName = commodity . ErpCategoryName
stock . CommoditySerialNumber = commodity . SerialNumber
2024-03-27 10:01:38 +00:00
stock . IMEIType = commodity . IMEIType
2023-12-11 08:21:21 +00:00
stock . RetailPrice = commodity . RetailPrice
stock . MinRetailPrice = commodity . MinRetailPrice
stock . Count = uint32 ( commodity . TotalCount )
2024-04-29 10:10:48 +00:00
stock . DispatchCount = uint32 ( commodity . TotalDispatchCount )
2023-12-11 08:21:21 +00:00
stockList = append ( stockList , stock )
}
2024-05-10 01:54:37 +00:00
SortStockCommodities ( stockList )
2023-12-11 08:21:21 +00:00
//跟之前保持一致
resp . Total = int ( count )
resp . PageIndex = page + 1
resp . PageSize = m . PageSize
resp . List = stockList
return resp , nil
}
2023-11-08 03:51:33 +00:00
func ErpStockCommodityListSetAge ( commodities [ ] ErpStockCommodity ) {
nowTime := time . Now ( )
for i , _ := range commodities {
commodities [ i ] . Age = uint32 ( nowTime . Sub ( commodities [ i ] . StockTime ) . Hours ( ) ) / 24
commodities [ i ] . AllAge = uint32 ( nowTime . Sub ( commodities [ i ] . FirstStockTime ) . Hours ( ) ) / 24
}
}
2023-11-16 10:09:11 +00:00
// ErpStockCommodityListReq 库存详情接口请求参数
2023-11-08 03:51:33 +00:00
type ErpStockCommodityListReq struct {
2024-01-06 08:48:35 +00:00
ScanCode string ` json:"scan_code" ` // 扫码枪扫码数据:串码/条码
2023-11-16 10:09:11 +00:00
ErpStockId uint32 ` json:"erp_stock_id" ` // 库存id
ErpCommodityId uint32 ` json:"erp_commodity_id" ` // 商品id
SerialNumber string ` json:"serial_number" ` // 商品编号
CommodityName string ` json:"commodity_name" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" ` // 商品分类Id
2024-04-10 06:17:19 +00:00
IsIMEI uint32 ` json:"is_imei" ` // 是否串码: 0-查全部 1-查串码类 2-查非串码
2023-11-16 10:09:11 +00:00
IMEI string ` json:"imei" ` // 串码
StoreId uint32 ` json:"store_id" ` // 门店编号
SupplierId uint32 ` json:"supplier_id" ` // 供应商id
2024-03-16 08:19:12 +00:00
State uint32 ` json:"state" ` // 库存状态:1-在库 2-已售 3-采购退货 4-调拨中 5-出库( 前端只看1, 4)
2024-04-22 01:51:41 +00:00
OriginalSn string ` json:"original_sn" ` // 首次入库订单编号
2023-11-16 10:09:11 +00:00
StorageType uint32 ` json:"storage_type" ` // 首次入库方式: 1-系统入库 2-采购入库
StockTimeStart string ` json:"stock_time_start" ` // 最近入库开始时间
StockTimeEnd string ` json:"stock_time_end" ` // 最近入库结束时间
Age uint32 ` json:"age" ` // 最近库龄
AllAge uint32 ` json:"all_age" ` // 总库龄
2023-11-28 09:33:38 +00:00
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 每页展示数据条数
2023-11-16 10:09:11 +00:00
IsExport uint32 ` json:"is_export" ` // 是否导出excel: 1-导出
2024-04-22 01:51:41 +00:00
//Sn string `json:"sn"` // 首次入库订单编号
2023-11-08 03:51:33 +00:00
}
2023-11-24 09:09:24 +00:00
// ErpStockCommodityListResp 库存详情接口响应参数
2023-11-08 03:51:33 +00:00
type ErpStockCommodityListResp struct {
2023-12-19 10:21:44 +00:00
List [ ] ErpStockCommodity ` json:"list" `
2024-02-02 06:33:45 +00:00
Total int ` json:"total" ` // 数据总条数
2023-12-19 10:21:44 +00:00
PageIndex int ` json:"pageIndex" ` // 页码
PageSize int ` json:"pageSize" ` // 每页展示条数
TotalWholesalePrice int ` json:"total_wholesale_price" ` // 入库采购价之和
TotalStaffPrice int ` json:"total_staff_price" ` // 入库员工成本价之和
ExportUrl string ` json:"export_url" `
2023-11-08 03:51:33 +00:00
}
2023-11-24 09:09:24 +00:00
// GetDetailList 查看库存详情
2024-04-17 09:44:43 +00:00
func ( m * ErpStockCommodityListReq ) GetDetailList ( c * gin . Context ) ( * ErpStockCommodityListResp , error ) {
2023-11-08 03:51:33 +00:00
resp := & ErpStockCommodityListResp {
2023-11-28 09:33:38 +00:00
PageIndex : m . PageIndex ,
PageSize : m . PageSize ,
2023-11-08 03:51:33 +00:00
}
2023-11-28 09:33:38 +00:00
page := m . PageIndex - 1
2023-11-08 03:51:33 +00:00
if page < 0 {
page = 0
}
if m . PageSize == 0 {
m . PageSize = 10
}
2023-11-16 10:09:11 +00:00
2023-12-11 08:21:21 +00:00
if m . ErpStockId != 0 {
updateCommodityStock ( m . ErpStockId ) // 同步详情表的库存id
}
// 出库数据不查询
2024-01-06 08:48:35 +00:00
qs := orm . Eloquent . Table ( "erp_stock_commodity" )
2023-11-16 10:09:11 +00:00
2024-04-17 09:44:43 +00:00
// 非管理员才判断所属门店
if ! ( tools . GetRoleName ( c ) == "admin" || tools . GetRoleName ( c ) == "系统管理员" ) {
sysUser , err := GetSysUserByCtx ( c )
if err != nil {
return nil , err
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs ( sysUser . StoreData )
if m . StoreId != 0 {
if ! Contains ( storeList , m . StoreId ) {
return nil , errors . New ( "您没有该门店权限" )
}
} else {
if len ( storeList ) > 0 {
2024-05-27 11:01:04 +00:00
if len ( storeList ) == 1 {
qs = qs . Where ( "store_id = ?" , storeList [ 0 ] )
} else {
qs = qs . Where ( "store_id IN (?)" , storeList )
}
2024-04-17 09:44:43 +00:00
} else {
return nil , errors . New ( "用户未绑定门店" )
}
}
}
2023-11-16 10:09:11 +00:00
// 构建查询条件
m . buildQueryConditions ( qs )
2023-12-19 10:21:44 +00:00
es := qs
2023-11-16 10:09:11 +00:00
var count int64
if err := qs . Count ( & count ) . Error ; err != nil {
2023-12-05 09:21:11 +00:00
logger . Error ( "count err:" , logger . Field ( "err" , err ) )
2023-11-16 10:09:11 +00:00
return resp , err
}
2023-12-19 10:21:44 +00:00
nTotalCount := & struct {
2024-04-17 01:37:02 +00:00
TotalWholesalePrice float64 ` json:"total_wholesale_price" `
TotalStaffCostPrice float64 ` json:"total_staff_cost_price" `
2023-12-19 10:21:44 +00:00
} { }
err := es . Debug ( ) . Select ( "SUM(wholesale_price) as total_wholesale_price, SUM(staff_cost_price) as total_staff_cost_price" ) .
Scan ( & nTotalCount ) . Error
if err != nil {
logger . Error ( "count err:" , logger . Field ( "err" , err ) )
return resp , err
}
2023-11-16 10:09:11 +00:00
//获取库存商品列表
var commodities [ ] ErpStockCommodity
if m . IsExport == 1 {
2023-12-19 10:21:44 +00:00
err := qs . Find ( & commodities ) . Order ( "id DESC" ) . Error
2023-11-16 10:09:11 +00:00
if err != nil && ! errors . Is ( err , RecordNotFound ) {
//logger.Error("dailys err:", err)
return resp , err
}
2024-03-27 10:01:38 +00:00
ErpStockCommodityListSetAge ( commodities )
2023-11-23 12:38:11 +00:00
listExport , err := InventoryDetailListExport ( commodities )
if err != nil {
//logger.Error("list export err:", err)
}
resp . ExportUrl = listExport
2023-11-16 10:09:11 +00:00
} else {
2024-03-16 08:19:12 +00:00
err := qs . Offset ( page * m . PageSize ) . Limit ( m . PageSize ) . Order ( "stock_time DESC,id DESC" ) . Find ( & commodities ) . Error
2023-11-16 10:09:11 +00:00
if err != nil && ! errors . Is ( err , RecordNotFound ) {
//logger.Error("erp commodity list err:", err)
return resp , err
}
ErpStockCommodityListSetAge ( commodities )
resp . List = commodities
}
2024-05-10 01:54:37 +00:00
if len ( commodities ) == 1 && commodities [ 0 ] . State == InAllot && m . ScanCode != "" {
return nil , errors . New ( "该商品在调拨中" )
}
2023-11-28 09:33:38 +00:00
//跟之前保持一致
resp . Total = int ( count )
resp . PageIndex = page + 1
resp . PageSize = m . PageSize
2023-12-19 10:21:44 +00:00
resp . TotalWholesalePrice = int ( nTotalCount . TotalWholesalePrice )
resp . TotalStaffPrice = int ( nTotalCount . TotalStaffCostPrice + nTotalCount . TotalWholesalePrice )
2023-11-28 09:33:38 +00:00
2023-11-16 10:09:11 +00:00
return resp , nil
}
2024-05-23 07:30:20 +00:00
func CheckScanCodeResp ( scanCode string , storeId uint32 , req * ErpStockCommodityListResp ) error {
2024-01-06 08:48:35 +00:00
if req . Total == 1 { // 串码商品, 只有1个; 条码商品, 刚好也只有1个
if req . List [ 0 ] . IMEI == scanCode { // 串码商品, 只有1个
2024-05-23 07:30:20 +00:00
if req . List [ 0 ] . StoreId != storeId && storeId != 0 {
return errors . New ( req . List [ 0 ] . ErpCommodityName + "商品非所选门店库存,请检查" )
}
2024-01-06 08:48:35 +00:00
return nil
}
if req . List [ 0 ] . ErpBarcode == scanCode && req . List [ 0 ] . IMEI != "" {
return errors . New ( "串码类商品,请直接输入串码" )
}
} else { // 条码商品,数量多
var barCodeList [ ] ErpStockCommodity
var imeiLst [ ] ErpStockCommodity
for _ , item := range req . List {
if item . ErpBarcode == scanCode { // 扫码跟商品条码匹配
flag := false
for _ , barCode := range barCodeList {
if barCode . ErpBarcode == item . ErpBarcode {
flag = true
break
}
}
if ! flag { // 遍历后不存在则添加
barCodeList = append ( barCodeList , item )
}
}
if item . IMEI == scanCode { // 扫码跟商品串码匹配
flag := false
for _ , barCode := range imeiLst {
if barCode . IMEI == item . IMEI {
flag = true
break
}
}
if ! flag { // 遍历后不存在则添加
imeiLst = append ( imeiLst , item )
}
}
}
req . List = nil
if len ( barCodeList ) > 0 {
req . List = append ( req . List , barCodeList [ 0 ] )
}
if len ( imeiLst ) > 0 {
req . List = append ( req . List , imeiLst [ 0 ] )
}
req . Total = len ( req . List )
req . TotalStaffPrice = 0
req . TotalWholesalePrice = 0
}
return nil
}
2024-03-16 08:19:12 +00:00
// contains 函数用于检查一个整数切片中是否包含某个值
func contains ( s [ ] int , e int ) bool {
for _ , a := range s {
if a == e {
return true
}
}
return false
}
2023-11-16 10:09:11 +00:00
// buildQueryConditions 根据请求参数构建查询条件
func ( m * ErpStockCommodityListReq ) buildQueryConditions ( qs * gorm . DB ) {
2024-01-06 08:48:35 +00:00
if m . ScanCode != "" {
qs = qs . Where ( "erp_barcode = ? or imei = ?" , m . ScanCode , m . ScanCode )
2024-05-10 01:54:37 +00:00
qs = qs . Where ( "state in (?)" , [ ] uint32 { InStock , InAllot } )
2024-01-06 08:48:35 +00:00
} else {
2024-04-29 10:10:48 +00:00
qs = qs . Where ( "state in (?)" , [ ] uint32 { InStock , InAllot } )
2024-01-06 08:48:35 +00:00
if m . ErpStockId != 0 { //库存id
qs = qs . Where ( "erp_stock_id=?" , m . ErpStockId )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . ErpCommodityId != 0 { //商品id
qs = qs . Where ( "erp_commodity_id=?" , m . ErpCommodityId )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . IsIMEI != 0 { // 是否串码
if m . IsIMEI == 1 { // 查串码数据
qs = qs . Where ( "imei_type != ?" , NoIMEICommodity )
} else if m . IsIMEI == 2 { // 查非串码数据
qs = qs . Where ( "imei_type = ?" , NoIMEICommodity )
}
2023-12-27 11:23:03 +00:00
}
2024-01-06 08:48:35 +00:00
if m . SerialNumber != "" { //商品编号
qs = qs . Where ( "commodity_serial_number=?" , m . SerialNumber )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . CommodityName != "" { //商品名称
2024-04-22 01:51:41 +00:00
//qs = qs.Where("erp_commodity_name LIKE ?", "%"+m.CommodityName+"%")
qs = qs . Where ( "erp_commodity_name = ?" , m . CommodityName )
2024-01-06 08:48:35 +00:00
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . ErpCategoryId != 0 { //商品分类id
qs = qs . Where ( "erp_category_id=?" , m . ErpCategoryId )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . IMEI != "" { //商品串码
qs = qs . Where ( "imei=?" , m . IMEI )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . StoreId != 0 { //门店编号
qs = qs . Where ( "store_id=?" , m . StoreId )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . SupplierId != 0 { //供应商id
qs = qs . Where ( "erp_supplier_id=?" , m . SupplierId )
}
2023-11-24 09:09:24 +00:00
2024-03-16 08:19:12 +00:00
defaultStates := [ ] int { 1 , 4 }
if m . State != 0 && contains ( defaultStates , int ( m . State ) ) {
2024-01-06 08:48:35 +00:00
qs = qs . Where ( "state=?" , m . State )
2024-03-16 08:19:12 +00:00
} else {
qs = qs . Where ( "state IN (?)" , defaultStates )
2024-01-06 08:48:35 +00:00
}
2023-11-16 10:09:11 +00:00
2024-04-22 01:51:41 +00:00
if m . OriginalSn != "" { //首次入库订单编号
qs = qs . Where ( "original_sn=?" , m . OriginalSn )
2024-01-06 08:48:35 +00:00
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . StorageType != 0 { //首次入库方式
qs = qs . Where ( "storage_type=?" , m . StorageType )
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . StockTimeStart != "" { //最近入库开始时间
startTime , err := time . Parse ( QueryTimeFormat , m . StockTimeStart )
if err == nil {
qs = qs . Where ( "stock_time>?" , startTime )
} else {
//logger.Error("stock time start parse err:", err)
}
2023-11-08 03:51:33 +00:00
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . StockTimeEnd != "" { //最近入库结束时间
endTime , err := time . Parse ( QueryTimeFormat , m . StockTimeEnd )
if err == nil {
qs = qs . Where ( "stock_time<?" , endTime )
} else {
//logger.Error("stock time end parse err:", err)
}
2023-11-08 03:51:33 +00:00
}
2023-11-16 10:09:11 +00:00
2024-01-06 08:48:35 +00:00
if m . Age != 0 { //最近库龄
qs = qs . Where ( "stock_time<?" , time . Now ( ) . AddDate ( 0 , 0 , int ( m . Age ) * ( - 1 ) ) )
}
2023-11-08 03:51:33 +00:00
2024-01-06 08:48:35 +00:00
if m . AllAge != 0 { //总库龄
qs = qs . Where ( "first_stock_time<?" , time . Now ( ) . AddDate ( 0 , 0 , int ( m . AllAge ) * ( - 1 ) ) )
}
2023-11-08 03:51:33 +00:00
}
}
2023-11-17 10:07:01 +00:00
2023-11-24 09:09:24 +00:00
// SetStockCommodityState 更新库存状态
2024-06-05 02:50:15 +00:00
func SetStockCommodityState ( c * gin . Context , id uint32 ) error { //更新库存状态为5, 并同步扣减库存数量
2023-12-11 08:21:21 +00:00
begin := orm . Eloquent . Begin ( )
// 查询库存详情
var commodityInfo ErpStockCommodity
err := orm . Eloquent . Table ( "erp_stock_commodity" ) .
Raw ( "SELECT * FROM erp_stock_commodity WHERE id = ?" , id ) .
Scan ( & commodityInfo ) . Error
if err != nil {
logger . Error ( "查询库存商品信息失败" , logger . Field ( "err" , err ) )
return err
2023-11-17 10:07:01 +00:00
}
2023-12-11 08:21:21 +00:00
2024-06-05 02:50:15 +00:00
// 校验是否有入参门店权限
err = AuthUserStore ( c , commodityInfo . StoreId )
if err != nil {
return err
}
2023-12-11 08:21:21 +00:00
// 查询库存数据
var record ErpStock
err = orm . Eloquent . Table ( "erp_stock" ) .
Where ( "erp_commodity_name = ? and store_id = ?" ,
commodityInfo . ErpCommodityName , commodityInfo . StoreId ) . First ( & record ) . Error
if err != nil {
logger . Error ( "查询库存数量失败" , logger . Field ( "err" , err ) )
return err
}
2024-04-29 10:10:48 +00:00
// 更新商品库存详情表状态为:系统出库
2023-12-11 08:21:21 +00:00
if err := begin . Model ( & ErpStockCommodity { } ) . Where ( "id=?" , id ) . Updates ( map [ string ] interface { } {
2024-04-24 08:53:14 +00:00
"state" : SystemOut } ) . Error ; err != nil {
2023-11-17 10:07:01 +00:00
return fmt . Errorf ( "[update err]: %v" , err )
}
2023-12-11 08:21:21 +00:00
if record . Count > 0 {
// 扣减商品库存数量
err = begin . Model ( & record ) . Update ( "count" , record . Count - 1 ) . Error
if err != nil {
logger . Error ( "扣减库存数量失败" , logger . Field ( "err" , err ) )
return err
}
}
err = begin . Commit ( ) . Error
if err != nil {
begin . Rollback ( )
logger . Error ( "出库事务失败" , logger . Field ( "err" , err ) )
return err
}
2023-11-17 10:07:01 +00:00
return nil
}
type BatchPrintInfo struct {
ErpCommodityName string ` json:"erp_commodity_name" binding:"required" ` // 商品名称
RetailPrice uint32 ` json:"retail_price" binding:"required" ` // 指导零售价
IMEI string ` json:"imei" binding:"required" ` // 商品串码
}
type BatchPrintInfoReq struct {
PrintListInfo [ ] * BatchPrintInfo ` json:"print_list_info" binding:"required" `
}
2023-11-24 09:09:24 +00:00
// BatchPrint 批量打印标签
2023-11-17 10:07:01 +00:00
func BatchPrint ( req * BatchPrintInfoReq ) error {
return nil
}
func StringToFloat ( req string ) ( float64 , error ) {
if req == "" {
return 0 , nil
}
return strconv . ParseFloat ( req , 64 )
}
2023-11-23 12:38:11 +00:00
2024-04-17 01:37:02 +00:00
func PercentFloatStringToFloat64 ( s string ) float64 {
u := float64 ( 0 )
2023-11-24 09:09:24 +00:00
if s != "" {
s = strings . ReplaceAll ( s , "%" , "" )
}
f , err := strconv . ParseFloat ( s , 64 )
if err != nil {
//logger.Error("parse float err:", err)
return u
}
2024-04-17 01:37:02 +00:00
u = f * 100
return tools . RoundToTwoDecimalPlaces ( u )
2023-11-24 09:09:24 +00:00
}
func IntStringToUin32 ( s string ) uint32 {
u := uint32 ( 0 )
if s != "" {
s = strings . ReplaceAll ( s , "%" , "" )
}
i , err := strconv . Atoi ( s )
if err != nil {
//logger.Error("parse float err:", err)
return u
}
u = uint32 ( i )
return u
2023-11-23 12:38:11 +00:00
}
func NewStockImporter ( ) * StockImporter {
return & StockImporter {
CensusMap : make ( map [ uint32 ] map [ uint32 ] uint32 , 0 ) ,
CommodityMap : make ( map [ uint32 ] * ErpCommodity ) ,
StoreMap : make ( map [ uint32 ] string , 0 ) ,
Inventories : make ( [ ] * ErpInventoryStock , 0 ) ,
}
}
2023-11-24 09:09:24 +00:00
// UpdateStockCommodityRemark 更新库存商品备注信息
func UpdateStockCommodityRemark ( id int , remark string ) error {
if remark == "" {
return nil
}
if err := orm . Eloquent . Model ( & ErpStockCommodity { } ) . Where ( "id=?" , id ) . Updates ( map [ string ] interface { } {
"remark" : remark } ) . Error ; err != nil {
return fmt . Errorf ( "[update err]: %v" , err )
}
return nil
}
2024-01-06 08:48:35 +00:00
func GetCommodity ( id uint32 ) ( * ErpCommodity , error ) {
var erpCommodity ErpCommodity
err := orm . Eloquent . Table ( "erp_commodity" ) . Where ( "id=?" , id ) . Find ( & erpCommodity ) . Error
if err != nil {
logger . Errorf ( "err:" , logger . Field ( "err" , err ) )
return & erpCommodity , err
}
return & erpCommodity , nil
}
// CheckAndConvertBarcode 校验输入的条码数据是否正确
func CheckAndConvertBarcode ( input string ) ( string , error ) {
// 1. 检查总长度不超过100字符
if utf8 . RuneCountInString ( input ) > 100 {
return "" , errors . New ( "error: Total length exceeds 100 characters" )
}
// 2. 转换中文逗号为英文逗号
input = strings . ReplaceAll ( input , ", " , "," )
// 3. 两个逗号之前需要有数据,不能是空格或无数据
parts := strings . Split ( input , "," )
for _ , part := range parts {
trimmedPart := strings . TrimSpace ( part )
if trimmedPart == "" {
return "" , errors . New ( "error: Two commas should have data in between" )
}
}
// 4.判断逗号隔开的数据数据库是否已存在
for _ , part := range parts {
// 检查生成的条码是否已存在
exist , err := QueryRecordExist ( fmt . Sprintf ( "SELECT * FROM erp_commodity WHERE FIND_IN_SET(%s, erp_barcode) > 0" , part ) )
if err != nil {
logger . Error ( "exist sn err" )
}
if exist {
return "" , errors . New ( "[" + part + "]" + "该条码已存在,请检查" )
}
}
// 如果通过所有检查,返回处理后的字符串
return input , nil
}
2024-02-05 06:11:48 +00:00
// CheckBarcodeById 校验输入的条码数据是否正确
func CheckBarcodeById ( input string , commodityId uint32 ) ( string , error ) {
// 1. 检查总长度不超过100字符
if utf8 . RuneCountInString ( input ) > 100 {
return "" , errors . New ( "error: Total length exceeds 100 characters" )
}
// 2. 转换中文逗号为英文逗号
input = strings . ReplaceAll ( input , ", " , "," )
// 3. 两个逗号之前需要有数据,不能是空格或无数据
parts := strings . Split ( input , "," )
for _ , part := range parts {
trimmedPart := strings . TrimSpace ( part )
if trimmedPart == "" {
return "" , errors . New ( "error: Two commas should have data in between" )
}
}
// 4.判断逗号隔开的数据数据库是否已存在
for _ , part := range parts {
// 检查生成的条码是否已存在
exist , err := QueryRecordExist ( fmt . Sprintf ( "SELECT * FROM erp_commodity WHERE FIND_IN_SET(%s, erp_barcode) > 0" , part ) )
if err != nil {
logger . Error ( "exist sn err" )
}
if exist {
var commodityInfo ErpCommodity
err = orm . Eloquent . Table ( "erp_commodity" ) . Where ( "id=?" , commodityId ) . Find ( & commodityInfo ) . Error
if err != nil {
logger . Errorf ( "get erp_commodity err:" , err )
return "" , err
}
if commodityInfo . ErpBarcode == input {
return input , nil
} else {
return "" , errors . New ( "[" + part + "]" + "该条码已存在,请检查" )
}
}
}
// 如果通过所有检查,返回处理后的字符串
return input , nil
}
2024-01-06 08:48:35 +00:00
// GenerateBarcode 系统生成条码
func GenerateBarcode ( categoryCode uint32 ) ( string , error ) {
category := new ( Category )
err := orm . Eloquent . Table ( "erp_category" ) . Where ( "id=?" , categoryCode ) . Find ( category ) . Error
if err != nil {
logger . Errorf ( "get erp category err:" , err )
return "" , err
}
max := 1
for {
if max > 5 {
logger . Error ( "create Barcode err" )
return "" , errors . New ( "create Barcode err" )
}
// 生成当前日期的六位数
dateCode := time . Now ( ) . Format ( "060102" )
// 生成三位随机数
randomNumber := fmt . Sprintf ( "%03d" , rand . Intn ( 1000 ) )
// 组合生成的条码
barcode := fmt . Sprintf ( "%03s%s%s" , category . Number [ : 3 ] , dateCode , randomNumber )
// 检查生成的条码是否已存在
exist , err := QueryRecordExist ( fmt . Sprintf ( "SELECT * FROM erp_commodity WHERE FIND_IN_SET(%s, erp_barcode) > 0" , barcode ) )
if err != nil {
logger . Error ( "exist sn err" )
}
if ! exist {
return barcode , nil
}
}
}
// GetCodeList 查询输入的条码或串码数据
func GetCodeList ( req * QueryCodeReq ) ( * QueryCodeResp , error ) {
resp := & QueryCodeResp {
PageIndex : req . PageIndex ,
PageSize : req . PageSize ,
}
page := req . PageIndex - 1
if page < 0 {
page = 0
}
if req . PageSize == 0 {
req . PageSize = 10
}
var commodities [ ] ErpStockCommodity
orderStr := fmt . Sprintf ( "CASE WHEN imei LIKE '%%%s%%' THEN 1 ELSE 2 END" , req . ScanCode )
qs := orm . Eloquent . Debug ( ) . Table ( "erp_stock_commodity" ) .
Where ( "imei LIKE ? OR erp_barcode LIKE ?" , "%" + req . ScanCode + "%" , "%" + req . ScanCode + "%" )
2024-01-31 10:00:16 +00:00
2024-01-06 08:48:35 +00:00
es := qs
err := qs . Order ( orderStr ) . Offset ( page * req . PageSize ) . Limit ( req . PageSize ) . Find ( & commodities ) . Error
if err != nil && err != RecordNotFound {
logger . Error ( "commodityList err" , logger . Field ( "err" , err ) )
return resp , err
}
var count int64
err = es . Count ( & count ) . Error
if err != nil {
logger . Error ( "commodityList count err" , logger . Field ( "err" , err ) )
return resp , err
}
var stockList [ ] string
var strCode string
for _ , commodity := range commodities {
if commodity . IMEI != "" && strings . Contains ( commodity . IMEI , req . ScanCode ) { // 串码非空且包含查找的数据
strCode = commodity . IMEI
2024-05-10 01:54:37 +00:00
//} else if commodity.IMEI != "" && strings.Contains(commodity.ErpBarcode, req.ScanCode) { // 串码不为空,但条码包含扫码数据
} else if commodity . IMEI != "" && commodity . ErpBarcode == req . ScanCode { // 串码不为空,但条码包含扫码数据
2024-01-31 10:00:16 +00:00
return nil , errors . New ( "串码类商品请直接输入串码" )
} else {
2024-01-06 08:48:35 +00:00
strCode = commodity . ErpBarcode
}
stockList = append ( stockList , strCode )
}
//跟之前保持一致
resp . Total = len ( stockList )
resp . PageIndex = page + 1
resp . PageSize = req . PageSize
resp . List = stockList
2024-03-16 08:19:12 +00:00
return removeDuplicates ( resp ) , nil
}
func removeDuplicates ( resp * QueryCodeResp ) * QueryCodeResp {
// 创建一个 map 用来记录已经出现过的字符串
uniqueMap := make ( map [ string ] bool )
// 新建一个切片用来保存不重复的数据
var uniqueList [ ] string
// 遍历原始的 List
for _ , item := range resp . List {
// 如果这个字符串已经在 map 中存在,说明重复,跳过
if _ , ok := uniqueMap [ item ] ; ok {
continue
}
// 否则,将其添加到新的切片中,并在 map 中标记为已经出现过
uniqueList = append ( uniqueList , item )
uniqueMap [ item ] = true
}
// 构建新的 QueryCodeResp 结构体
newResp := & QueryCodeResp {
List : uniqueList ,
Total : len ( uniqueList ) ,
PageIndex : resp . PageIndex ,
PageSize : resp . PageSize ,
}
return newResp
2024-01-06 08:48:35 +00:00
}
2024-02-20 09:59:43 +00:00
func GetErpCommodityMap ( ids [ ] uint32 ) ( map [ uint32 ] ErpCommodity , error ) {
commodityMap := make ( map [ uint32 ] ErpCommodity , 0 )
if len ( ids ) == 0 {
return commodityMap , nil
}
var commodities [ ] ErpCommodity
err := orm . Eloquent . Table ( "erp_commodity" ) . Where ( "id IN (?)" , ids ) . Find ( & commodities ) . Error
if err != nil {
logger . Error ( "commodities err:" , logger . Field ( "err" , err ) )
return commodityMap , err
}
for i , _ := range commodities {
commodityMap [ commodities [ i ] . ID ] = commodities [ i ]
}
return commodityMap , nil
}
2024-04-22 01:51:41 +00:00
type CommodityCreateRequest struct {
Name string ` json:"name" binding:"required" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" binding:"required" ` // 商品分类id
IsIMEI uint32 ` json:"is_imei" binding:"required" ` // 是否串码: 1-串码类 2-非串码
ErpBarcode string ` json:"erp_barcode" ` // 商品条码
IMEIType uint32 ` json:"imei_type" ` // 系统生成串码: 2-是(系统生成) 3-否(手动添加)
ErpSupplierId uint32 ` json:"erp_supplier_id" binding:"required" ` // 主供应商
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" ` // 会员优惠
Origin string ` json:"origin" ` // 产地
Remark string ` json:"remark" gorm:"type:varchar(512)" ` // 备注
}
type CommodityEditRequest struct {
Id uint32 ` json:"id" binding:"required" ` // 商品id
Name string ` json:"name" binding:"required" ` // 商品名称
ErpCategoryId uint32 ` json:"erp_category_id" binding:"required" ` // 商品分类id
ErpBarcode string ` json:"erp_barcode" ` // 商品条码
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 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" ` // 会员优惠
Origin string ` json:"origin" ` // 产地
Remark string ` json:"remark" gorm:"type:varchar(512)" ` // 备注
}
type CommodityDetailRequest struct {
ErpCommodityId uint32 ` json:"erp_commodity_id" ` // 商品id
SerialNumber string ` json:"serial_number" ` // 商品编号
}
type CommodityDelRequest struct {
ErpCommodityId uint32 ` json:"erp_commodity_id" binding:"required" ` // 商品id
}