mh_goadmin_server/app/admin/models/inventory_report.go

1758 lines
64 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/gin-gonic/gin"
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"go-admin/tools/config"
"sort"
"strconv"
"time"
)
// InventoryReportByProductReq 产品库存汇总(按门店)入参
type InventoryReportByProductReq struct {
StoreId []uint32 `json:"store_id"` // 门店id
CommoditySerialNumber []string `json:"commodity_serial_number"` // 商品编号
CommodityName []string `json:"commodity_name"` // 商品名称
CategoryID []uint32 `json:"category_id"` // 商品分类id
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryReportByProductResp 产品库存汇总(按门店)出参
type InventoryReportByProductResp struct {
Total uint32 `json:"total"` // 总条数/记录数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
TotalEffectiveCount uint32 `json:"total_effective_count"` // 有效库存数
TotalTransferCount uint32 `json:"total_transfer_count"` // 调入中数量
TotalCount uint32 `json:"total_count"` // 总数量
TotalEffectiveAmount float64 `json:"total_effective_amount"` // 有效库存金额
TotalTransferAmount float64 `json:"total_transfer_amount"` // 调入中金额
ExportUrl string `json:"export_url"` // 导出excel路径
List []ReportByProductData `json:"list"` //
}
// ReportByProductData 产品库存汇总(按门店)数据
type ReportByProductData struct {
StoreId uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
CommoditySerialNumber string `json:"commodity_serial_number"` // 商品编号
CommodityId uint32 `json:"commodity_id"` // 商品id
CommodityName string `json:"commodity_name"` // 商品名称
CategoryID uint32 `json:"category_id"` // 商品分类id
CategoryName string `json:"category_name"` // 商品分类名称
EffectiveCount uint32 `json:"effective_count"` // 有效库存数
TransferCount uint32 `json:"transfer_count"` // 调入中数量
Count uint32 `json:"count"` // 总数量
EffectiveAmount float64 `json:"effective_amount"` // 有效库存金额
TransferAmount float64 `json:"transfer_amount"` // 调入中金额
}
// InventoryReportByAllotReq 库存调拨入参
type InventoryReportByAllotReq struct {
DeliverStoreId []uint32 `json:"deliver_store_id"` // 调出门店id
ReceiveStoreId []uint32 `json:"receive_store_id"` // 调入门店id
CommodityName []string `json:"commodity_name"` // 商品名称
CategoryID []uint32 `json:"category_id"` // 商品分类id
State uint32 `json:"state"` // 调拨状态1-调拨中 2-已完成
AuditTimeStart string `json:"audit_time_start"` // 审核/发起开始时间
AuditTimeEnd string `json:"audit_time_end"` // 审核/发起结束时间
ReceiveTimeStart string `json:"receive_time_start"` // 调入开始时间
ReceiveTimeEnd string `json:"receive_time_end"` // 调入结束时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryReportByAllotResp 库存调拨出参
type InventoryReportByAllotResp struct {
Total int `json:"total"` // 总条数/记录数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
TotalAllotCount uint32 `json:"total_allot_count"` // 调拨数量
TotalAllotAmount float64 `json:"total_allot_amount"` // 调拨金额
ExportUrl string `json:"export_url"` // 导出excel路径
List []ReportByAllotData `json:"list"` //
}
// ReportByAllotData 库存调拨数据
type ReportByAllotData struct {
DeliverStoreId uint32 `json:"deliver_store_id"` // 调出门店id
DeliverStoreName string `json:"deliver_store_name"` // 调出门店名称
ReceiveStoreId uint32 `json:"receive_store_id"` // 调入门店id
ReceiveStoreName string `json:"receive_store_name"` // 调入门店名称
CommodityId uint32 `json:"commodity_id"` // 商品id
CommodityName string `json:"commodity_name"` // 商品名称
CategoryID uint32 `json:"category_id"` // 商品分类id
CategoryName string `json:"category_name"` // 商品分类名称
AuditTime *time.Time `json:"audit_time"` // 审核时间
ReceiveTime *time.Time `json:"receive_time"` // 收货时间/调入时间
State uint32 `json:"state"` // 调拨状态1-调拨中 2-已完成
AllotCount uint32 `json:"allot_count"` // 调拨数量
AllotAmount float64 `json:"allot_amount"` // 调拨金额
}
// InventoryReportAllotDetailReq 库存调拨明细入参
type InventoryReportAllotDetailReq struct {
SerialNumber string `json:"serial_number"` // 单据编号
DeliverStoreId []uint32 `json:"deliver_store_id"` // 调出门店id
ReceiveStoreId []uint32 `json:"receive_store_id"` // 调入门店id
CommodityName []string `json:"commodity_name"` // 商品名称
CategoryID []uint32 `json:"category_id"` // 商品分类id
State uint32 `json:"state"` // 调拨状态1-调拨中 2-已完成
AuditTimeStart string `json:"audit_time_start"` // 审核/发起开始时间
AuditTimeEnd string `json:"audit_time_end"` // 审核/发起结束时间
ReceiveTimeStart string `json:"receive_time_start"` // 调入开始时间
ReceiveTimeEnd string `json:"receive_time_end"` // 调入结束时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryReportAllotDetailResp 库存调拨明细出参
type InventoryReportAllotDetailResp struct {
Total int64 `json:"total"` // 总条数/记录数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
ExportUrl string `json:"export_url"` // 导出excel路径
List []ReportAllotDetailData `json:"list"` //
}
// ReportAllotDetailData 库存调拨明细数据
type ReportAllotDetailData struct {
SerialNumber string `json:"serial_number"` // 单据编号
DeliverStoreId uint32 `json:"deliver_store_id"` // 调出门店id
DeliverStoreName string `json:"deliver_store_name"` // 调出门店名称
ReceiveStoreId uint32 `json:"receive_store_id"` // 调入门店id
ReceiveStoreName string `json:"receive_store_name"` // 调入门店名称
MakerTime *time.Time `json:"maker_time"` // 制单时间/发起时间
AuditTime *time.Time `json:"audit_time"` // 审核时间
ReceiveTime *time.Time `json:"receive_time"` // 收货时间/调入时间
State uint32 `json:"state"` // 调拨状态1-调拨中 2-已完成
CommodityId uint32 `json:"commodity_id"` // 商品id
CommodityName string `json:"commodity_name"` // 商品名称
CategoryID uint32 `json:"category_id"` // 商品分类id
CategoryName string `json:"category_name"` // 商品分类名称
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
Remark string `json:"remark"` // 备注
}
// InventoryReportByOtherReq 其他出入库汇总入参
type InventoryReportByOtherReq struct {
StoreId []uint32 `json:"store_id"` // 门店id
CommodityName []string `json:"commodity_name"` // 商品名称
CategoryID []uint32 `json:"category_id"` // 商品分类id
State uint32 `json:"state"` // 调拨状态1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
StartTime string `json:"start_time"` // 开始时间/入库时间
EndTime string `json:"end_time"` // 结束时间/出库时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryReportByOtherResp 其他出入库汇总出参
type InventoryReportByOtherResp struct {
Total int `json:"total"` // 总条数/记录数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
TotalCount uint32 `json:"total_count"` // 总数量
TotalAmount float64 `json:"total_amount"` // 总金额
ExportUrl string `json:"export_url"` // 导出excel路径
List []ReportByOtherData `json:"list"` //
}
// ReportByOtherData 其他出入库汇总数据
type ReportByOtherData struct {
StoreId uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
CommodityId uint32 `json:"commodity_id"` // 商品id
CommodityName string `json:"commodity_name"` // 商品名称
CategoryID uint32 `json:"category_id"` // 商品分类id
CategoryName string `json:"category_name"` // 商品分类名称
Type uint32 `json:"type"` // 调拨状态1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
Count int64 `json:"count"` // 数量
Amount float64 `json:"amount"` // 金额
}
// InventoryReportOtherDetailReq 其他出入库明细入参
type InventoryReportOtherDetailReq struct {
SerialNumber string `json:"serial_number"` // 单据编号
StoreId []uint32 `json:"store_id"` // 门店id
CommodityName []string `json:"commodity_name"` // 商品名称
CategoryID []uint32 `json:"category_id"` // 商品分类id
Type uint32 `json:"type"` // 出入库方式1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
StartTime string `json:"start_time"` // 开始时间/入库时间
EndTime string `json:"end_time"` // 结束时间/出库时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// InventoryReportOtherDetailResp 其他出入库明细出参
type InventoryReportOtherDetailResp struct {
Total int `json:"total"` // 总条数/记录数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
TotalPurchasePrice float64 `json:"total_purchase_price"` // 总入库采购价
TotalEmployeePrice float64 `json:"total_employee_price"` // 总入库员工成本价
ExportUrl string `json:"export_url"` // 导出excel路径
List []ReportOtherDetailData `json:"list"` //
}
// ReportOtherDetailData 其他出入库明细数据
type ReportOtherDetailData struct {
CommodityId uint32 `json:"commodity_id"` // 商品id
CommodityName string `json:"commodity_name"` // 商品名称
CategoryID uint32 `json:"category_id"` // 商品分类id
CategoryName string `json:"category_name"` // 商品分类名称
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
StoreId uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
SupplierId uint32 `json:"supplier_id"` // 供应商id
SupplierName string `json:"supplier_name"` // 供应商名称
StockTime *time.Time `json:"stock_time"` // 出入库时间
Type uint32 `json:"type"` // 调拨状态1-产品入库 2-盘点入库 3-系统出库 4-盘点出库
SerialNumber string `json:"serial_number"` // 单据编号
PurchasePrice float64 `json:"purchase_price"` // 入库采购价
EmployeePrice float64 `json:"employee_price"` // 入库员工成本价
}
// ReportByProductList 产品库存汇总(按门店)
func (m *InventoryReportByProductReq) ReportByProductList(c *gin.Context) (*InventoryReportByProductResp, error) {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
m.StoreId = CompareLists(storeList, m.StoreId)
if len(m.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
return &InventoryReportByProductResp{}, nil
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
resp := &InventoryReportByProductResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
qs := orm.Eloquent.Debug().Table("erp_stock")
if len(m.StoreId) > 0 { // 门店复选
var storeIDs []uint32
for _, store := range m.StoreId {
storeIDs = append(storeIDs, store)
}
qs = qs.Where("store_id IN (?)", storeIDs)
}
if len(m.CategoryID) > 0 { // 商品分类id
var categoryIDs []uint32
for _, category := range m.CategoryID {
categoryIDs = append(categoryIDs, category)
}
qs = qs.Where("category_id IN (?)", categoryIDs)
}
if len(m.CommoditySerialNumber) > 0 { // 商品编号
var serialNumbers []string
for _, serialNumber := range m.CommoditySerialNumber {
serialNumbers = append(serialNumbers, serialNumber)
}
qs = qs.Where("commodity_serial_number IN (?)", serialNumbers)
}
if len(m.CommodityName) > 0 { // 商品名称
var commodityNames []string
for _, commodityName := range m.CommodityName {
commodityNames = append(commodityNames, commodityName)
}
qs = qs.Where("commodity_name IN (?)", commodityNames)
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("查询无库存列表数量失败", logger.Field("err", err))
return nil, err
}
var commodities []ErpStock
if m.IsExport == 1 { // 导出excel
err = qs.Order("erp_commodity_id, store_id desc").Find(&commodities).Error
} else {
err = qs.Order("erp_commodity_id, store_id desc").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
}
if err != nil && err != RecordNotFound {
logger.Error("查询无库存列表失败", logger.Field("err", err))
return nil, err
}
var reportList []ReportByProductData
var nTotalEffectiveCount, nTotalTransferCount uint32
var nTotalEffectiveAmount, nTotalTransferAmount float64
// 遍历库存列表,计算有效库存金额,调入中金额
for _, item := range commodities {
var reportData ReportByProductData
reportData.StoreId = item.StoreId
reportData.StoreName = item.StoreName
reportData.CommoditySerialNumber = item.CommoditySerialNumber
reportData.CommodityId = item.ErpCommodityId
reportData.CommodityName = item.ErpCommodityName
reportData.CategoryID = item.ErpCategoryId
reportData.CategoryName = item.ErpCategoryName
reportData.EffectiveCount = item.Count
reportData.TransferCount = item.DispatchCount
reportData.Count = item.Count + item.DispatchCount
// 查询有效库存金额
if item.Count != 0 {
reportData.EffectiveAmount, err = getStockCommodityAmount(item.StoreId, item.ErpCommodityId)
if err != nil {
return nil, err
}
}
// 查询调入中金额
if item.DispatchCount != 0 {
reportData.TransferAmount, err = getDispatchCommodityAmount(item.StoreId, item.ErpCommodityId)
if err != nil {
return nil, err
}
}
nTotalEffectiveCount += reportData.EffectiveCount
nTotalTransferCount += reportData.TransferCount
nTotalEffectiveAmount += reportData.EffectiveAmount
nTotalTransferAmount += reportData.TransferAmount
reportList = append(reportList, reportData)
}
resp.TotalEffectiveCount = nTotalEffectiveCount
resp.TotalTransferCount = nTotalTransferCount
resp.TotalCount = resp.TotalTransferCount + resp.TotalEffectiveCount
resp.TotalEffectiveAmount = nTotalEffectiveAmount
resp.TotalTransferAmount = nTotalTransferAmount
resp.Total = resp.TotalCount
resp.List = reportList
if m.IsExport == 1 { // 导出excel
resp.ExportUrl, err = reportByProductExport(resp)
if err != nil {
return nil, err
}
resp.List = []ReportByProductData{}
}
return resp, nil
}
// 查询有效库存金额
func getStockCommodityAmount(storeId, commodityId uint32) (float64, error) {
var nCount int64
err := orm.Eloquent.Debug().Table("erp_stock_commodity").
Where("store_id = ? and erp_commodity_id = ? and state = ?",
storeId, commodityId, InStock).Count(&nCount).Error
if err != nil {
return 0, err
}
if nCount == 0 {
return 0, nil
}
var nStockCommodityAmount float64
err = orm.Eloquent.Debug().Table("erp_stock_commodity").Select("SUM(wholesale_price) AS "+
"nStockCommodityAmount").Where("store_id = ? and erp_commodity_id = ? and state = ?",
storeId, commodityId, InStock).Find(&nStockCommodityAmount).Error
if err != nil {
return 0, err
}
return nStockCommodityAmount, nil
}
// 查询调入中金额
func getDispatchCommodityAmount(storeId, commodityId uint32) (float64, error) {
var nCount int64
err := orm.Eloquent.Debug().Table("erp_stock_commodity").
Where("store_id = ? and erp_commodity_id = ? and state = ?",
storeId, commodityId, InAllot).Count(&nCount).Error
if err != nil {
return 0, err
}
if nCount == 0 {
return 0, nil
}
var nDispatchCommodityAmount float64
err = orm.Eloquent.Debug().Table("erp_stock_commodity").Select("SUM(wholesale_price) AS "+
"nStockCommodityAmount").Where("store_id = ? and erp_commodity_id = ? and state = ?",
storeId, commodityId, InAllot).Find(&nDispatchCommodityAmount).Error
if err != nil {
return 0, err
}
return nDispatchCommodityAmount, nil
}
// reportByProductExport 产品库存汇总按门店导出excel
func reportByProductExport(req *InventoryReportByProductResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "产品库存汇总(按门店)" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"门店", "商品编号", "商品名称", "商品分类", "有效库存数", "调入中数量", "总数量", "有效库存金额", "调入中金额"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row1 []interface{}
nExcelStartRow := 0
for _, reportData := range req.List {
row1 = []interface{}{
reportData.StoreName, // 门店
reportData.CommoditySerialNumber, // 商品编号
reportData.CommodityName, // 商品名称
reportData.CategoryName, // 商品分类
reportData.EffectiveCount, // 有效库存数
reportData.TransferCount, // 调入中数量
reportData.Count, // 总数量
reportData.EffectiveAmount, // 有效库存金额
reportData.TransferAmount, // 调入中金额
}
for j, _ := range row1 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row1[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", req.TotalEffectiveCount, req.TotalTransferCount, req.TotalCount,
req.TotalEffectiveAmount, req.TotalTransferAmount}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 30)
file.SetColWidth("Sheet1", "C", "C", 25)
file.SetColWidth("Sheet1", "D", "D", 15)
file.SetColWidth("Sheet1", "E", "E", 15)
file.SetColWidth("Sheet1", "F", "F", 15)
file.SetColWidth("Sheet1", "H", "H", 15)
file.SetColWidth("Sheet1", "I", "I", 15)
endRow := fmt.Sprintf("I"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
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
}
// ReportAllotList 库存调拨汇总
func (m *InventoryReportByAllotReq) ReportAllotList(c *gin.Context) (*InventoryReportByAllotResp, error) {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
m.DeliverStoreId = CompareLists(storeList, m.DeliverStoreId)
m.ReceiveStoreId = CompareLists(storeList, m.ReceiveStoreId)
if len(m.DeliverStoreId) == 0 && len(m.ReceiveStoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
return &InventoryReportByAllotResp{}, nil
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
resp := &InventoryReportByAllotResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
qs := orm.Eloquent.Debug().Table("erp_inventory_allot_order").
Select("erp_inventory_allot_order.deliver_store_id, "+
"erp_inventory_allot_order.deliver_store_name, "+
"erp_inventory_allot_order.receive_store_id, "+
"erp_inventory_allot_order.receive_store_name, "+
"erp_inventory_allot_order.audit_time, "+
"erp_inventory_allot_order.receive_time, "+
"CASE "+
"WHEN erp_inventory_allot_order.state IN (2, 3) THEN 1 "+
"WHEN erp_inventory_allot_order.state = 4 THEN 2 "+
"ELSE erp_inventory_allot_order.state "+
"END AS state, "+
"erp_inventory_allot_commodity.commodity_id, "+
"erp_inventory_allot_commodity.commodity_name, "+
"erp_inventory_allot_commodity.count as allot_count, "+
"erp_inventory_allot_commodity.amount as allot_amount").
Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id").
Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单
// 创建一个新的查询对象,用于 count 查询
countQuery := orm.Eloquent.Debug().Table("erp_inventory_allot_order").
Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id").
Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单
if len(m.DeliverStoreId) > 0 { // 调出门店id复选
var storeIDs []uint32
for _, store := range m.DeliverStoreId {
storeIDs = append(storeIDs, store)
}
qs = qs.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs)
countQuery = countQuery.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs)
}
if len(m.ReceiveStoreId) > 0 { // 调入门店id复选
var storeIDs []uint32
for _, store := range m.ReceiveStoreId {
storeIDs = append(storeIDs, store)
}
qs = qs.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs)
countQuery = countQuery.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs)
}
if len(m.CommodityName) > 0 { // 商品名称
var commodityNames []string
for _, commodityName := range m.CommodityName {
commodityNames = append(commodityNames, commodityName)
}
qs = qs.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames)
countQuery = countQuery.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames)
}
if len(m.CategoryID) > 0 { // 商品分类id
var categoryIDs []uint32
for _, category := range m.CategoryID {
categoryIDs = append(categoryIDs, category)
}
qs = qs.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs)
countQuery = countQuery.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs)
}
if m.State != 0 { // 调拨状态
switch m.State {
case 1: // 调拨中
qs = qs.Where("erp_inventory_allot_order.state IN (?)",
ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive)
countQuery = countQuery.Where("erp_inventory_allot_order.state IN (?)",
ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive)
case 2: // 已完成
qs = qs.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished)
countQuery = countQuery.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished)
}
}
if m.AuditTimeStart != "" { // 审核开始时间
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("ReportAllotList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.audit_time > ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.audit_time > ?", parse)
}
if m.AuditTimeEnd != "" { // 审核结束时间
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("ReportAllotList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.audit_time < ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.audit_time < ?", parse)
}
if m.ReceiveTimeStart != "" { // 调入开始时间
parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeStart)
if err != nil {
logger.Errorf("ReportAllotList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.receive_time > ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.receive_time > ?", parse)
}
if m.ReceiveTimeEnd != "" { // 调入结束时间
parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeEnd)
if err != nil {
logger.Errorf("ReportAllotList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.receive_time < ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.receive_time < ?", parse)
}
var count int64
err := countQuery.Count(&count).Error
if err != nil {
logger.Error("ReportAllotList 查询失败", logger.Field("err", err))
return nil, err
}
var commodities []ReportByAllotData
err = qs.Find(&commodities).Error
if err != nil {
return nil, err
}
var nTotalAllotCount uint32
var nTotalAllotAmount float64
// 创建 map 用于存储汇总数据
summaryMap := make(map[string]*ReportByAllotData)
// 遍历 commodities 切片
for _, item := range commodities {
nTotalAllotCount += item.AllotCount
nTotalAllotAmount += item.AllotAmount
// 生成键
key := fmt.Sprintf("%d_%d_%d", item.DeliverStoreId, item.ReceiveStoreId, item.State)
// 检查是否已经存在该键的汇总数据
if summary, ok := summaryMap[key]; ok {
// 如果已经存在,累加调拨数量和调拨金额
summary.AllotCount += item.AllotCount
// 假设商品金额在 item.CommodityAmount 中
summary.AllotAmount += item.AllotAmount
} else {
// 如果不存在,创建新的汇总数据并添加到 map 中
summaryMap[key] = &ReportByAllotData{
DeliverStoreId: item.DeliverStoreId,
DeliverStoreName: item.DeliverStoreName,
ReceiveStoreId: item.ReceiveStoreId,
ReceiveStoreName: item.ReceiveStoreName,
CommodityId: item.CommodityId,
CommodityName: item.CommodityName,
CategoryID: item.CategoryID,
CategoryName: item.CategoryName,
AuditTime: item.AuditTime,
ReceiveTime: item.ReceiveTime,
State: item.State, // 调拨中状态为 1
AllotCount: item.AllotCount, // 初始化为 1
AllotAmount: item.AllotAmount,
}
}
}
var summaryList []ReportByAllotData
for i, summary := range summaryMap {
// 添加分类信息
commodityInfo, err := GetCommodity(summary.CommodityId)
if err != nil {
logger.Error("SetCategory err:", logger.Field("err", err))
}
summaryMap[i].CategoryID = commodityInfo.ErpCategoryId
summaryMap[i].CategoryName = commodityInfo.ErpCategoryName
summaryList = append(summaryList, *summary)
}
// 排序规则:商品编号小>调出店铺编号小>调入门店编号小>状态为已完成
sort.Slice(summaryList, func(i, j int) bool {
if summaryList[i].CommodityId != summaryList[j].CommodityId {
return summaryList[i].CommodityId < summaryList[j].CommodityId
}
if summaryList[i].DeliverStoreId != summaryList[j].DeliverStoreId {
return summaryList[i].DeliverStoreId < summaryList[j].DeliverStoreId
}
if summaryList[i].ReceiveStoreId != summaryList[j].ReceiveStoreId {
return summaryList[i].ReceiveStoreId < summaryList[j].ReceiveStoreId
}
return summaryList[i].State < summaryList[j].State
})
// 计算分页所需的切片索引
startIndex := page * m.PageSize
endIndex := (page + 1) * m.PageSize
if endIndex > len(summaryList) {
endIndex = len(summaryList)
}
resp.Total = len(summaryMap)
resp.TotalAllotCount = nTotalAllotCount
resp.TotalAllotAmount = nTotalAllotAmount
resp.List = summaryList[startIndex:endIndex]
if m.IsExport == 1 {
resp.ExportUrl, err = reportAllotExport(resp)
if err != nil {
return nil, err
}
resp.List = []ReportByAllotData{}
}
return resp, nil
}
// reportAllotExport 库存调拨汇总导出excel
func reportAllotExport(req *InventoryReportByAllotResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "库存调拨汇总" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"调出门店", "调入门店", "商品名称", "商品分类", "调拨状态", "调拨数量", "调拨金额"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row1 []interface{}
nExcelStartRow := 0
for _, reportData := range req.List {
var allotState string
switch reportData.State {
case 1: // 调拨中
allotState = "调拨中"
case 2: // 已完成
allotState = "已完成"
}
row1 = []interface{}{
reportData.DeliverStoreName, // 调出门店
reportData.ReceiveStoreName, // 调入门店
reportData.CommodityName, // 商品名称
reportData.CategoryName, // 商品分类
allotState, // 调拨状态
reportData.AllotCount, // 调拨数量
reportData.AllotAmount, // 调拨金额
}
for j, _ := range row1 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row1[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", "", req.TotalAllotCount, req.TotalAllotAmount}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 28)
file.SetColWidth("Sheet1", "B", "B", 28)
file.SetColWidth("Sheet1", "C", "C", 23)
file.SetColWidth("Sheet1", "D", "D", 15)
endRow := fmt.Sprintf("G"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
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
}
// ReportAllotDetailList 库存调拨明细
func (m *InventoryReportAllotDetailReq) ReportAllotDetailList(c *gin.Context) (*InventoryReportAllotDetailResp, error) {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
m.DeliverStoreId = CompareLists(storeList, m.DeliverStoreId)
m.ReceiveStoreId = CompareLists(storeList, m.ReceiveStoreId)
if len(m.DeliverStoreId) == 0 && len(m.ReceiveStoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
return &InventoryReportAllotDetailResp{}, nil
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
resp := &InventoryReportAllotDetailResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
qs := orm.Eloquent.Debug().Table("erp_inventory_allot_order").
Select("erp_inventory_allot_order.serial_number, "+
"erp_inventory_allot_order.deliver_store_id, "+
"erp_inventory_allot_order.deliver_store_name, "+
"erp_inventory_allot_order.receive_store_id, "+
"erp_inventory_allot_order.receive_store_name, "+
"erp_inventory_allot_order.maker_time, "+
"erp_inventory_allot_order.audit_time, "+
"erp_inventory_allot_order.receive_time, "+
"CASE "+
"WHEN erp_inventory_allot_order.state IN (2, 3) THEN 1 "+
"WHEN erp_inventory_allot_order.state = 4 THEN 2 "+
"ELSE erp_inventory_allot_order.state "+
"END AS state, "+
"erp_inventory_allot_commodity.commodity_id, "+
"erp_inventory_allot_commodity.commodity_name, "+
"erp_inventory_allot_commodity.imei_type, "+
"erp_inventory_allot_commodity.imei, "+
"erp_inventory_allot_commodity.count, "+
"erp_inventory_allot_commodity.remark").
Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id").
Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单
// 创建一个新的查询对象,用于 count 查询
countQuery := orm.Eloquent.Debug().Table("erp_inventory_allot_order").
Joins("JOIN erp_inventory_allot_commodity ON erp_inventory_allot_commodity.allot_order_id = erp_inventory_allot_order.id").
Where("erp_inventory_allot_order.state <> ?", ErpInventoryAllotOrderUnAudit) // 排除待审核的订单
if m.SerialNumber != "" { // 单据编号
qs = qs.Where("erp_inventory_allot_order.serial_number = ?", m.SerialNumber)
countQuery = countQuery.Where("erp_inventory_allot_order.serial_number = ?", m.SerialNumber)
}
if len(m.DeliverStoreId) > 0 { // 调出门店id复选
var storeIDs []uint32
for _, store := range m.DeliverStoreId {
storeIDs = append(storeIDs, store)
}
qs = qs.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs)
countQuery = countQuery.Where("erp_inventory_allot_order.deliver_store_id IN (?)", storeIDs)
}
if len(m.ReceiveStoreId) > 0 { // 调入门店id复选
var storeIDs []uint32
for _, store := range m.ReceiveStoreId {
storeIDs = append(storeIDs, store)
}
qs = qs.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs)
countQuery = countQuery.Where("erp_inventory_allot_order.receive_store_id IN (?)", storeIDs)
}
if len(m.CommodityName) > 0 { // 商品名称
var commodityNames []string
for _, commodityName := range m.CommodityName {
commodityNames = append(commodityNames, commodityName)
}
qs = qs.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames)
countQuery = countQuery.Where("erp_inventory_allot_order.commodity_name IN (?)", commodityNames)
}
if len(m.CategoryID) > 0 { // 商品分类id
var categoryIDs []uint32
for _, category := range m.CategoryID {
categoryIDs = append(categoryIDs, category)
}
qs = qs.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs)
countQuery = countQuery.Where("erp_inventory_allot_order.category_id IN (?)", categoryIDs)
}
if m.State != 0 { // 调拨状态
switch m.State {
case 1: // 调拨中
qs = qs.Where("erp_inventory_allot_order.state IN (?)",
ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive)
countQuery = countQuery.Where("erp_inventory_allot_order.state IN (?)",
ErpInventoryAllotOrderWaitSend, ErpInventoryAllotOrderWaitReceive)
case 2: // 已完成
qs = qs.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished)
countQuery = countQuery.Where("erp_inventory_allot_order.state = ?", ErpInventoryAllotOrderFinished)
}
}
if m.AuditTimeStart != "" { // 审核开始时间
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("ReportAllotDetailList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.audit_time > ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.audit_time > ?", parse)
}
if m.AuditTimeEnd != "" { // 审核结束时间
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("ReportAllotDetailList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.audit_time < ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.audit_time < ?", parse)
}
if m.ReceiveTimeStart != "" { // 调入开始时间
parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeStart)
if err != nil {
logger.Errorf("ReportAllotDetailList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.receive_time > ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.receive_time > ?", parse)
}
if m.ReceiveTimeEnd != "" { // 调入结束时间
parse, err := time.Parse(QueryTimeFormat, m.ReceiveTimeEnd)
if err != nil {
logger.Errorf("ReportAllotDetailList err:", err)
return nil, err
}
qs = qs.Where("erp_inventory_allot_order.receive_time < ?", parse)
countQuery = countQuery.Where("erp_inventory_allot_order.receive_time < ?", parse)
}
var count int64
err := countQuery.Count(&count).Error
if err != nil {
logger.Error("查询无库存列表数量失败", logger.Field("err", err))
return nil, err
}
var commodities []ReportAllotDetailData
if m.IsExport == 1 { // 导出excel
err = qs.Order("audit_time DESC").Find(&commodities).Error
} else {
err = qs.Order("audit_time DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&commodities).Error
}
if err != nil {
return nil, err
}
// 添加分类信息
reportAllotDetailSetCategory(commodities)
resp.Total = count
resp.List = commodities
if m.IsExport == 1 {
resp.ExportUrl, err = reportAllotDetailExport(resp)
if err != nil {
return nil, err
}
resp.List = []ReportAllotDetailData{}
}
return resp, nil
}
// 添加订单的添加分类信息
func reportAllotDetailSetCategory(list []ReportAllotDetailData) {
for i, _ := range list {
list[i].SetCategory()
}
}
func (m *ReportAllotDetailData) SetCategory() {
commodityInfo, err := GetCommodity(m.CommodityId)
if err != nil {
logger.Error("SetCategory err:", logger.Field("err", err))
}
m.CategoryID = commodityInfo.ErpCategoryId
m.CategoryName = commodityInfo.ErpCategoryName
}
// reportAllotDetailExport 库存调拨明细导出excel
func reportAllotDetailExport(req *InventoryReportAllotDetailResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "库存调拨明细" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"单据编号", "调出门店", "调入门店", "订单审核时间", "调入时间", "调拨状态", "商品名称",
"商品分类", "是否串码", "串码"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row1 []interface{}
nExcelStartRow := 0
for _, reportData := range req.List {
var allotState string
switch reportData.State {
case 1: // 调拨中
allotState = "调拨中"
case 2: // 已完成
allotState = "已完成"
}
var IMEIType string
switch reportData.IMEIType {
case 1:
IMEIType = "非串码"
case 2, 3:
IMEIType = "串码类"
}
var receiveTime, auditTime string
if reportData.ReceiveTime != nil {
receiveTime = reportData.ReceiveTime.Format(TimeFormat)
}
if reportData.AuditTime != nil {
auditTime = reportData.AuditTime.Format(TimeFormat)
}
row1 = []interface{}{
reportData.SerialNumber, // 单据编号
reportData.DeliverStoreName, // 调出门店
reportData.ReceiveStoreName, // 调入门店
auditTime, // 订单审核时间
receiveTime, // 调入时间
allotState, // 调拨状态
reportData.CommodityName, // 商品名称
reportData.CategoryName, // 商品分类
IMEIType, // 是否串码
reportData.IMEI, // 串码
}
for j, _ := range row1 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row1[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", "", "", "", "", "", ""}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 13)
file.SetColWidth("Sheet1", "B", "B", 28)
file.SetColWidth("Sheet1", "C", "C", 28)
file.SetColWidth("Sheet1", "D", "D", 18)
file.SetColWidth("Sheet1", "E", "E", 18)
file.SetColWidth("Sheet1", "G", "G", 23)
file.SetColWidth("Sheet1", "H", "H", 15)
file.SetColWidth("Sheet1", "J", "J", 15)
endRow := fmt.Sprintf("J"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
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
}
// ReportByOtherList 其他出入库汇总
func (m *InventoryReportByOtherReq) ReportByOtherList(c *gin.Context) (*InventoryReportByOtherResp, error) {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
m.StoreId = CompareLists(storeList, m.StoreId)
if len(m.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
return &InventoryReportByOtherResp{}, nil
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
resp := &InventoryReportByOtherResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
// 查询产品入库数据
var err error
var productList []ReportOtherDetailData
productList, err = getProductOrderData()
if err != nil {
return nil, err
}
// 查询盘点出入库数据
var changeList []ReportOtherDetailData
changeList, err = getChangeOrderData()
if err != nil {
return nil, err
}
// 查询系统出库数据
var systemList []ReportOtherDetailData
systemList, err = getSystemOutData()
if err != nil {
return nil, err
}
// 合并数据
allData := append(productList, changeList...)
allData = append(allData, systemList...)
var nTotalAllotCount uint32
var nTotalAllotAmount float64
// 创建 map 用于存储汇总数据
summaryMap := make(map[string]*ReportByOtherData)
// 遍历切片
for _, item := range allData {
if item.Type == 3 || item.Type == 4 {
nTotalAllotCount -= 1
nTotalAllotAmount -= item.PurchasePrice
} else {
nTotalAllotCount += 1
nTotalAllotAmount += item.PurchasePrice
}
// 生成键
key := fmt.Sprintf("%d_%d_%d", item.CommodityId, item.StoreId, item.Type)
// 检查是否已经存在该键的汇总数据
if summary, ok := summaryMap[key]; ok {
// 如果已经存在,累加调拨数量和调拨金额
summary.Count += 1
// 假设商品金额在 item.CommodityAmount 中
summary.Amount += item.PurchasePrice
} else {
// 如果不存在,创建新的汇总数据并添加到 map 中
summaryMap[key] = &ReportByOtherData{
StoreId: item.StoreId,
StoreName: item.StoreName,
CommodityId: item.CommodityId,
CommodityName: item.CommodityName,
CategoryID: item.CategoryID,
CategoryName: item.CategoryName,
Type: item.Type,
Count: 1, // 初始化为 1
Amount: item.PurchasePrice,
}
}
}
var summaryList []ReportByOtherData
for i, summary := range summaryMap {
// 添加分类信息
commodityInfo, err := GetCommodity(summary.CommodityId)
if err != nil {
logger.Error("SetCategory err:", logger.Field("err", err))
}
summaryMap[i].CategoryID = commodityInfo.ErpCategoryId
summaryMap[i].CategoryName = commodityInfo.ErpCategoryName
if summary.Type == 3 || summary.Type == 4 {
summaryMap[i].Count = -summaryMap[i].Count
summaryMap[i].Amount = -summaryMap[i].Amount
}
summaryList = append(summaryList, *summary)
}
// 使用排序规则函数对汇总数据进行排序
sortSummaryList(summaryList)
// 计算分页所需的切片索引
startIndex := page * m.PageSize
endIndex := (page + 1) * m.PageSize
if endIndex > len(summaryList) {
endIndex = len(summaryList)
}
resp.Total = len(summaryList)
resp.TotalCount = nTotalAllotCount
resp.TotalAmount = tools.RoundToTwoDecimalPlaces(nTotalAllotAmount)
if m.IsExport == 1 {
resp.List = summaryList
resp.ExportUrl, err = reportOtherExport(resp)
if err != nil {
return nil, err
}
resp.List = []ReportByOtherData{}
resp.TotalCount = 0
resp.TotalAmount = 0
} else {
resp.List = summaryList[startIndex:endIndex]
}
return resp, nil
}
// 排序规则函数
// 排序规则:商品编号小>门店编号小>产品入库>盘点入库>系统出库>盘点出库
func sortSummaryList(summaryList []ReportByOtherData) {
sort.Slice(summaryList, func(i, j int) bool {
// 按 CommodityId 排序
if summaryList[i].CommodityId != summaryList[j].CommodityId {
return summaryList[i].CommodityId < summaryList[j].CommodityId
}
// 如果 CommodityId 相同,则按 StoreId 排序
if summaryList[i].StoreId != summaryList[j].StoreId {
return summaryList[i].StoreId < summaryList[j].StoreId
}
// 如果 StoreId 相同, 按 Type 排序
if summaryList[i].Type != summaryList[j].Type {
return summaryList[i].Type < summaryList[j].Type
}
// 如果 Type 相同,则按 Amount 排序
return summaryList[i].Amount < summaryList[j].Amount
})
}
// reportOtherExport 其他出入库汇总导出excel
func reportOtherExport(req *InventoryReportByOtherResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "其他出入库汇总" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"门店", "商品名称", "商品分类", "出入库方式", "数量", "金额"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row1 []interface{}
nExcelStartRow := 0
for _, reportData := range req.List {
var inventoryType string
switch reportData.Type {
case 1:
inventoryType = "产品入库"
case 2:
inventoryType = "盘点入库"
case 3:
inventoryType = "系统出库"
case 4:
inventoryType = "盘点出库"
}
row1 = []interface{}{
reportData.StoreName, // 门店
reportData.CommodityName, // 商品名称
reportData.CategoryName, // 商品分类
inventoryType, // 出入库方式
reportData.Count, // 数量
reportData.Amount, // 金额
}
for j, _ := range row1 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row1[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", req.TotalCount, req.TotalAmount}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 28)
file.SetColWidth("Sheet1", "B", "B", 28)
file.SetColWidth("Sheet1", "C", "C", 20)
file.SetColWidth("Sheet1", "D", "D", 20)
endRow := fmt.Sprintf("F"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
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
}
// ReportByOtherDetailList 其他出入库明细
func (m *InventoryReportOtherDetailReq) ReportByOtherDetailList(c *gin.Context) (*InventoryReportOtherDetailResp, error) {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
m.StoreId = CompareLists(storeList, m.StoreId)
if len(m.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
return &InventoryReportOtherDetailResp{}, nil
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
resp := &InventoryReportOtherDetailResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
// 查询产品入库数据
var err error
var productList []ReportOtherDetailData
productList, err = getProductOrderData()
if err != nil {
return nil, err
}
// 查询盘点出入库数据
var changeList []ReportOtherDetailData
changeList, err = getChangeOrderData()
if err != nil {
return nil, err
}
// 查询系统出库数据
var systemList []ReportOtherDetailData
systemList, err = getSystemOutData()
if err != nil {
return nil, err
}
// 合并数据
allData := append(productList, changeList...)
allData = append(allData, systemList...)
// 进行条件查询
var startTime time.Time
if m.StartTime != "" { // 出入库开始时间
startTime, err = time.Parse(QueryTimeFormat, m.StartTime)
if err != nil {
logger.Errorf("ReportByOtherDetailList err:", err)
return nil, err
}
}
var endTime time.Time
if m.EndTime != "" { // 出入库结束时间
endTime, err = time.Parse(QueryTimeFormat, m.EndTime)
if err != nil {
logger.Errorf("ReportByOtherDetailList err:", err)
return nil, err
}
}
var totalPurchasePrice, totalEmployeePrice float64
filteredData := make([]ReportOtherDetailData, 0)
for i, data := range allData {
if allData[i].CategoryID == 0 {
// 添加分类信息
commodityInfo, err := GetCommodity(data.CommodityId)
if err != nil {
logger.Error("SetCategory err:", logger.Field("err", err))
}
allData[i].CategoryID = commodityInfo.ErpCategoryId
allData[i].CategoryName = commodityInfo.ErpCategoryName
}
if (len(m.SerialNumber) == 0 || data.SerialNumber == m.SerialNumber) &&
(len(m.StoreId) == 0 || tools.Uint32SliceContains(m.StoreId, data.StoreId)) &&
(len(m.CommodityName) == 0 || tools.StringSliceContains(m.CommodityName, data.CommodityName)) &&
(len(m.CategoryID) == 0 || tools.Uint32SliceContains(m.CategoryID, allData[i].CategoryID)) &&
(m.Type == 0 || m.Type == data.Type) &&
((m.StartTime == "" && m.EndTime == "") || (data.StockTime.After(startTime) && data.StockTime.Before(endTime))) {
if data.Type == 3 || data.Type == 4 { // 系统出库、盘点出库
totalPurchasePrice -= allData[i].PurchasePrice
totalEmployeePrice -= allData[i].EmployeePrice
allData[i].PurchasePrice = -allData[i].PurchasePrice
allData[i].EmployeePrice = -allData[i].EmployeePrice
} else {
totalPurchasePrice += allData[i].PurchasePrice
totalEmployeePrice += allData[i].EmployeePrice
}
filteredData = append(filteredData, allData[i])
}
}
// 进行排序
sort.Slice(filteredData, func(i, j int) bool {
return filteredData[i].StockTime.After(*filteredData[j].StockTime)
})
resp.TotalPurchasePrice = tools.RoundToTwoDecimalPlaces(totalPurchasePrice)
resp.TotalEmployeePrice = tools.RoundToTwoDecimalPlaces(totalEmployeePrice)
if m.IsExport == 1 {
resp.List = filteredData
resp.Total = len(filteredData)
resp.ExportUrl, err = reportOtherDetailExport(resp)
if err != nil {
return nil, err
}
resp.List = []ReportOtherDetailData{}
resp.TotalPurchasePrice = 0
resp.TotalEmployeePrice = 0
} else {
// 进行分页处理
startIndex := page * m.PageSize
endIndex := startIndex + m.PageSize
if endIndex > len(filteredData) {
endIndex = len(filteredData)
}
resp.List = filteredData[startIndex:endIndex]
resp.Total = len(filteredData)
}
return resp, nil
}
// 查询产品入库数据
func getProductOrderData() ([]ReportOtherDetailData, error) {
var productList []ReportOtherDetailData
err := orm.Eloquent.Debug().Table("erp_inventory_product_order").
Select("erp_inventory_product_order.serial_number, "+
"erp_inventory_product_order.store_id, "+
"erp_inventory_product_order.store_name, "+
"erp_inventory_product_order.audit_time as stock_time, "+
"CASE "+
"WHEN erp_inventory_product_order.state = 2 THEN 1 "+
"ELSE erp_inventory_product_order.state "+
"END AS type, "+
"erp_inventory_product_commodity.commodity_id, "+
"erp_inventory_product_commodity.commodity_name, "+
"erp_inventory_product_commodity.supplier_id, "+
"erp_inventory_product_commodity.supplier_name, "+
"erp_inventory_product_commodity.imei_type, "+
"erp_inventory_product_commodity.imei, "+
"erp_inventory_product_commodity.price as purchase_price, "+
"erp_inventory_product_commodity.employee_price as employee_price").
Joins("JOIN erp_inventory_product_commodity "+
"ON erp_inventory_product_commodity.product_order_id = erp_inventory_product_order.id").
Where("erp_inventory_product_order.state = ?", ErpInventoryProductOrderFinished).
Find(&productList).Error // 查询已审核的订单
if err != nil {
return nil, err
}
return productList, nil
}
// 查询盘点出入库数据
func getChangeOrderData() ([]ReportOtherDetailData, error) {
var changeList []ReportOtherDetailData
err := orm.Eloquent.Debug().Table("erp_inventory_change_order").
Select("erp_inventory_change_order.serial_number, "+
"erp_inventory_change_order.store_id, "+
"erp_inventory_change_order.store_name, "+
"erp_inventory_change_order.audit_time as stock_time, "+
"CASE "+
"WHEN erp_inventory_change_order.change_type = 'add' THEN 2 "+
"WHEN erp_inventory_change_order.change_type = 'reduce' THEN 4 "+
"ELSE erp_inventory_change_order.state "+
"END AS type, "+
"erp_inventory_change_commodity.commodity_id, "+
"erp_inventory_change_commodity.commodity_name, "+
"erp_inventory_change_commodity.supplier_id, "+
"erp_inventory_change_commodity.supplier_name, "+
"erp_inventory_change_commodity.imei_type, "+
"erp_inventory_change_commodity.imei, "+
"erp_inventory_change_commodity.price as purchase_price, "+
"erp_inventory_change_commodity.employee_price as employee_price").
Joins("JOIN erp_inventory_change_commodity "+
"ON erp_inventory_change_commodity.change_order_id = erp_inventory_change_order.id").
Where("erp_inventory_change_order.state = ?", ErpInventoryChangeOrderFinished).
Find(&changeList).Error // 查询已审核的订单
if err != nil {
return nil, err
}
return changeList, nil
}
// 查询系统出库数据
func getSystemOutData() ([]ReportOtherDetailData, error) {
var stockCommodities []ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").
Where("state = ?", SystemOut).Find(&stockCommodities).Error
if err != nil {
return nil, err
}
var systemOutList []ReportOtherDetailData
for _, item := range stockCommodities {
var systemOutData ReportOtherDetailData
systemOutData.CommodityId = item.ErpCommodityId
systemOutData.CommodityName = item.ErpCommodityName
systemOutData.CategoryID = item.ErpCategoryId
systemOutData.CategoryName = item.ErpCategoryName
systemOutData.IMEIType = item.IMEIType
systemOutData.IMEI = item.IMEI
systemOutData.StoreId = item.StoreId
systemOutData.StoreName = item.StoreName
systemOutData.SupplierId = item.ErpSupplierId
systemOutData.SupplierName = item.ErpSupplierName
systemOutData.StockTime = &item.UpdatedAt
systemOutData.Type = 3
systemOutData.PurchasePrice = item.WholesalePrice
systemOutData.EmployeePrice = item.WholesalePrice + item.StaffCostPrice
systemOutList = append(systemOutList, systemOutData)
}
return systemOutList, nil
}
// reportOtherDetailExport 其他出入库明细导出excel
func reportOtherDetailExport(req *InventoryReportOtherDetailResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "其他出入库明细" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"商品名称", "商品分类", "是否串码", "商品串码", "所属门店", "供应商", "出/入库时间", "方式", "单据编号",
"入库采购价", "入库员工成本价"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row1 []interface{}
nExcelStartRow := 0
for _, reportData := range req.List {
var inventoryType string
switch reportData.Type {
case 1:
inventoryType = "产品入库"
case 2:
inventoryType = "盘点入库"
case 3:
inventoryType = "系统出库"
case 4:
inventoryType = "盘点出库"
}
var IMEIType string
switch reportData.IMEIType {
case 1:
IMEIType = "非串码"
case 2, 3:
IMEIType = "串码类"
}
var auditTime string
if reportData.StockTime != nil {
auditTime = reportData.StockTime.Format(TimeFormat)
}
row1 = []interface{}{
reportData.CommodityName, // 商品名称
reportData.CategoryName, // 商品分类
IMEIType, // 是否串码
reportData.IMEI, // 商品串码
reportData.StoreName, // 所属门店
reportData.SupplierName, // 供应商
auditTime, // 出/入库时间
inventoryType, // 方式
reportData.SerialNumber, // 单据编号
reportData.PurchasePrice, // 入库采购价
reportData.EmployeePrice, // 入库员工成本价
}
for j, _ := range row1 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row1[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", "", "", "", "", "", req.TotalPurchasePrice, req.TotalEmployeePrice}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 28)
file.SetColWidth("Sheet1", "B", "B", 15)
file.SetColWidth("Sheet1", "D", "D", 18)
file.SetColWidth("Sheet1", "E", "E", 28)
file.SetColWidth("Sheet1", "G", "G", 18)
file.SetColWidth("Sheet1", "I", "I", 18)
endRow := fmt.Sprintf("K"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
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
}