mh_goadmin_server/app/admin/models/commodity.go

1392 lines
45 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package models
import (
"errors"
"fmt"
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
"golang.org/x/sync/errgroup"
"gorm.io/gorm"
"strconv"
"strings"
"sync"
"time"
)
// ErpStock 库存表
//
//go:generate goqueryset -in commodity.go
type ErpStock struct {
Model
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-串码(手动添加)
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
Count uint32 `json:"count"` // 数量
DispatchCount uint32 `json:"dispatch_count"` // 调拨中数量
Commodities []ErpStockCommodity `json:"commodities" gorm:"-"`
}
// ErpStockCommodity 库存详情
type ErpStockCommodity struct {
Model
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"` // 分类名称
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"` // 最近入库时间
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价
State uint32 `json:"state"` // 状态:1-在库 2-已售 3-采购退货 4-调拨中
Count uint32 `json:"count"` // 数量
StorageType uint32 `json:"storage_type"` // 入库方式1-系统入库 2-采购入库
FirstStockTime time.Time `json:"first_stock_time"` // 首次入库时间
StockSn string `json:"stock_sn"` // 库存订单编号
OriginalSn string `json:"original_sn" gorm:"index"` // 首次入库订单编号
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:"-"` // 总库龄
//Commodity ErpCommodity `json:"commodity" gorm:"-"`
}
// ErpCommodity 商品表
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"` // 商品分类名称
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"` // 主供应商名称
RetailPrice uint32 `json:"retail_price"` // 指导零售价
MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice uint32 `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)"` // 备注
ErpCategory *ErpCategory `json:"erp_category" gorm:"-"`
}
// gen:qs
type ErpCategory struct {
Model
Name string `json:"name"` // 名称
Priority string `json:"priority"` // 分类
Number uint32 `json:"number"`
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
}
// gen:qs
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
}
// gen:qs
type ErpInventoryStock struct {
Model
StoreId uint32 `json:"store_id" gorm:"index"`
StoreName string `json:"store_name"`
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"`
ErpCommodityName string `json:"erp_commodity_name"`
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"`
ErpCategoryName string `json:"erp_category_name"`
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"`
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
RetailPrice uint32 `json:"retail_price"`
MinRetailPrice uint32 `json:"min_retail_price"`
Count uint32 `json:"count"`
Sn string `json:"sn" gorm:"index"`
//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
}
// gen:qs
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"`
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
IMEI string `json:"imei"`
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"`
ErpSupplierName string `json:"erp_supplier_name"`
StockTime time.Time `json:"stock_time"`
RetailPrice uint32 `json:"retail_price"`
MinRetailPrice uint32 `json:"min_retail_price"`
StaffCostPrice uint32 `json:"staff_cost_price"`
WholesalePrice uint32 `json:"wholesale_price"`
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
}
func (c *ErpCommodity) IdInit() {
if c.ErpCategoryId != 0 {
if c.ErpCategory == nil {
category, err := GetErpCategory(c.ErpCategoryId)
if err != nil {
//logger.Error("get erp category err:", err)
return
}
c.ErpCategory = category
}
c.ErpCategoryName = c.ErpCategory.Name
}
if c.ErpSupplierId != 0 {
supplier, err := GetErpSupplier(c.ErpSupplierId)
if err != nil {
//logger.Error("get erp category err:", err)
} else {
c.ErpSupplierName = supplier.Name
}
}
}
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
}
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
}
func (c *ErpCommodity) SetErpCategory() error {
if c.ErpCategoryId != 0 {
category, err := GetErpCategory(c.ErpCategoryId)
if err != nil {
//logger.Error("get erp category err:", err)
return err
}
c.ErpCategory = category
return nil
}
return errors.New("erp category id null")
}
type ErpCommodityListReq struct {
SerialNumber string `json:"serial_number"` // 商品编号
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryId uint32 `json:"erp_category_id"` // 商品分类id
IMEI string `json:"imei"` // 串码
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
PageNum int `json:"page_num"` // 页码
PageSize int `json:"page_size"` // 每页展示数据条数
IsExport uint32 `json:"is_export"` // 1-导出
}
type ErpCommodityListResp struct {
List []ErpCommodity `json:"list"`
Total int `json:"total"` // 总页数
PageNum int `json:"page_num"` // 页码
PageSize int `json:"page_size"` // 每页展示数据条数
ExportUrl string `json:"export_url"` // 1-导出
}
func (m *ErpCommodityListReq) List() (*ErpCommodityListResp, error) {
resp := &ErpCommodityListResp{
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.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 {
qs = qs.Where("erp_category_id=?", m.ErpCategoryId)
}
if m.ErpSupplierId != 0 {
qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId)
}
var count int64
err := qs.Count(&count).Error
if err != nil {
//logger.Error("count err:", err)
return resp, err
}
resp.Total = int(count)/m.PageSize + 1
var commodities []ErpCommodity
if m.IsExport == 1 {
err = qs.Order("id DESC").Find(&commodities).Error
if err != nil && err != RecordNotFound {
//logger.Error("dailys err:", err)
return resp, err
}
listExport, err := ErpCommodityListExport(commodities)
if err != nil {
//logger.Error("list export err:", err)
}
resp.ExportUrl = listExport
} else {
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
if err != nil && err != RecordNotFound {
//logger.Error("erp commodity list err:", err)
return resp, err
}
resp.List = commodities
}
return resp, nil
}
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
//err := qs.Count(&count).Error
//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
}
var ErpCommodityFileExcelCols = []string{"category_1", "category_2", "name", "is_imei", "erp_supplier_name",
"brokerage_1_string", "brokerage_2_string", "retail_price_string", "min_retail_price_string",
"staff_cost_price_string", "wholesale_price_string", "origin", "remark"}
type ErpCommodityFileExcel struct {
Category1 string `json:"category_1"`
Category2 string `json:"category_2"`
IsIMEI string `json:"is_imei"`
RetailPriceString string `json:"retail_price_string"`
MinRetailPriceString string `json:"min_retail_price_string"`
StaffCostPriceString string `json:"staff_cost_price_string"`
WholesalePriceString string `json:"wholesale_price_string"`
Brokerage1String string `json:"brokerage_1_string"`
Brokerage2String string `json:"brokerage_2_string"`
Code string `json:"code"`
ErpCommodity
}
func (e *ErpCommodityFileExcel) Processing() {
if e.IsIMEI == "是" {
e.IMEIType = 2
} else if e.IsIMEI == "否" {
e.IMEIType = 1
}
e.RetailPrice = PercentFloatStringToUin32(e.RetailPriceString)
e.MinRetailPrice = PercentFloatStringToUin32(e.MinRetailPriceString)
e.StaffCostPrice = PercentFloatStringToUin32(e.StaffCostPriceString)
e.WholesalePrice = PercentFloatStringToUin32(e.WholesalePriceString)
e.Brokerage1 = PercentFloatStringToFloat(e.Brokerage1String)
e.Brokerage2 = PercentFloatStringToFloat(e.Brokerage2String)
}
func PercentFloatStringToUin32(s string) uint32 {
u := uint32(0)
if s != "" {
s = strings.ReplaceAll(s, "%", "")
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
//logger.Error("parse float err:", err)
return u
}
u = uint32(f * 100)
return u
}
func PercentFloatStringToFloat(s string) float64 {
//u := uint32(0)
if s != "" {
s = strings.ReplaceAll(s, "%", "")
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
//logger.Error("parse float err:", err)
return f
}
//u = uint32(f * 100)
return f
}
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
}
type ErpCategorySub struct {
Id uint32 `json:"id"`
Name string `json:"name"`
FullNum uint32 `json:"full_num"`
SubMap map[string]ErpCategory
//UnCodeMap map[string]uint32
}
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
}
func GetErpCategorySubMap() (map[string]*ErpCategorySub, error) {
var erpCategories []ErpCategory
err := orm.Eloquent.Table("erp_category").Find(&erpCategories).Error
if err != nil {
//logger.Error("erp categories err:", err)
return nil, err
}
categoriesMaps := make(map[string]*ErpCategorySub, 0)
pidMap := make(map[uint32]string, 0)
for i, _ := range erpCategories {
if erpCategories[i].Level == 1 {
if erpCategories[i].Pid != 0 {
logger.Error("erp categories level 1 pid gt 0")
return nil, errors.New("erp categories level 1 pid gt 0")
}
if _, ok := categoriesMaps[erpCategories[i].Name]; !ok {
categoriesMaps[erpCategories[i].Name] = &ErpCategorySub{
Id: erpCategories[i].ID,
Name: erpCategories[i].Name,
FullNum: erpCategories[i].FullNum,
SubMap: make(map[string]ErpCategory, 0),
}
pidMap[erpCategories[i].ID] = erpCategories[i].Name
}
}
}
for i, _ := range erpCategories {
if erpCategories[i].Level == 2 {
if erpCategories[i].Pid == 0 {
logger.Error("erp categories level 2 pid is 0")
return nil, errors.New("erp categories level 2 pid is 0")
}
name, ok := pidMap[erpCategories[i].Pid]
if ok {
categoriesMaps[name].SubMap[erpCategories[i].Name] = erpCategories[i]
}
}
}
return categoriesMaps, nil
}
func ErpCategoryCreate(name string, pid uint32) (*ErpCategory, error) {
category := &ErpCategory{
Number: 0,
State: 2,
Level: 1,
Pid: pid,
}
var (
pCategory ErpCategory
sCategory ErpCategory
)
qs := orm.Eloquent.Table("erp_category")
if category.Pid != 0 {
category.Level = 2
qs = qs.Where("id=?", pid)
err := orm.Eloquent.Table("erp_category").Where("pid=?", pid).Order("id DESC").Limit(1).Find(&sCategory).Error
if err != nil {
//logger.Error("s category err:", err)
return category, err
}
} else {
qs = qs.Where("level=1")
}
err := qs.Order("id DESC").Limit(1).Find(&pCategory).Error
if err != nil && err != RecordNotFound {
//logger.Error("cat erp commodity err:", err)
return category, err
}
if category.Level == 1 {
category.Number = pCategory.Number + 1
category.FullNum = pCategory.FullNum + 1000
category.Name = fmt.Sprintf("%03d%s", category.Number, name)
} else {
category.Number = sCategory.Number + 1
category.Name = fmt.Sprintf("%03d-%03d%s", pCategory.Number, category.Number, name)
category.FullNum = pCategory.FullNum + category.Number
}
err = orm.Eloquent.Create(category).Error
if err != nil {
//logger.Error("create commodity err:", err)
return category, err
}
return category, nil
}
type ErpSupplierListResp struct {
List []ErpSupplier `json:"list"`
Total int `json:"total"`
PageNum int `json:"page_num"`
PageSize int `json:"page_size"`
ExportUrl string `json:"export_url"`
}
var ErpStockFileExcelCols = []string{"store_name", "erp_commodity_name", "erp_category_name", "serial_number",
"is_imei", "imei", "erp_supplier_name", "stock_time_string", "retail_price_string",
"min_retail_price_string", "staff_cost_price_string", "wholesale_price_string", "count_string",
}
var EsfLock sync.Mutex
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"`
StaffCostPriceString string `json:"staff_cost_price_string"`
WholesalePriceString string `json:"wholesale_price_string"`
CountString string `json:"count_string"`
//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 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),
}
}
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
e.RetailPrice = PercentFloatStringToUin32(e.RetailPriceString)
e.MinRetailPrice = PercentFloatStringToUin32(e.MinRetailPriceString)
e.StaffCostPrice = PercentFloatStringToUin32(e.StaffCostPriceString)
e.WholesalePrice = PercentFloatStringToUin32(e.WholesalePriceString)
}
func (m *StockImporter) ErpStockFileExcelListProcessing(list []ErpStockFileExcel) error {
//allCategoriesMap, err := GetErpCategorySubMap()
//if err != nil {
// logger.Error("all categories map err:", err)
// return
//}
// 加锁
//m.CensusMap = make(map[uint32]map[uint32]uint32, 0)
storeNameMap := make(map[string]uint32, 0)
erpCommodityMap := make(map[string]*ErpCommodity, 0)
erpCategoryNameMap := make(map[string]uint32, 0)
erpSupplierNameMap := make(map[string]uint32, 0)
storeNames := make([]string, 0, len(list))
erpCommodityNames := make([]string, 0, len(list))
erpCategoryNames := make([]string, 0, len(list))
erpSupplierNames := make([]string, 0, len(list))
for i, _ := range list {
list[i].Processing()
_, ok1 := storeNameMap[list[i].StoreName]
if !ok1 {
storeNames = append(storeNames, list[i].StoreName)
}
_, ok2 := erpCommodityMap[list[i].ErpCommodityName]
if !ok2 {
erpCommodityNames = append(erpCommodityNames, list[i].ErpCommodityName)
}
_, ok3 := erpCategoryNameMap[list[i].ErpCategoryName]
if !ok3 {
erpCategoryNames = append(erpCategoryNames, list[i].ErpCategoryName)
}
_, ok4 := erpSupplierNameMap[list[i].ErpSupplierName]
if !ok4 {
erpSupplierNames = append(erpSupplierNames, list[i].ErpSupplierName)
}
storeNameMap[list[i].StoreName] = uint32(0)
erpCommodityMap[list[i].ErpCommodityName] = nil
erpCategoryNameMap[list[i].ErpCategoryName] = uint32(0)
erpSupplierNameMap[list[i].ErpSupplierName] = uint32(0)
}
var stores []Store
err := orm.Eloquent.Table("store").Where("name IN (?)", storeNames).Find(&stores).Error
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 erpCategories []ErpCategory
err = orm.Eloquent.Table("erp_category").Where("name IN (?)", erpCategoryNames).Find(&erpCategories).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
if err != nil && err != RecordNotFound {
//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 erpCategories {
erpCategoryNameMap[erpCategories[i].Name] = erpCategories[i].ID
}
for i, _ := range erpSuppliers {
erpSupplierNameMap[erpSuppliers[i].Name] = erpSuppliers[i].ID
}
//categoryCommodityNumMap := make(map[uint32]uint32, 0)
//for i, _ := range erpCommodities {
// var commodity ErpCommodity
// err = orm.Eloquent.Table("erp_commodity").Where("erp_category_id=?", erpCommodities[i].ErpCategoryId).
// Order("id DESC").Limit(1).Find(&commodity).Error
// if err != nil {
// logger.Error("commodity err:", err)
// }
// categoryCommodityNumMap[erpCommodities[i].ErpCategoryId] = commodity.Number
//}
nowTime := time.Now()
for i, _ := range list {
v1, ok1 := storeNameMap[list[i].StoreName]
v2, ok2 := erpCommodityMap[list[i].ErpCommodityName]
v3, ok3 := erpCategoryNameMap[list[i].ErpCategoryName]
v4, ok4 := erpSupplierNameMap[list[i].ErpSupplierName]
if !ok1 {
logger.Error("store name err")
return errors.New("store name err")
}
if !ok2 && v2 == nil {
logger.Error("erp commodity name err")
return errors.New("erp commodity name err")
}
if !ok3 {
logger.Error("erp category name err")
return errors.New("erp category name err")
}
if !ok4 {
logger.Error("erp supplier name err")
return errors.New("erp supplier name err")
}
list[i].StoreId = v1
list[i].ErpCommodityId = v2.ID
list[i].CommoditySerialNumber = v2.SerialNumber
list[i].ErpCategoryId = v3
list[i].ErpSupplierId = v4
list[i].State = 1
list[i].StorageType = 1
list[i].FirstStockTime = nowTime
//v6, ok6 := m.CommodityMap[v2]
_, ok5 := m.CensusMap[list[i].StoreId]
if ok5 {
m.CensusMap[list[i].StoreId][list[i].ErpCommodityId] += list[i].Count
} else {
m.CensusMap[list[i].StoreId] = map[uint32]uint32{list[i].ErpCommodityId: list[i].Count}
}
//v5, ok5 := categoryCommodityNumMap[list[i].ErpCategoryId]
//if !ok5 {
// logger.Error("category commodity num err")
// return errors.New("category commodity num err")
//}
}
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)
}
}
}
return nil
}
func (m *StockImporter) ErpInventoryStockCreate(gdb *gorm.DB, list []ErpStockFileExcel) error {
defer func() {
if err := recover(); err != nil {
//logger.Error("err:", err)
return
}
}()
inventoryStockIdMap := make(map[string]uint32, 0)
for _, inventory := range m.Inventories {
//err := gdb.Create(inventory).Error
err := orm.Eloquent.Create(inventory).Error
if err != nil {
//logger.Error("create erp inventory stock err:", err)
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
}
//go func() {
// //inventoryStockIdMap := make(map[string]uint32, 0)
// //for _, inventory := range m.Inventories {
// // //err := gdb.Create(inventory).Error
// // err := orm.Eloquent.Create(inventory).Error
// // if err != nil {
// // logger.Error("create erp inventory stock err:", err)
// // return
// // }
// // inventoryStockIdMap[fmt.Sprintf("%d_%d", inventory.StoreId, inventory.ErpCommodityId)] = inventory.ID
// //}
//
// //stock := ErpStockFileExcel{}
// //ErpInventoryStock
// 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,
// SerialNumber: list[i].SerialNumber,
// 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
// err := orm.Eloquent.Create(inventoryCommodity).Error
// if err != nil {
// logger.Error("create erp inventory stock commodity err:", err)
// return
// }
// }
//
// }
//}()
return nil
}
func ErpStockCommodityToInventory(inventoryStockIdMap map[string]uint32, list []ErpStockFileExcel) []*ErpInventoryStockCommodity {
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 {
// logger.Error("create erp inventory stock commodity err:", err)
// return inventoryList
//}
}
}
return inventoryList
}
func ErpCommodityListExport(list []ErpCommodity) (string, error) {
file := excelize.NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")
if err != nil {
fmt.Println(err)
}
url := "http://39.108.188.218:8000/img/export/"
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
}
func ErpCategoryListExport(list []ErpCategory) (string, error) {
file := excelize.NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")
if err != nil {
fmt.Println(err)
}
url := "http://39.108.188.218:8000/img/export/"
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 {
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"` // 门店编号
PageNum int `json:"page_num"` // 页面条数
PageSize int `json:"page_size"` // 页码
//IsExport uint32 `json:"is_export"` // 1-导出
}
type ErpStockListResp struct {
List []ErpStock `json:"list"`
Total int `json:"total"`
PageNum int `json:"page_num"`
PageSize int `json:"page_size"`
ExportUrl string `json:"export_url"`
}
func (m *ErpStockListReq) List() (*ErpStockListResp, error) {
resp := &ErpStockListResp{
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_stock")
if m.SerialNumber != "" {
qs = qs.Where("commodity_serial_number=?", m.SerialNumber)
}
if m.CommodityName != "" {
qs = qs.Where("name Like %" + m.CommodityName + "%")
}
if m.ErpCategoryId != 0 {
qs = qs.Where("erp_category_id=?", m.ErpCategoryId)
}
if m.StoreId != 0 {
qs = qs.Where("store_id=?", m.StoreId)
}
switch m.StockType {
case 2:
qs = qs.Where("count > 0")
case 3:
qs = qs.Where("count = 0")
}
var count int64
if err := qs.Count(&count).Error; err != nil {
//logger.Error("count err:", err)
return resp, err
}
resp.Total = int(count)/m.PageSize + 1
var commodities []ErpStock
err := qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
if err != nil && !errors.Is(err, RecordNotFound) {
//logger.Error("erp commodity list err:", err)
return resp, err
}
resp.List = commodities
return resp, nil
}
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
}
}
func ErpStockCommodityListSetCommodity(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
}
}
// ErpStockCommodityListReq 库存详情接口请求参数
type ErpStockCommodityListReq struct {
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
IMEI string `json:"imei"` // 串码
StoreId uint32 `json:"store_id"` // 门店编号
SupplierId uint32 `json:"supplier_id"` // 供应商id
State uint32 `json:"state"` // 库存状态:1-在库 2-已售 3-采购退货 4-调拨中
Sn string `json:"sn"` // 首次入库订单编号
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"` // 总库龄
PageNum int `json:"page_num"` // 页面条数
PageSize int `json:"page_size"` // 页码
IsExport uint32 `json:"is_export"` // 是否导出excel1-导出
}
type ErpStockCommodityListResp struct {
List []ErpStockCommodity `json:"list"`
Total int `json:"total"`
PageNum int `json:"page_num"`
PageSize int `json:"page_size"`
ExportUrl string `json:"export_url"`
}
func (m *ErpStockCommodityListReq) GetDetailList() (*ErpStockCommodityListResp, error) {
resp := &ErpStockCommodityListResp{
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_stock_commodity").Order("id DESC")
// 构建查询条件
m.buildQueryConditions(qs)
var count int64
if err := qs.Count(&count).Error; err != nil {
//logger.Error("count err:", err)
return resp, err
}
resp.Total = int(count)/m.PageSize + 1
//获取库存商品列表
var commodities []ErpStockCommodity
if m.IsExport == 1 {
err := qs.Find(&commodities).Error
if err != nil && !errors.Is(err, RecordNotFound) {
//logger.Error("dailys err:", err)
return resp, err
}
//listExport, err := ErpCommodityListExport(commodities)
//if err != nil {
// logger.Error("list export err:", err)
//}
//resp.ExportUrl = listExport
} else {
err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
if err != nil && !errors.Is(err, RecordNotFound) {
//logger.Error("erp commodity list err:", err)
return resp, err
}
ErpStockCommodityListSetAge(commodities)
resp.List = commodities
}
return resp, nil
}
// buildQueryConditions 根据请求参数构建查询条件
func (m *ErpStockCommodityListReq) buildQueryConditions(qs *gorm.DB) {
if m.ErpStockId != 0 { //库存id
qs = qs.Where("erp_stock_id=?", m.ErpStockId)
}
if m.ErpCommodityId != 0 { //商品id
qs = qs.Where("erp_commodity_id=?", m.ErpCommodityId)
}
if m.SerialNumber != "" { //商品编号
qs = qs.Where("commodity_serial_number=?", m.SerialNumber)
}
if m.CommodityName != "" { //商品名称
qs = qs.Where("erp_commodity_name LIKE ?", "%"+m.CommodityName+"%")
}
if m.ErpCategoryId != 0 { //商品分类id
qs = qs.Where("erp_category_id=?", m.ErpCategoryId)
}
if m.IMEI != "" { //商品串码
qs = qs.Where("imei=?", m.IMEI)
}
if m.StoreId != 0 { //门店编号
qs = qs.Where("store_id=?", m.StoreId)
}
if m.State != 0 { //库存状态
qs = qs.Where("state=?", m.State)
}
if m.Sn != "" { //首次入库订单编号
qs = qs.Where("stock_sn=?", m.Sn)
}
if m.StorageType != 0 { //首次入库方式
qs = qs.Where("storage_type=?", m.StorageType)
}
if m.StockTimeStart != "" { //最近入库开始时间
startTime, err := time.Parse(DateTimeFormat, m.StockTimeStart)
if err == nil {
qs = qs.Where("first_stock_time>?", startTime)
} else {
//logger.Error("stock time start parse err:", err)
}
}
if m.StockTimeEnd != "" { //最近入库结束时间
endTime, err := time.Parse(DateTimeFormat, m.StockTimeEnd)
if err == nil {
qs = qs.Where("first_stock_time<?", endTime)
} else {
//logger.Error("stock time end parse err:", err)
}
}
if m.Age != 0 { //最近库龄
qs = qs.Where("stock_time<?", time.Now().AddDate(0, 0, int(m.Age)*(-1)))
}
if m.AllAge != 0 { //总库龄
qs = qs.Where("first_stock_time<?", time.Now().AddDate(0, 0, int(m.AllAge)*(-1)))
}
}