5725 lines
202 KiB
Go
5725 lines
202 KiB
Go
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"
|
||
"gorm.io/gorm"
|
||
"math"
|
||
"math/rand"
|
||
"sort"
|
||
"strconv"
|
||
"strings"
|
||
"sync"
|
||
"time"
|
||
)
|
||
|
||
const (
|
||
ErpPurchaseOrderUnAudit = 1 // 待审核
|
||
ErpPurchaseOrderWaitInventory = 2 // 待入库
|
||
ErpPurchaseOrderWaitReject = 3 // 待退货
|
||
ErpPurchaseOrderFinished = 4 // 已完成
|
||
ErpPurchaseOrderEnd = 5 // 已终止
|
||
|
||
ErpProcureOrder = "procure" // 采购入库订单
|
||
ErpRejectOrder = "reject" // 采购退货订单
|
||
|
||
ErpDemandStateWait = 1 // 待采购
|
||
ErpDemandStateFinish = 2 // 完成采购
|
||
)
|
||
|
||
// ErpPurchaseOrder 采购订单表
|
||
type ErpPurchaseOrder struct {
|
||
Model
|
||
SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号
|
||
PurchaseType string `json:"purchase_type"` // 类型:procure-采购 reject-退货
|
||
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id
|
||
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
|
||
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
|
||
HandlerName string `json:"handler_name"` // 经手人名称
|
||
MakerTime *time.Time `json:"maker_time"` // 制单时间
|
||
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
|
||
MakerName string `json:"maker_name"` // 制单人名称
|
||
AuditTime *time.Time `json:"audit_time"` // 审核时间
|
||
AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id
|
||
AuditorName string `json:"auditor_name"` // 审核人名称
|
||
State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
|
||
RejectedSerialNumber string `json:"rejected_serial_number"` // 退货的采购订单单据编号
|
||
ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式/收款方式id
|
||
ErpCashierName string `json:"erp_cashier_name"` // 付款方式/收款方式名称
|
||
AccountHolder string `json:"account_holder"` // 收款人
|
||
OpeningBank string `json:"opening_bank"` // 开户行
|
||
BankAccount string `json:"bank_account"` // 银行卡号
|
||
DeliveryTime string `json:"delivery_time"` // 交货日期,如:2024-02-23
|
||
DeliveryAddress string `json:"delivery_address"` // 交货地址
|
||
Remark string `json:"remark"` // 备注
|
||
Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"` //
|
||
InventoryId uint32 `json:"inventory_id" gorm:"-"` // 最近入库人id
|
||
InventoryName string `json:"inventory_name" gorm:"-"` // 最近入库人名称
|
||
}
|
||
|
||
// ErpPurchaseCommodity 采购订单商品表
|
||
type ErpPurchaseCommodity struct {
|
||
Model
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 采购订单id
|
||
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
|
||
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
|
||
IMEI string `json:"imei"` // 商品串码
|
||
RetailPrice float64 `json:"retail_price"` // 指导零售价
|
||
Count uint32 `json:"count"` // 计划采购数量
|
||
Price float64 `json:"price"` // 计划采购单价
|
||
Amount float64 `json:"amount"` // 计划采购金额
|
||
Remark string `json:"remark"` // 备注
|
||
RejectedPrice float64 `json:"rejected_price"` // 计划退货单价
|
||
RejectedCount uint32 `json:"rejected_count"` // 计划退货数量
|
||
RejectedAmount float64 `json:"rejected_amount"` // 计划退货金额
|
||
InventoryCount int32 `json:"inventory_count"` // 入库数量(=执行数量)
|
||
ExecutionCount uint32 `json:"execute_count" gorm:"-"` // 执行数量
|
||
ExecutionPrice float64 `json:"execute_price" gorm:"-"` // 平均采购单价
|
||
ExecutionEmployeePrice float64 `json:"execute_employee_price" gorm:"-"` // 平均员工成本价
|
||
ExecutionAmount float64 `json:"execute_amount" gorm:"-"` // 执行金额
|
||
DefaultEmployeePrice float64 `json:"default_employee_price" gorm:"-"` // 默认员工成本价
|
||
EffectiveCount uint32 `json:"effective_count" gorm:"-"` // 有效数量(该商品实际库存详情处剩余有效数,不包含已出库的数量)
|
||
ErpCategoryID uint32 `json:"erp_category_id" gorm:"-"` // 商品分类id
|
||
ErpCategoryName string `json:"erp_category_name" gorm:"-"` // 商品分类名称
|
||
}
|
||
|
||
// ErpPurchaseInventory 采购入库执行信息
|
||
type ErpPurchaseInventory struct {
|
||
Model
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id
|
||
ErpPurchaseCommodityId uint32 `json:"erp_purchase_commodity_id" gorm:"index"` // 采购订单商品表id
|
||
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
|
||
SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号
|
||
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"` // 商品串码
|
||
Count uint32 `json:"count"` // 执行数量
|
||
ImplementationPrice float64 `json:"implementation_price"` // 执行单价
|
||
Amount float64 `json:"amount"` // 执行金额
|
||
EmployeePrice float64 `json:"employee_price"` // 员工成本价
|
||
InventoryId uint32 `json:"inventory_id"` // 最近入库人id
|
||
InventoryName string `json:"inventory_name"` // 最近入库人名称
|
||
ErpStockCommodityID uint32 `json:"erp_stock_commodity_id"` // 库存商品表主键id
|
||
}
|
||
|
||
// ErpPurchaseCreateReq 新建采购订单入参
|
||
type ErpPurchaseCreateReq struct {
|
||
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
|
||
PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号:出库必传
|
||
StoreId uint32 `json:"store_id"` // 门店id:入库必传
|
||
DeliveryAddress string `json:"delivery_address"` // 交货地址:入库必传
|
||
HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id
|
||
HandlerName string `json:"handler_name"` // 经手人名称
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id:入库必传
|
||
ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式
|
||
AccountHolder string `json:"account_holder"` // 收款人:入库必传
|
||
OpeningBank string `json:"opening_bank"` // 开户行:入库必传
|
||
BankAccount string `json:"bank_account" ` // 银行卡号:入库必传
|
||
DeliveryTime string `json:"delivery_time" ` // 交货日期:入库必传
|
||
Remark string `json:"remark"` // 备注
|
||
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodity" binding:"required"` // 采购商品信息
|
||
}
|
||
|
||
// ErpPurchaseEditReq 编辑采购订单入参
|
||
type ErpPurchaseEditReq struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
|
||
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
|
||
PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号:出库必传
|
||
StoreId uint32 `json:"store_id"` // 门店id:入库必传
|
||
DeliveryAddress string `json:"delivery_address"` // 交货地址:入库必传
|
||
HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id
|
||
HandlerName string `json:"handler_name"` // 经手人名称
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id:入库必传
|
||
ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式
|
||
AccountHolder string `json:"account_holder"` // 收款人:入库必传
|
||
OpeningBank string `json:"opening_bank"` // 开户行:入库必传
|
||
BankAccount string `json:"bank_account" ` // 银行卡号:入库必传
|
||
DeliveryTime string `json:"delivery_time"` // 交货日期:入库必传
|
||
Remark string `json:"remark"` // 备注
|
||
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodity" binding:"required"` // 采购商品信息
|
||
}
|
||
|
||
// ErpPurchaseOrderListReq 查询采购订单列表入参
|
||
type ErpPurchaseOrderListReq struct {
|
||
SerialNumber string `json:"serial_number"` // 单据编号
|
||
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
|
||
StoreId uint32 `json:"store_id"` // 门店id
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
|
||
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
|
||
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
|
||
AuditFlag string `json:"audit_flag"` // 审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成/入库中
|
||
State []uint32 `json:"state"` // 状态:1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
|
||
HandlerId uint32 `json:"handler_id"` // 经手人id
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
}
|
||
|
||
// ErpPurchaseOrderListResp 查询采购订单列表出参
|
||
type ErpPurchaseOrderListResp struct {
|
||
List []ErpPurchaseOrder `json:"list"`
|
||
Total int `json:"total"` // 总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
}
|
||
|
||
// ErpPurchaseDetailReq 查询采购订单详情入参
|
||
type ErpPurchaseDetailReq struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
|
||
}
|
||
|
||
// ErpPurchaseInventoryReq 入库(退货)入参
|
||
type ErpPurchaseInventoryReq struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
|
||
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
|
||
InventoryId uint32 `json:"inventory_id"` // 最近入库人id
|
||
InventoryName string `json:"inventory_name"` // 最近入库人名称
|
||
Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息
|
||
}
|
||
|
||
// ErpPurchaseExecuteReq 执行(入库/退货)入参
|
||
type ErpPurchaseExecuteReq struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
|
||
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
|
||
Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息
|
||
}
|
||
|
||
// ErpPurchaseAuditReq 审核采购订单入参
|
||
type ErpPurchaseAuditReq struct {
|
||
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
|
||
State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核
|
||
}
|
||
|
||
// ErpPurchaseTerminateReq 终止采购入参
|
||
type ErpPurchaseTerminateReq struct {
|
||
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
|
||
Remark string `json:"remark" binding:"required"` // 备注
|
||
}
|
||
|
||
// ErpPurchaseDeleteReq 删除采购单入参
|
||
type ErpPurchaseDeleteReq struct {
|
||
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
|
||
}
|
||
|
||
// ErpPurchaseExecuteResp 执行(入库/退货)出参
|
||
type ErpPurchaseExecuteResp struct {
|
||
List []ExecuteData `json:"list"`
|
||
Total int `json:"total"` // 总条数
|
||
}
|
||
|
||
// ExecuteData 库存执行数据
|
||
type ExecuteData struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id
|
||
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
|
||
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
|
||
IMEI string `json:"imei"` // 商品串码
|
||
Count uint32 `json:"count"` // 数量
|
||
ImplementationPrice float64 `json:"implementation_price"` // 执行单价
|
||
EmployeePrice float64 `json:"employee_price"` // 员工成本价
|
||
}
|
||
|
||
// ErpPurchaseDemand 采购需求表
|
||
type ErpPurchaseDemand struct {
|
||
Model
|
||
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
|
||
ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号
|
||
ErpCommodityName string `json:"erp_commodity_name" gorm:"index"` // 商品名称
|
||
StoreId uint32 `json:"store_id"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
Count uint32 `json:"count"` // 需采购数量
|
||
State uint32 `json:"state"` // 1-待采购 2-已采购
|
||
MakerId uint32 `json:"maker_id"` // 制单人id
|
||
FinishTime *time.Time `json:"finish_time"` // 完成采购时间
|
||
//PurchaserId uint32 `json:"purchaser_id"` // 采购人id
|
||
//Remark string `json:"remark"` // 备注
|
||
}
|
||
|
||
// ErpPurchaseDemandRemark 采购需求备注表
|
||
type ErpPurchaseDemandRemark struct {
|
||
Model
|
||
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
|
||
State uint32 `json:"state"` // 1-待采购 2-已采购
|
||
MakerId uint32 `json:"maker_id"` // 制单人id
|
||
FinishTime *time.Time `json:"finish_time"` // 完成采购时间
|
||
Remark string `json:"remark"` // 备注
|
||
}
|
||
|
||
// GetErpPurchaseDemandReq 获取采购需求入参
|
||
type GetErpPurchaseDemandReq struct {
|
||
ErpCategoryId uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
HideFlag string `json:"hide_flag"` // 隐藏标记(默认关闭):ON-开启,隐藏无采购需求的商品,OFF-关闭,展示所有
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 每页展示数据条数
|
||
IsExport uint32 `json:"is_export"` // 1-导出
|
||
}
|
||
|
||
// DemandData 采购需求数据
|
||
type DemandData struct {
|
||
ErpCommodityID uint32 `json:"erp_commodity_id"` // 商品id
|
||
ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
|
||
RetailPrice float64 `json:"retail_price"` // 指导零售价
|
||
LastWholesalePrice float64 `json:"last_wholesale_price"` // 最近采购价
|
||
TotalCount uint32 `json:"total_count"` // 需采购总数量
|
||
TotalAmount float64 `json:"total_amount"` // 需采购总金额
|
||
Remark string `json:"remark"` // 备注
|
||
StoreList []struct {
|
||
StoreID uint32 `json:"store_id"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
LastMonthSales uint32 `json:"last_month_sales"` // 上月销售数
|
||
StockCount uint32 `json:"stock_count"` // 库存数量
|
||
NeedCount uint32 `json:"need_count"` // 需采购数
|
||
} `json:"store_list"`
|
||
}
|
||
|
||
// GetErpPurchaseDemandResp 获取采购需求出参
|
||
type GetErpPurchaseDemandResp struct {
|
||
List []DemandData `json:"list"`
|
||
Total int64 `json:"total"` // 数据总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 每页展示条数
|
||
ExportUrl string `json:"export_url"` // 文件路径
|
||
}
|
||
|
||
// CreateErpPurchaseDemandReq 创建采购需求入参
|
||
type CreateErpPurchaseDemandReq struct {
|
||
ErpCommodityID uint32 `json:"erp_commodity_id"` // 商品id
|
||
ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
Remark string `json:"remark"` // 备注
|
||
List []struct {
|
||
StoreID uint32 `json:"store_id"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
NeedCount uint32 `json:"need_count"` // 需采购数
|
||
} `json:"list"`
|
||
}
|
||
|
||
// FinishErpPurchaseDemandReq 完成采购需求入参
|
||
type FinishErpPurchaseDemandReq struct {
|
||
ErpCommodityID uint32 `json:"erp_commodity_id" binding:"required"` // 商品id
|
||
}
|
||
|
||
// ErpPurchaseReportByOrderReq 采购报表(按单)入参
|
||
type ErpPurchaseReportByOrderReq struct {
|
||
SerialNumber string `json:"serial_number"` // 单据编号
|
||
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
StoreId []uint32 `json:"store_id"` // 门店id
|
||
HandlerId uint32 `json:"handler_id"` // 经手人id
|
||
ErpSupplierId []uint32 `json:"erp_supplier_id"` // 供应商id
|
||
State uint32 `json:"state"` // 2-待入库 3-待退货 4-已完成 5-已终止
|
||
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
|
||
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
|
||
IsExport uint32 `json:"is_export"` // 1-导出
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
}
|
||
|
||
// ErpPurchaseReportByOrderResp 采购报表(按单)出参
|
||
type ErpPurchaseReportByOrderResp struct {
|
||
Total int `json:"total"` // 总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
Amount float64 `json:"amount"` // 已执行金额
|
||
Count int32 `json:"count"` // 已执行数量
|
||
ExportUrl string `json:"export_url"` // 导出excel路径
|
||
List []ReportByOrderData `json:"list"` // 采购报表信息
|
||
}
|
||
|
||
type ReportByOrderData struct {
|
||
CommonData
|
||
State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
|
||
Remark string `json:"remark"` // 备注
|
||
Amount float64 `json:"amount"` // 已执行金额
|
||
Price float64 `json:"price"` // 执行单价
|
||
Count int32 `json:"count"` // 已执行数量
|
||
CommodityData []ErpPurchaseCommodityData `json:"commodity_data"` // 商品信息
|
||
}
|
||
|
||
type CommodityData struct {
|
||
ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
|
||
}
|
||
|
||
type CommonData struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
|
||
SerialNumber string `json:"serial_number"` // 单据编号
|
||
PurchaseType string `json:"purchase_type"` // 单据类型:procure-采购 reject-退货
|
||
StoreId uint32 `json:"store_id"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
|
||
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
|
||
HandlerId uint32 `json:"handler_id"` // 经手人id
|
||
HandlerName string `json:"handler_name"` // 经手人名称
|
||
MakerTime *time.Time `json:"maker_time"` // 制单时间
|
||
MakerId uint32 `json:"maker_id"` // 制单人id
|
||
MakerName string `json:"maker_name"` // 制单人名称
|
||
AuditTime *time.Time `json:"audit_time"` // 审核时间
|
||
AuditorId uint32 `json:"auditor_id"` // 审核人id
|
||
AuditorName string `json:"auditor_name"` // 审核人名称
|
||
}
|
||
|
||
// ErpPurchaseCommodityData 采购订单商品信息
|
||
type ErpPurchaseCommodityData struct {
|
||
CommodityData
|
||
Amount float64 `json:"amount"` // 已执行金额
|
||
Price float64 `json:"price"` // 已执行单价
|
||
Count int32 `json:"count"` // 已执行数量
|
||
}
|
||
|
||
// ErpPurchaseReportByCommodityReq 采购报表(按商品)入参
|
||
type ErpPurchaseReportByCommodityReq struct {
|
||
SerialNumber string `json:"serial_number"` // 单据编号
|
||
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
StoreId []uint32 `json:"store_id"` // 门店id
|
||
HandlerId uint32 `json:"handler_id"` // 经手人id
|
||
ErpSupplierId []uint32 `json:"erp_supplier_id"` // 供应商id
|
||
State uint32 `json:"state"` // 2-待入库 3-待退货 4-已完成 5-已终止
|
||
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
|
||
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
|
||
IsExport uint32 `json:"is_export"` // 1-导出
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
}
|
||
|
||
// ErpPurchaseReportByCommodityResp 采购报表(按商品)出参
|
||
type ErpPurchaseReportByCommodityResp struct {
|
||
Total int `json:"total"` // 总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
PurchaseData
|
||
ExportUrl string `json:"export_url"` // 导出excel路径
|
||
List []ReportByCommodityData `json:"list"` // 采购报表信息
|
||
}
|
||
|
||
type ReportByCommodityData struct {
|
||
CommodityData
|
||
PurchaseData
|
||
OrderInfo []ErpCommodityPurchaseOrderData `json:"order_info"` // 采购订单信息
|
||
}
|
||
|
||
// ErpCommodityPurchaseOrderData 采购商品的订单信息
|
||
type ErpCommodityPurchaseOrderData struct {
|
||
CommonData
|
||
PurchaseData
|
||
}
|
||
|
||
type TempData struct {
|
||
CommodityData
|
||
ErpCommodityPurchaseOrderData
|
||
}
|
||
|
||
// PurchaseData 采购金额和数量
|
||
type PurchaseData struct {
|
||
OrderId uint32 `json:"order_id"` // 采购订单id
|
||
PlanCount int32 `json:"plan_count"` // 计划采购数量
|
||
PlanPrice float64 `json:"plan_price"` // 计划采购单价
|
||
PlanAmount float64 `json:"plan_amount"` // 计划采购金额
|
||
Amount float64 `json:"amount"` // 已执行金额
|
||
Price float64 `json:"price"` // 已执行单价
|
||
Count int32 `json:"count"` // 已执行数量
|
||
NonExecutionAmount float64 `json:"non_execution_amount"` // 未执行金额
|
||
NonExecutionCount int32 `json:"non_execution_count"` // 未执行数量
|
||
}
|
||
|
||
// ErpPurchaseReportBySupplierReq 供应商采购汇总入参
|
||
type ErpPurchaseReportBySupplierReq struct {
|
||
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
|
||
ErpCommodityName []string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID []uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpSupplierId []uint32 `json:"erp_supplier_id"` // 供应商id
|
||
StartTime string `json:"start_time"` // 入/出库,开始时间
|
||
EndTime string `json:"end_time"` // 入/出库,结束时间
|
||
IsExport uint32 `json:"is_export"` // 1-导出
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
StoreList []uint32 `json:"store_list"` // 门店复选
|
||
}
|
||
|
||
// ErpPurchaseReportBySupplierResp 供应商采购汇总出参
|
||
type ErpPurchaseReportBySupplierResp struct {
|
||
Total int `json:"total"` // 总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
Count int32 `json:"count"` // 采购数量
|
||
Amount float64 `json:"amount"` // 采购金额
|
||
RejectAmount float64 `json:"reject_amount"` // 退货金额
|
||
Difference float64 `json:"difference"` // 差额
|
||
ExportUrl string `json:"export_url"` // 导出excel路径
|
||
List []PurchaseReportData `json:"list"` // 供应商采购汇总信息
|
||
}
|
||
|
||
type PurchaseReportData struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
|
||
SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号
|
||
StoreId uint32 `json:"store_id"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
|
||
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
|
||
ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
|
||
Count int32 `json:"count"` // 采购数量
|
||
Amount float64 `json:"amount"` // 采购金额
|
||
RejectAmount float64 `json:"reject_amount"` // 退货金额
|
||
Difference float64 `json:"difference"` // 差额
|
||
}
|
||
|
||
// ErpPurchaseReportDetailReq 采购明细入参
|
||
type ErpPurchaseReportDetailReq struct {
|
||
SerialNumber string `json:"serial_number"` // 单据编号
|
||
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
|
||
IMEI string `json:"imei"` // 串码
|
||
StartTime string `json:"startTime"` // 入/出库,开始时间
|
||
EndTime string `json:"endTime"` // 入/出库,结束时间
|
||
IsExport uint32 `json:"is_export"` // 1-导出
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
StoreId []uint32 `json:"store_id"` // 门店id
|
||
}
|
||
|
||
// ErpPurchaseReportDetailResp 采购明细出参
|
||
type ErpPurchaseReportDetailResp struct {
|
||
Total int `json:"total"` // 总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 页面条数
|
||
Price float64 `json:"price"` // 采购价
|
||
EmployeePrice float64 `json:"employee_price"` // 员工成本价
|
||
RejectPrice float64 `json:"reject_price"` // 退货价
|
||
DifferencePrice float64 `json:"difference_price"` // 差价
|
||
ExportUrl string `json:"export_url"` // 导出excel路径
|
||
List []struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
|
||
OrderSerialNumber string `json:"order_serial_number"` // 单据编号
|
||
SerialNumber string `json:"serial_number"` // 采购入库编号
|
||
PurchaseType string `json:"purchase_type"` // 单据类型:procure-采购 reject-退货
|
||
ExecuteTime *time.Time `json:"execute_time"` // 出/入库时间
|
||
StoreId uint32 `json:"store_id"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
|
||
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
|
||
ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id
|
||
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
|
||
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
|
||
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
|
||
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
|
||
IMEI string `json:"imei"` // 商品串码
|
||
Price float64 `json:"price"` // 采购价
|
||
EmployeePrice float64 `json:"employee_price"` // 员工成本价
|
||
RejectPrice float64 `json:"reject_price"` // 退货价
|
||
DifferencePrice float64 `json:"difference_price"` // 差价
|
||
} `json:"list"` // 采购明细信息
|
||
}
|
||
|
||
// List 查询采购订单列表
|
||
func (m *ErpPurchaseOrderListReq) List(c *gin.Context) (*ErpPurchaseOrderListResp, error) {
|
||
resp := &ErpPurchaseOrderListResp{
|
||
PageIndex: m.PageIndex,
|
||
PageSize: m.PageSize,
|
||
}
|
||
page := m.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if m.PageSize == 0 {
|
||
m.PageSize = 10
|
||
}
|
||
qs := orm.Eloquent.Table("erp_purchase_order")
|
||
var stateList []int
|
||
if m.AuditFlag == "ON" { //2-待入库 4-已完成 5-已终止 6-入库中
|
||
stateList = []int{2, 4, 5, 6}
|
||
qs = qs.Where("state IN ?", stateList)
|
||
qs = qs.Where("purchase_type=?", ErpProcureOrder)
|
||
}
|
||
if m.SerialNumber != "" {
|
||
qs = qs.Where("serial_number=?", m.SerialNumber)
|
||
} else {
|
||
if m.PurchaseType != "" {
|
||
qs = qs.Where("purchase_type=?", m.PurchaseType)
|
||
}
|
||
if m.StoreId != 0 {
|
||
qs = qs.Where("store_id=?", m.StoreId)
|
||
}
|
||
// 非管理员才判断所属门店
|
||
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
|
||
sysUser, err := GetSysUserByCtx(c)
|
||
if err != nil {
|
||
return nil, errors.New("操作失败:" + err.Error())
|
||
}
|
||
|
||
// 返回sysUser未过期的门店id列表
|
||
storeList := GetValidStoreIDs(sysUser.StoreData)
|
||
if len(storeList) > 0 {
|
||
qs = qs.Where("store_id IN (?)", storeList)
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
if m.ErpSupplierId != 0 {
|
||
qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId)
|
||
}
|
||
if len(m.State) > 0 {
|
||
qs = qs.Where("state IN (?)", m.State)
|
||
}
|
||
if m.AuditTimeStart != "" {
|
||
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
|
||
if err != nil {
|
||
logger.Errorf("erpPurchaseOrderList err:", err)
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("audit_time > ?", parse)
|
||
}
|
||
if m.AuditTimeEnd != "" {
|
||
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
|
||
if err != nil {
|
||
logger.Errorf("erpPurchaseOrderList err:", err)
|
||
return nil, err
|
||
}
|
||
//parse = parse.AddDate(0, 0, 1)
|
||
qs = qs.Where("audit_time < ?", parse)
|
||
}
|
||
if m.HandlerId != 0 {
|
||
qs = qs.Where("handler_id=?", m.HandlerId)
|
||
}
|
||
}
|
||
|
||
var count int64
|
||
err := qs.Count(&count).Error
|
||
if err != nil {
|
||
logger.Error("count err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
resp.Total = int(count)
|
||
var orders []ErpPurchaseOrder
|
||
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("erp commodity list err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
// 校验时间,如果为01-01-01 08:05,则赋值为空
|
||
for i, v := range orders {
|
||
if v.MakerTime != nil && v.MakerTime.IsZero() {
|
||
orders[i].MakerTime = nil
|
||
}
|
||
|
||
if v.AuditTime != nil && v.AuditTime.IsZero() {
|
||
orders[i].AuditTime = nil
|
||
}
|
||
}
|
||
|
||
resp.List = orders
|
||
return resp, nil
|
||
}
|
||
|
||
// newErpPurchaseSn 生成采购订单号
|
||
func newErpPurchaseSn(purchaseType string) string {
|
||
var prefix string
|
||
switch purchaseType {
|
||
case ErpProcureOrder: // 采购入库订单
|
||
prefix = "cgr"
|
||
case ErpRejectOrder: // 采购退货订单
|
||
prefix = "cgt"
|
||
}
|
||
|
||
nowTime := time.Now()
|
||
rand.Seed(nowTime.UnixNano())
|
||
max := 1
|
||
for {
|
||
if max > 5 {
|
||
logger.Error("create sn err")
|
||
return ""
|
||
}
|
||
random := rand.Intn(9000) + 1000
|
||
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE "+
|
||
"serial_number='%s'", prefix+sn))
|
||
if err != nil {
|
||
logger.Error("exist sn err")
|
||
}
|
||
if !exist {
|
||
return prefix + sn
|
||
}
|
||
|
||
max++
|
||
}
|
||
}
|
||
|
||
func ErpPurchaseCommodityListPerfectInfo(serialNumber string, purchaseCommodities []ErpPurchaseCommodity) error {
|
||
commodityIds := make([]uint32, 0, len(purchaseCommodities))
|
||
for i, _ := range purchaseCommodities {
|
||
commodityIds = append(commodityIds, purchaseCommodities[i].ID)
|
||
}
|
||
commodityMap, err := GetErpCommodityMap(commodityIds)
|
||
if err != nil {
|
||
logger.Error("purchase commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
for i, _ := range purchaseCommodities {
|
||
if serialNumber != "" { // 采购退货单才需判断
|
||
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
|
||
nCount, err := GetCommodityStockByPurchaseId(serialNumber, purchaseCommodities[i].ErpCommodityId)
|
||
if err != nil {
|
||
logger.Error("ErpPurchaseCommodityListPerfectInfo GetCommodityStockByPurchaseId err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
// 如果库存数量不够则报错
|
||
if nCount < purchaseCommodities[i].RejectedCount {
|
||
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", purchaseCommodities[i].ErpCommodityName)
|
||
}
|
||
}
|
||
|
||
v, ok := commodityMap[purchaseCommodities[i].ErpCommodityId]
|
||
if ok {
|
||
purchaseCommodities[i].CommoditySerialNumber = v.SerialNumber
|
||
purchaseCommodities[i].IMEIType = v.IMEIType
|
||
//purchaseCommodities[i].IMEI = v.IMEI
|
||
purchaseCommodities[i].ErpCommodityName = v.Name
|
||
if purchaseCommodities[i].Count != 0 {
|
||
purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price
|
||
}
|
||
if purchaseCommodities[i].RejectedCount != 0 {
|
||
purchaseCommodities[i].RejectedAmount = float64(purchaseCommodities[i].RejectedCount) * purchaseCommodities[i].RejectedPrice
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// IdInit 添加商户和供应商信息
|
||
func (m *ErpPurchaseOrder) IdInit() error {
|
||
if m.StoreId != 0 {
|
||
store, err := GetStore(m.StoreId)
|
||
if err != nil {
|
||
logger.Error("get store err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
m.StoreName = store.Name
|
||
}
|
||
|
||
if m.ErpSupplierId != 0 {
|
||
supplier, err := GetErpSupplier(m.ErpSupplierId)
|
||
if err != nil {
|
||
logger.Error("get supplier err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
m.ErpSupplierName = supplier.Name
|
||
}
|
||
|
||
if m.ErpCashierId != 0 {
|
||
cashier, err := GetAccountDetail(int(m.ErpCashierId))
|
||
if err != nil {
|
||
logger.Error("get cashier err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
m.ErpCashierName = cashier.Name
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// GetPurchaseInventorySn 生成入库编号
|
||
func GetPurchaseInventorySn() string {
|
||
count := 0
|
||
for {
|
||
if count > 5 {
|
||
return ""
|
||
}
|
||
nowTime := time.Now()
|
||
sn := nowTime.Format("060102")
|
||
sn += fmt.Sprintf("%d", nowTime.Unix()%100)
|
||
rand.Seed(nowTime.UnixNano())
|
||
sn += fmt.Sprintf("%d", rand.Int31n(100))
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_inventory WHERE serial_number='%s'", sn))
|
||
if err != nil {
|
||
logger.Error("sn err:", logger.Field("err", err))
|
||
count++
|
||
continue
|
||
}
|
||
if err == nil && !exist {
|
||
return sn
|
||
}
|
||
return ""
|
||
}
|
||
}
|
||
|
||
// CheckCreateErpPurchaseOrderParam 新增采购订单-检查参数
|
||
func CheckCreateErpPurchaseOrderParam(req *ErpPurchaseCreateReq) error {
|
||
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
|
||
if req.StoreId == 0 {
|
||
return errors.New("操作失败:门店id为空")
|
||
}
|
||
if req.DeliveryAddress == "" {
|
||
return errors.New("操作失败:交货地址为空")
|
||
}
|
||
if req.ErpSupplierId == 0 {
|
||
return errors.New("操作失败:供应商id为空")
|
||
}
|
||
if req.AccountHolder == "" {
|
||
return errors.New("操作失败:收款人为空")
|
||
}
|
||
if req.OpeningBank == "" {
|
||
return errors.New("操作失败:开户行为空")
|
||
}
|
||
if req.BankAccount == "" {
|
||
return errors.New("操作失败:银行卡号为空")
|
||
}
|
||
if req.DeliveryTime == "" {
|
||
return errors.New("操作失败:交货日期为空")
|
||
}
|
||
for _, item := range req.ErpPurchaseCommodities {
|
||
if item.Count <= 0 {
|
||
return errors.New("操作失败:采购数量需大于0")
|
||
}
|
||
}
|
||
} else if req.PurchaseType == ErpRejectOrder { // 退货单
|
||
if req.PurchaseOrderSn == "" {
|
||
return errors.New("操作失败:采购退货单据编号为空")
|
||
}
|
||
for _, item := range req.ErpPurchaseCommodities {
|
||
if item.RejectedCount <= 0 {
|
||
return errors.New("操作失败:采购退货数量需大于0")
|
||
}
|
||
}
|
||
} else {
|
||
return errors.New("操作失败:采购类型有误")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// CheckEditErpPurchaseOrderParam 编辑采购订单-检查参数
|
||
func CheckEditErpPurchaseOrderParam(req *ErpPurchaseEditReq) error {
|
||
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
|
||
if req.StoreId == 0 {
|
||
return errors.New("操作失败:门店id为空")
|
||
}
|
||
if req.DeliveryAddress == "" {
|
||
return errors.New("操作失败:交货地址为空")
|
||
}
|
||
if req.ErpSupplierId == 0 {
|
||
return errors.New("操作失败:供应商id为空")
|
||
}
|
||
if req.AccountHolder == "" {
|
||
return errors.New("操作失败:收款人为空")
|
||
}
|
||
if req.OpeningBank == "" {
|
||
return errors.New("操作失败:开户行为空")
|
||
}
|
||
if req.BankAccount == "" {
|
||
return errors.New("操作失败:银行卡号为空")
|
||
}
|
||
if req.DeliveryTime == "" {
|
||
return errors.New("操作失败:交货日期为空")
|
||
}
|
||
} else if req.PurchaseType == ErpRejectOrder { // 退货单
|
||
if req.PurchaseOrderSn == "" {
|
||
return errors.New("操作失败:采购退货单据编号为空")
|
||
}
|
||
} else {
|
||
return errors.New("操作失败:采购类型有误")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// CreateErpPurchaseOrder 新增采购订单
|
||
func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
|
||
var err error
|
||
nowTime := time.Now()
|
||
|
||
purchaseOrder := &ErpPurchaseOrder{}
|
||
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
|
||
purchaseOrder = &ErpPurchaseOrder{
|
||
SerialNumber: newErpPurchaseSn(req.PurchaseType),
|
||
PurchaseType: req.PurchaseType,
|
||
StoreId: req.StoreId,
|
||
ErpSupplierId: req.ErpSupplierId,
|
||
MakerTime: &nowTime,
|
||
HandlerId: req.HandlerId,
|
||
HandlerName: req.HandlerName,
|
||
MakerId: uint32(sysUser.UserId),
|
||
MakerName: sysUser.NickName,
|
||
State: ErpPurchaseOrderUnAudit, // 1-待审核
|
||
ErpCashierId: req.ErpCashierId,
|
||
AccountHolder: req.AccountHolder,
|
||
OpeningBank: req.OpeningBank,
|
||
BankAccount: req.BankAccount,
|
||
DeliveryTime: req.DeliveryTime,
|
||
DeliveryAddress: req.DeliveryAddress,
|
||
Remark: req.Remark,
|
||
}
|
||
err = purchaseOrder.IdInit()
|
||
} else if req.PurchaseType == ErpRejectOrder { // 采购退货订单
|
||
if req.PurchaseOrderSn == "" {
|
||
return nil, errors.New("新建失败:采购退货订单号为空")
|
||
}
|
||
var erpPurchaseOrder ErpPurchaseOrder
|
||
err = orm.Eloquent.Table("erp_purchase_order").Where("serial_number=?", req.PurchaseOrderSn).Find(&erpPurchaseOrder).Error
|
||
if err != nil {
|
||
logger.Error("purchase order err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
purchaseOrder = &ErpPurchaseOrder{
|
||
SerialNumber: newErpPurchaseSn(req.PurchaseType),
|
||
PurchaseType: req.PurchaseType,
|
||
StoreId: erpPurchaseOrder.StoreId,
|
||
ErpSupplierId: erpPurchaseOrder.ErpSupplierId,
|
||
MakerTime: &nowTime,
|
||
HandlerId: req.HandlerId,
|
||
HandlerName: req.HandlerName,
|
||
MakerId: uint32(sysUser.UserId),
|
||
MakerName: sysUser.NickName,
|
||
State: ErpPurchaseOrderUnAudit, // 1-待审核
|
||
ErpCashierId: req.ErpCashierId,
|
||
Remark: req.Remark,
|
||
RejectedSerialNumber: req.PurchaseOrderSn,
|
||
}
|
||
err = purchaseOrder.IdInit()
|
||
} else {
|
||
logger.Errorf("purchase_type err:", req.PurchaseType)
|
||
return nil, errors.New("操作失败:采购类型有误")
|
||
}
|
||
|
||
if err != nil {
|
||
logger.Error("info err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
err = ErpPurchaseCommodityListPerfectInfo(req.PurchaseOrderSn, req.ErpPurchaseCommodities)
|
||
if err != nil {
|
||
logger.Error("info err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
begin := orm.Eloquent.Begin()
|
||
err = begin.Create(purchaseOrder).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("create purchase order err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
for i, _ := range req.ErpPurchaseCommodities {
|
||
req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = purchaseOrder.ID
|
||
req.ErpPurchaseCommodities[i].InventoryCount = 0 // todo 数量待核实
|
||
err = begin.Create(&req.ErpPurchaseCommodities[i]).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("create purchase commodity err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
}
|
||
err = begin.Commit().Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("commit purchase commodity err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
return purchaseOrder, nil
|
||
}
|
||
|
||
// EditErpPurchaseOrder 编辑采购订单
|
||
func EditErpPurchaseOrder(req *ErpPurchaseEditReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
|
||
// 查询订单信息
|
||
var purchaseOrder ErpPurchaseOrder
|
||
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
logger.Error("purchase order err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
if purchaseOrder.State != ErpPurchaseOrderUnAudit { // 只有待审核的订单才能编辑
|
||
return nil, errors.New("订单不是待审核状态")
|
||
}
|
||
|
||
if req.StoreId == 0 && req.PurchaseType == ErpProcureOrder {
|
||
return nil, errors.New("操作失败:门店id为空")
|
||
}
|
||
|
||
begin := orm.Eloquent.Begin()
|
||
// 1-更新采购订单信息
|
||
purchaseOrder.StoreId = req.StoreId
|
||
purchaseOrder.ErpSupplierId = req.ErpSupplierId
|
||
purchaseOrder.HandlerId = req.HandlerId
|
||
purchaseOrder.HandlerName = req.HandlerName
|
||
purchaseOrder.MakerId = uint32(sysUser.UserId)
|
||
purchaseOrder.MakerName = sysUser.NickName
|
||
purchaseOrder.ErpCashierId = req.ErpCashierId
|
||
purchaseOrder.AccountHolder = req.AccountHolder
|
||
purchaseOrder.OpeningBank = req.OpeningBank
|
||
purchaseOrder.BankAccount = req.BankAccount
|
||
purchaseOrder.DeliveryTime = req.DeliveryTime
|
||
purchaseOrder.DeliveryAddress = req.DeliveryAddress
|
||
purchaseOrder.Remark = req.Remark
|
||
err = purchaseOrder.IdInit()
|
||
if err != nil {
|
||
logger.Error("purchase IdInit err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
err = begin.Model(&ErpPurchaseOrder{}).Where("id = ?", req.ErpPurchaseOrderId).Updates(purchaseOrder).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("update erp_order err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
// 2-更新采购订单商品表
|
||
err = updatePurchaseCommodityData(begin, req.ErpPurchaseOrderId, req)
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("update erp_purchase_commodity err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
err = begin.Commit().Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("commit err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
return &purchaseOrder, nil
|
||
}
|
||
|
||
// updatePurchaseCommodityData 更新采购订单商品信息
|
||
func updatePurchaseCommodityData(gdb *gorm.DB, orderId uint32, req *ErpPurchaseEditReq) error {
|
||
// 查询现有的零售订单信息
|
||
var commodities []ErpPurchaseCommodity
|
||
err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error
|
||
if err != nil {
|
||
logger.Error("query erp_purchase_commodity err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
var newCommodities []ErpPurchaseCommodity
|
||
var deletedCommodities []ErpPurchaseCommodity
|
||
var matchingCommodities []ErpPurchaseCommodity
|
||
// 找到新增的商品
|
||
for i, reqCommodity := range req.ErpPurchaseCommodities {
|
||
// 订单商品表信息添加零售订单id
|
||
req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = orderId
|
||
|
||
var found bool
|
||
for _, dbCommodity := range commodities {
|
||
if reqCommodity.ErpCommodityId == dbCommodity.ErpCommodityId {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
if !found {
|
||
newCommodities = append(newCommodities, reqCommodity)
|
||
}
|
||
}
|
||
|
||
// 找到删除的商品
|
||
for _, dbCommodity := range commodities {
|
||
var found bool
|
||
for _, reqCommodity := range req.ErpPurchaseCommodities {
|
||
if reqCommodity.ID == dbCommodity.ID { // 应该是比较商品id,前端入参如果有主键id也可以比较
|
||
//if reqCommodity.ErpCommodityId == dbCommodity.ErpCommodityId {
|
||
found = true
|
||
// 找到匹配的商品,加入匹配列表
|
||
matchingCommodities = append(matchingCommodities, reqCommodity)
|
||
break
|
||
}
|
||
}
|
||
if !found {
|
||
deletedCommodities = append(deletedCommodities, dbCommodity)
|
||
}
|
||
}
|
||
|
||
// 2-更新商品订单信息-更新
|
||
for _, commodity := range matchingCommodities {
|
||
if err := gdb.Model(&ErpPurchaseCommodity{}).Where("id = ?", commodity.ID).Updates(commodity).Error; err != nil {
|
||
logger.Error("更新商品订单信息-更新 error")
|
||
return errors.New("操作失败:" + err.Error())
|
||
}
|
||
}
|
||
|
||
// 2-更新商品订单信息-新增
|
||
if len(newCommodities) != 0 {
|
||
err = gdb.Create(&newCommodities).Error
|
||
if err != nil {
|
||
logger.Error("更新商品订单信息-新增 error")
|
||
return errors.New("操作失败:" + err.Error())
|
||
}
|
||
}
|
||
|
||
//2-更新商品订单信息-删除
|
||
if len(deletedCommodities) != 0 {
|
||
err = gdb.Delete(&deletedCommodities).Error
|
||
if err != nil {
|
||
logger.Error("更新商品订单信息-删除 error")
|
||
return errors.New("操作失败:" + err.Error())
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// InventoryErpPurchase 采购订单入库
|
||
func InventoryErpPurchase(req *ErpPurchaseInventoryReq, c *gin.Context) error {
|
||
// 查询采购订单信息
|
||
var purchaseOrder ErpPurchaseOrder
|
||
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
logger.Error("purchase order err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
// 校验入参门店是否包含在用户所有门店中,是否过期
|
||
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
|
||
sysUser, err := GetSysUserByCtx(c)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if !CheckUserStore(purchaseOrder.StoreId, sysUser) {
|
||
return errors.New("操作失败:您没有该门店权限")
|
||
}
|
||
}
|
||
|
||
err = checkPurchaseInventory(req)
|
||
if err != nil {
|
||
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
begin := orm.Eloquent.Begin()
|
||
var inventoryList []ErpPurchaseInventory
|
||
for i, v := range req.Inventories {
|
||
req.Inventories[i].SerialNumber = v.SerialNumber
|
||
// 更新采购商品表的执行数量
|
||
// todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息,可能采购价不同,需要区分入库的是哪一条(已修改)
|
||
err = begin.Model(&ErpPurchaseCommodity{}).
|
||
Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
|
||
UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("update inventory count err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
v.PurchaseType = req.PurchaseType // 记录采购类型
|
||
v.InventoryId = req.InventoryId // 记录入库人id
|
||
v.InventoryName = req.InventoryName // 记录入库人姓名
|
||
|
||
nCount := v.Count
|
||
nAmount := v.Amount
|
||
for j := 0; j < int(nCount); j++ { // 采购入库记录表都是单笔数据
|
||
if v.PurchaseType == ErpProcureOrder {
|
||
v.SerialNumber = GetPurchaseInventorySn()
|
||
} else {
|
||
v.SerialNumber = purchaseOrder.SerialNumber
|
||
}
|
||
|
||
v.ID = 0
|
||
v.Count = 1
|
||
v.Amount = nAmount / float64(nCount) // 前端传的执行金额是总金额
|
||
// 新建采购入库记录
|
||
err = begin.Create(&v).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("create erp inventory commodity err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
inventoryList = append(inventoryList, v)
|
||
}
|
||
}
|
||
|
||
// 更新库存信息表
|
||
if purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单
|
||
err = InventoryErpPurchaseUpdateStock(begin, inventoryList, purchaseOrder)
|
||
} else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单
|
||
err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder)
|
||
} else {
|
||
return errors.New("订单类型有误")
|
||
}
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("update stock err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
err = begin.Commit().Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("commit err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
// 查询采购订单商品表入库或退库情况,如果都已经完成了,则更新采购订单的状态为:已完成
|
||
_ = CheckAndUpdatePurchaseOrderState(req.ErpPurchaseOrderId)
|
||
|
||
return nil
|
||
}
|
||
|
||
// CheckAndUpdatePurchaseOrderState
|
||
// 查询采购订单商品表入库或退库情况,如果都已经完成了,则更新采购订单的状态为:已完成
|
||
func CheckAndUpdatePurchaseOrderState(orderId uint32) error {
|
||
var order ErpPurchaseOrder
|
||
if err := orm.Eloquent.Where("id = ?", orderId).First(&order).Error; err != nil {
|
||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||
return fmt.Errorf("purchase order with ID %d not found", orderId)
|
||
}
|
||
return err
|
||
}
|
||
|
||
if order.State == ErpPurchaseOrderFinished {
|
||
return nil // Order is already marked as completed
|
||
}
|
||
|
||
var commodities []ErpPurchaseCommodity
|
||
if err := orm.Eloquent.Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error; err != nil {
|
||
return err
|
||
}
|
||
|
||
for _, commodity := range commodities {
|
||
if (order.PurchaseType == "procure" && commodity.Count != uint32(commodity.InventoryCount)) ||
|
||
(order.PurchaseType == "reject" && commodity.RejectedCount != uint32(commodity.InventoryCount)) {
|
||
return nil // Order not completed, exit early
|
||
}
|
||
}
|
||
|
||
// If all commodities are checked and everything is in order, update the state to completed
|
||
if err := orm.Eloquent.Model(&order).Update("state", ErpPurchaseOrderFinished).Update("audit_time", time.Now()).Error; err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GetInventoryIdAndName 获取采购单最近入库人信息
|
||
func GetInventoryIdAndName(orderId uint32) (uint32, string, error) {
|
||
var purchaseInventory ErpPurchaseInventory
|
||
err := orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", orderId).
|
||
Order("created_at DESC").First(&purchaseInventory).Error
|
||
if err != nil {
|
||
logger.Error("purchase order err:", logger.Field("err", err))
|
||
return 0, "", err
|
||
}
|
||
|
||
return purchaseInventory.InventoryId, purchaseInventory.InventoryName, nil
|
||
}
|
||
|
||
// InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息
|
||
func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
|
||
// 遍历采购入库商品信息
|
||
var stockList []ErpStockCommodity
|
||
var waitCreateStockList []ErpStock
|
||
for _, v := range list {
|
||
commodityInfo, err := GetCommodity(v.ErpCommodityId)
|
||
if err != nil {
|
||
logger.Errorf("GetCommodity err:", err)
|
||
return err
|
||
}
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
|
||
purchaseOrder.StoreId, v.ErpCommodityId))
|
||
if err != nil {
|
||
logger.Errorf("exist err:", err)
|
||
return err
|
||
}
|
||
if exist {
|
||
err = gdb.Exec(fmt.Sprintf(
|
||
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d",
|
||
v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error
|
||
if err != nil {
|
||
logger.Errorf("update stock err:", err)
|
||
return err
|
||
}
|
||
} else {
|
||
// 如果同时入库多个商品,刚好之前又没有记录,则可能生成多条记录
|
||
stock := ErpStock{
|
||
StoreId: purchaseOrder.StoreId,
|
||
StoreName: purchaseOrder.StoreName,
|
||
ErpCommodityId: v.ErpCommodityId,
|
||
ErpCommodityName: v.ErpCommodityName,
|
||
ErpCategoryId: commodityInfo.ErpCategoryId,
|
||
ErpCategoryName: commodityInfo.ErpCategoryName,
|
||
CommoditySerialNumber: v.CommoditySerialNumber,
|
||
IMEIType: v.IMEIType,
|
||
RetailPrice: commodityInfo.RetailPrice,
|
||
MinRetailPrice: commodityInfo.MinRetailPrice,
|
||
Count: v.Count,
|
||
DispatchCount: 0,
|
||
}
|
||
|
||
waitCreateStockList = append(waitCreateStockList, stock)
|
||
//err = gdb.Create(stock).Error
|
||
//if err != nil {
|
||
// logger.Errorf("create stock err:", err)
|
||
// return err
|
||
//}
|
||
}
|
||
|
||
nowTime := time.Now()
|
||
stockCommodity := ErpStockCommodity{
|
||
StoreId: purchaseOrder.StoreId,
|
||
StoreName: purchaseOrder.StoreName,
|
||
ErpCommodityId: v.ErpCommodityId,
|
||
ErpCommodityName: v.ErpCommodityName,
|
||
CommoditySerialNumber: v.CommoditySerialNumber,
|
||
ErpCategoryId: commodityInfo.ErpCategoryId,
|
||
ErpCategoryName: commodityInfo.ErpCategoryName,
|
||
ErpSupplierId: purchaseOrder.ErpSupplierId,
|
||
ErpSupplierName: purchaseOrder.ErpSupplierName,
|
||
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.ImplementationPrice),
|
||
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.ImplementationPrice),
|
||
State: InStock,
|
||
StorageType: PurchaseInventory, // 采购入库
|
||
FirstStockTime: nowTime,
|
||
StockTime: nowTime,
|
||
Count: v.Count,
|
||
ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码
|
||
IMEIType: v.IMEIType,
|
||
IMEI: v.IMEI,
|
||
Remark: "",
|
||
MemberDiscount: commodityInfo.MemberDiscount,
|
||
MinRetailPrice: commodityInfo.MinRetailPrice,
|
||
RetailPrice: commodityInfo.RetailPrice,
|
||
OriginalSn: purchaseOrder.SerialNumber,
|
||
StockSn: v.SerialNumber,
|
||
}
|
||
stockList = append(stockList, stockCommodity)
|
||
}
|
||
|
||
// 遍历库存信息,合并重复数据
|
||
if len(waitCreateStockList) > 0 {
|
||
newStockList := combineStocks(waitCreateStockList)
|
||
err := gdb.Debug().Create(&newStockList).Error
|
||
if err != nil {
|
||
logger.Errorf("create erp_stock err:", err)
|
||
return err
|
||
}
|
||
}
|
||
|
||
err := gdb.Debug().Create(&stockList).Error
|
||
if err != nil {
|
||
logger.Errorf("create erp_stock_commodity err:", err)
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func combineStocks(waitCreateStockList []ErpStock) []ErpStock {
|
||
// 创建一个map,用于存储相同 StoreId 和 ErpCommodityId 的库存信息
|
||
stockMap := make(map[string]*ErpStock)
|
||
|
||
// 遍历待处理的库存列表
|
||
for _, stock := range waitCreateStockList {
|
||
// 构建库存信息的唯一标识
|
||
key := fmt.Sprintf("%d_%d", stock.StoreId, stock.ErpCommodityId)
|
||
|
||
// 如果该库存信息已经存在于 map 中,则累加数量
|
||
if existingStock, found := stockMap[key]; found {
|
||
existingStock.Count += stock.Count
|
||
} else {
|
||
// 否则,将该库存信息添加到 map 中
|
||
stockMap[key] = &ErpStock{
|
||
StoreId: stock.StoreId,
|
||
StoreName: stock.StoreName,
|
||
ErpCommodityId: stock.ErpCommodityId,
|
||
ErpCommodityName: stock.ErpCommodityName,
|
||
ErpCategoryId: stock.ErpCategoryId,
|
||
ErpCategoryName: stock.ErpCategoryName,
|
||
CommoditySerialNumber: stock.CommoditySerialNumber,
|
||
IMEIType: stock.IMEIType,
|
||
RetailPrice: stock.RetailPrice,
|
||
MinRetailPrice: stock.MinRetailPrice,
|
||
Count: stock.Count,
|
||
DispatchCount: stock.DispatchCount,
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将 map 中的库存信息转换为列表
|
||
var combinedStocks []ErpStock
|
||
for _, stock := range stockMap {
|
||
combinedStocks = append(combinedStocks, *stock)
|
||
}
|
||
|
||
return combinedStocks
|
||
}
|
||
|
||
// InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息
|
||
func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
|
||
usedStockCommodityIdList := make(map[uint32]bool)
|
||
for i, _ := range list {
|
||
if list[i].IMEIType == 2 { // 串码商品
|
||
if list[i].IMEI == "" {
|
||
return errors.New("串码为空")
|
||
}
|
||
|
||
// 判断该串码商品是否已经销售
|
||
var stockCommodityInfo ErpStockCommodity
|
||
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI).
|
||
Find(&stockCommodityInfo).Error
|
||
if err != nil {
|
||
logger.Error("Inventory RejectStock query commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
if stockCommodityInfo.State == SoldOut {
|
||
return fmt.Errorf("商品[%s]已经销售,不能退货", stockCommodityInfo.ErpCommodityName)
|
||
}
|
||
//else if stockCommodityInfo.State == OnSale {
|
||
// return fmt.Errorf("商品[%s]在销售锁定中,不能退货", stockCommodityInfo.ErpCommodityName)
|
||
//}
|
||
|
||
err = gdb.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI).
|
||
Updates(&map[string]interface{}{
|
||
"state": PurchaseReturn,
|
||
"stock_sn": list[i].SerialNumber,
|
||
}).Error // 状态更新为采购退货
|
||
if err != nil {
|
||
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
|
||
purchaseOrder.StoreId, list[i].ErpCommodityId).
|
||
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
|
||
if err != nil {
|
||
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
} else {
|
||
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
|
||
nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, list[i].ErpCommodityId)
|
||
if err != nil {
|
||
logger.Error("InventoryErpPurchaseUpdateRejectStock GetCommodityStockByPurchaseId err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
// 如果库存数量不够则报错
|
||
if nCount < list[i].Count {
|
||
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", list[i].ErpCommodityName)
|
||
}
|
||
|
||
var stockCommodity []ErpStockCommodity
|
||
//// 通过门店id,商品id,查找状态为1-在库的非串码商品
|
||
//err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
|
||
// "and state = ? and imei_type = ? ", list[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1).
|
||
// Order("id DESC").Find(&stockCommodity).Error
|
||
|
||
// 通过首次入库订单编号,查找状态为1-在库的非串码商品
|
||
err = orm.Eloquent.Table("erp_stock_commodity").
|
||
Where("erp_commodity_id = ? and state = ? and imei_type = ? and original_sn = ?",
|
||
list[i].ErpCommodityId, InStock, 1, purchaseOrder.RejectedSerialNumber).
|
||
Order("id DESC").Find(&stockCommodity).Error
|
||
if err != nil {
|
||
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
if stockCommodity == nil {
|
||
return errors.New("RetailTypeRejected find no stock commodity")
|
||
}
|
||
|
||
var currentID uint32
|
||
// 找一个可用的库存ID
|
||
for _, item := range stockCommodity {
|
||
_, ok := usedStockCommodityIdList[item.ID]
|
||
if !ok {
|
||
usedStockCommodityIdList[item.ID] = true
|
||
currentID = item.ID
|
||
break
|
||
} else {
|
||
continue
|
||
}
|
||
}
|
||
if currentID == 0 {
|
||
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", list[i].ErpCommodityName)
|
||
}
|
||
err = gdb.Table("erp_stock_commodity").Where("id = ?", currentID).Updates(&map[string]interface{}{
|
||
"state": PurchaseReturn,
|
||
"stock_sn": list[i].SerialNumber,
|
||
}).Error // 状态更新为采购退货
|
||
if err != nil {
|
||
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
|
||
purchaseOrder.StoreId, list[i].ErpCommodityId).
|
||
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
|
||
if err != nil {
|
||
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 校验入参数据,执行数量是否超过总数;串码商品的串码是否重复
|
||
func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error {
|
||
// 查询现有的零售订单信息
|
||
var commodities []ErpPurchaseCommodity
|
||
err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", req.ErpPurchaseOrderId).Find(&commodities).Error
|
||
if err != nil {
|
||
logger.Error("query erp_purchase_commodity err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
countMap := make(map[uint32]uint32)
|
||
for i, inventory := range req.Inventories {
|
||
if inventory.ErpCommodityId == 0 {
|
||
return fmt.Errorf("商品Id传参错误,不能为0")
|
||
}
|
||
countMap[inventory.ErpCommodityId] += inventory.Count
|
||
|
||
// 如果该商品是串码商品,判断其串码是否会重复
|
||
if inventory.IMEI != "" {
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET(%s, imei) > 0", inventory.IMEI))
|
||
if err != nil {
|
||
logger.Error("exist sn err")
|
||
}
|
||
if exist {
|
||
return fmt.Errorf("串码有重复项请修改[%s]", inventory.IMEI)
|
||
}
|
||
}
|
||
|
||
// 备注:员工成本价在"库存管理-采购单入库"里面的入库操作前端是隐藏不可修改的,会默认传0
|
||
if inventory.EmployeePrice != 0 && inventory.EmployeePrice < inventory.ImplementationPrice {
|
||
return fmt.Errorf("数据错误,员工成本价不能低于采购执行单价")
|
||
}
|
||
|
||
erpCommodity, err := GetCommodity(inventory.ErpCommodityId)
|
||
if err != nil {
|
||
logger.Error("checkPurchaseInventory GetCommodity err:", logger.Field("err", err))
|
||
return fmt.Errorf("查询员工成本价报错")
|
||
}
|
||
req.Inventories[i].ErpCategoryID = erpCommodity.ErpCategoryId // 分类id,入库的时候前端没传,后端补充
|
||
req.Inventories[i].ErpCategoryName = erpCommodity.ErpCategoryName // 分类名称,入库的时候前端没传,后端补充
|
||
|
||
//if inventory.EmployeePrice == 0 { // 没有传入员工成本价,则默认按照商品资料设置的员工成本价加价金额
|
||
// req.Inventories[i].EmployeePrice = inventory.ImplementationPrice + float64(erpCommodity.StaffCostPrice)
|
||
//}
|
||
}
|
||
|
||
// 入库的商品信息有误,不在之前的商品列表中
|
||
for commodityID := range countMap {
|
||
found := false
|
||
for _, commodity := range commodities {
|
||
if commodity.ErpCommodityId == commodityID {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
if !found {
|
||
return fmt.Errorf("商品编号[%d]不属于该采购订单", commodityID)
|
||
}
|
||
}
|
||
|
||
// 本次入库的数量超出该商品未入库数量
|
||
for _, commodity := range commodities {
|
||
if inventoryCount, ok := countMap[commodity.ErpCommodityId]; ok {
|
||
if req.PurchaseType == ErpProcureOrder {
|
||
if commodity.Count-uint32(commodity.InventoryCount) < inventoryCount {
|
||
return fmt.Errorf("本次入库商品[%s]数量[%d]超出该商品未入库数量[%d]", commodity.ErpCommodityName,
|
||
inventoryCount, int32(commodity.Count)-commodity.InventoryCount)
|
||
}
|
||
} else if req.PurchaseType == ErpRejectOrder {
|
||
if commodity.RejectedCount-uint32(commodity.InventoryCount) < inventoryCount {
|
||
return fmt.Errorf("本次退货商品[%s]数量[%d]超出该商品未退货数量[%d]", commodity.ErpCommodityName,
|
||
inventoryCount, int32(commodity.Count)-commodity.InventoryCount)
|
||
}
|
||
|
||
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
|
||
var purchaseOrder ErpPurchaseOrder
|
||
err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, commodity.ErpCommodityId)
|
||
if err != nil {
|
||
logger.Error("checkPurchaseInventory GetCommodityStockByPurchaseId err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
// 如果库存数量不够则报错
|
||
if nCount < commodity.RejectedCount {
|
||
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", commodity.ErpCommodityName)
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ExecuteErpPurchase 执行(入库/退货)
|
||
func ExecuteErpPurchase(req *ErpPurchaseExecuteReq, c *gin.Context) (*ErpPurchaseExecuteResp, error) {
|
||
// 查询采购订单信息
|
||
var purchaseOrder ErpPurchaseOrder
|
||
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
logger.Error("purchase order err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
// 校验入参门店是否包含在用户所有门店中,是否过期
|
||
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
|
||
sysUser, err := GetSysUserByCtx(c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
if !CheckUserStore(purchaseOrder.StoreId, sysUser) {
|
||
return nil, errors.New("操作失败:您没有该门店权限")
|
||
}
|
||
}
|
||
|
||
reqParam := &ErpPurchaseInventoryReq{
|
||
ErpPurchaseOrderId: req.ErpPurchaseOrderId,
|
||
PurchaseType: req.PurchaseType,
|
||
Inventories: req.Inventories,
|
||
}
|
||
err = checkPurchaseInventory(reqParam)
|
||
if err != nil {
|
||
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
resp := &ErpPurchaseExecuteResp{
|
||
List: make([]ExecuteData, 0),
|
||
}
|
||
|
||
for _, inventory := range req.Inventories {
|
||
if inventory.Count == 0 {
|
||
continue
|
||
}
|
||
// 获取商品信息
|
||
commodityInfo, err := GetCommodity(inventory.ErpCommodityId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if commodityInfo.IMEIType == 2 || commodityInfo.IMEIType == 3 {
|
||
// 如果是串码商品,根据 Count 拆分成对应数量的数据
|
||
for i := 0; i < int(inventory.Count); i++ {
|
||
imei := "" // 默认退货单执行时不需要串码
|
||
if inventory.PurchaseType == ErpProcureOrder && commodityInfo.IMEIType == 2 { // 采购单
|
||
// 调用函数B生成商品串码
|
||
imei, err = GenerateIMEI(inventory.ErpCommodityId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
// 将拆分后的商品信息添加到执行响应中
|
||
resp.List = append(resp.List, ExecuteData{
|
||
ErpPurchaseOrderId: inventory.ErpPurchaseOrderId,
|
||
ErpCommodityId: inventory.ErpCommodityId,
|
||
ErpCommodityName: inventory.ErpCommodityName,
|
||
CommoditySerialNumber: inventory.CommoditySerialNumber,
|
||
IMEIType: inventory.IMEIType,
|
||
IMEI: imei,
|
||
Count: 1,
|
||
ImplementationPrice: inventory.ImplementationPrice,
|
||
EmployeePrice: inventory.EmployeePrice,
|
||
})
|
||
}
|
||
} else if commodityInfo.IMEIType == 1 {
|
||
// 如果是非串码商品,只需拆分为1条数据
|
||
resp.List = append(resp.List, ExecuteData{
|
||
ErpPurchaseOrderId: inventory.ErpPurchaseOrderId,
|
||
ErpCommodityId: inventory.ErpCommodityId,
|
||
ErpCommodityName: inventory.ErpCommodityName,
|
||
CommoditySerialNumber: inventory.CommoditySerialNumber,
|
||
IMEIType: inventory.IMEIType,
|
||
IMEI: "",
|
||
Count: inventory.Count,
|
||
ImplementationPrice: inventory.ImplementationPrice,
|
||
EmployeePrice: inventory.EmployeePrice,
|
||
})
|
||
}
|
||
}
|
||
|
||
resp.Total = len(resp.List)
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// GenerateIMEI 生成串码
|
||
func GenerateIMEI(commodityId uint32) (string, error) {
|
||
commodity, err := GetCommodity(commodityId)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
return GenerateSerialCode(commodity.ErpCategoryId)
|
||
}
|
||
|
||
// CreateErpPurchaseDemand 创建采购需求单
|
||
func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error {
|
||
var demandInfo ErpPurchaseDemand
|
||
var demandRemark ErpPurchaseDemandRemark
|
||
var demandList []ErpPurchaseDemand
|
||
|
||
// 采购需求信息
|
||
demandInfo.ErpCommodityId = req.ErpCommodityID
|
||
demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber
|
||
demandInfo.ErpCommodityName = req.ErpCommodityName
|
||
demandInfo.State = ErpDemandStateWait // 待采购
|
||
for _, v := range req.List {
|
||
demandInfo.StoreId = v.StoreID
|
||
demandInfo.StoreName = v.StoreName
|
||
demandInfo.Count = v.NeedCount
|
||
demandInfo.MakerId = uint32(sysUser.UserId)
|
||
demandList = append(demandList, demandInfo)
|
||
}
|
||
|
||
// 采购需求备注信息
|
||
demandRemark.ErpCommodityId = req.ErpCommodityID
|
||
demandRemark.State = ErpDemandStateWait // 待采购
|
||
demandRemark.MakerId = uint32(sysUser.UserId)
|
||
demandRemark.Remark = req.Remark
|
||
|
||
begin := orm.Eloquent.Begin()
|
||
// 查询当前表格,有记录则更新,没有则插入新记录
|
||
for _, v := range demandList {
|
||
var demand ErpPurchaseDemand
|
||
err := orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? and store_id = ? and state = 1",
|
||
v.ErpCommodityId, v.StoreId).Find(&demand).Error
|
||
if err != nil {
|
||
logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
if demand.StoreId != 0 { // 有记录
|
||
if demand.Count == v.Count { // 值没变则不更新
|
||
continue
|
||
} else {
|
||
err = begin.Model(&ErpPurchaseDemand{}).Where("erp_commodity_id = ? and store_id = ? and state = 1",
|
||
v.ErpCommodityId, v.StoreId).Updates(map[string]interface{}{
|
||
"count": v.Count,
|
||
"state": v.State,
|
||
"maker_id": v.MakerId,
|
||
}).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("update erp_order err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
} else { // 无记录,新建
|
||
err = begin.Create(&v).Error
|
||
if err != nil {
|
||
logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新备注,先查询有无记录,有则更新,没有则插入新记录
|
||
var demandRemarkInfo ErpPurchaseDemandRemark
|
||
err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1",
|
||
req.ErpCommodityID).Find(&demandRemarkInfo).Error
|
||
if err != nil {
|
||
logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
if demandRemarkInfo.ErpCommodityId != 0 { // 有记录
|
||
if demandRemarkInfo.Remark != req.Remark { // 备注有变化才更新
|
||
err := begin.Model(&ErpPurchaseDemandRemark{}).Where("erp_commodity_id = ? and state = 1",
|
||
req.ErpCommodityID).Updates(map[string]interface{}{
|
||
"state": demandRemark.State,
|
||
"remark": demandRemark.Remark,
|
||
"maker_id": demandRemark.MakerId,
|
||
}).Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("update erp_purchase_demand_remark err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
} else { // 无记录,新建
|
||
err = begin.Create(&demandRemark).Error
|
||
if err != nil {
|
||
logger.Error("create erp_purchase_demand_remark err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
|
||
err = begin.Commit().Error
|
||
if err != nil {
|
||
begin.Rollback()
|
||
logger.Error("commit err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// FinishErpPurchaseDemand 完成采购需求
|
||
func FinishErpPurchaseDemand(req *FinishErpPurchaseDemandReq, sysUser *SysUser) error {
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_demand WHERE erp_commodity_id='%d'",
|
||
req.ErpCommodityID))
|
||
if err != nil {
|
||
logger.Error("exist sn err")
|
||
}
|
||
if !exist {
|
||
return fmt.Errorf("商品编号[%d]的商品不在采购需求单中", req.ErpCommodityID)
|
||
}
|
||
|
||
// 批量更新状态
|
||
err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID).
|
||
Updates(map[string]interface{}{
|
||
"state": ErpDemandStateFinish,
|
||
"finish_time": time.Now(),
|
||
"purchaser_id": sysUser.UserId,
|
||
}).Error
|
||
if err != nil {
|
||
logger.Error("update err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
err = orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID).
|
||
Updates(map[string]interface{}{
|
||
"state": ErpDemandStateFinish,
|
||
"finish_time": time.Now(),
|
||
"purchaser_id": sysUser.UserId,
|
||
}).Error
|
||
if err != nil {
|
||
logger.Error("update err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
//// GetErpPurchaseDemand 获取采购需求
|
||
//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
|
||
// resp := &GetErpPurchaseDemandResp{
|
||
// PageIndex: req.PageIndex,
|
||
// PageSize: req.PageSize,
|
||
// }
|
||
// page := req.PageIndex - 1
|
||
// if page < 0 {
|
||
// page = 0
|
||
// }
|
||
// if req.PageSize == 0 {
|
||
// req.PageSize = 10
|
||
// }
|
||
//
|
||
// qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||
// if req.ErpCategoryId != 0 {
|
||
// qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
|
||
// }
|
||
//
|
||
// var commodities []ErpCommodity
|
||
// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
|
||
// if err != nil && err != RecordNotFound {
|
||
// //logger.Error("erp commodity list err:", err)
|
||
// return resp, err
|
||
// }
|
||
//
|
||
// // 组合数据
|
||
// resp, err = convertToDemandResp(commodities)
|
||
//
|
||
// return resp, nil
|
||
//}
|
||
//
|
||
//func convertToDemandResp(commodities []ErpCommodity) (*GetErpPurchaseDemandResp, error) {
|
||
// resp := new(GetErpPurchaseDemandResp)
|
||
// var demandData DemandData
|
||
// var demandList []DemandData
|
||
//
|
||
// // 查询所有在线门店信息
|
||
// var stores []Store
|
||
// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
|
||
// if err != nil {
|
||
// logger.Error("stores err:", logger.Field("err", err))
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// demandData.List = make([]struct {
|
||
// StoreID uint32 `json:"store_id"`
|
||
// StoreName string `json:"store_name"`
|
||
// LastMonthSales uint32 `json:"last_month_sales"`
|
||
// StockCount uint32 `json:"stock_count"`
|
||
// NeedCount uint32 `json:"need_count"`
|
||
// }, len(stores))
|
||
//
|
||
// var totalCount uint32 // 总需采购数量
|
||
//
|
||
// // 遍历所有商品
|
||
// for _, v := range commodities {
|
||
// // 初始化 NeedCount 为 0
|
||
// var totalNeedCount uint32
|
||
//
|
||
// for i, store := range stores {
|
||
// demandData.List[i].StoreID = store.ID
|
||
// demandData.List[i].StoreName = store.Name
|
||
//
|
||
// // 初始化 NeedCount 为 0
|
||
// demandData.List[i].NeedCount = 0
|
||
//
|
||
// // 设置商品相关信息
|
||
// demandData.ErpCommodityID = v.ID
|
||
// demandData.ErpCommoditySerialNumber = v.SerialNumber
|
||
// demandData.ErpCommodityName = v.Name
|
||
// demandData.ErpCategoryID = v.ErpCategoryId
|
||
// demandData.ErpCategoryName = v.ErpCategoryName
|
||
// demandData.RetailPrice = v.RetailPrice
|
||
// // 最近采购价
|
||
// demandData.LastWholesalePrice, _ = GetCommodityLastWholesalePrice(v.ID)
|
||
//
|
||
// // 查询采购需求单
|
||
// var demand []ErpPurchaseDemand
|
||
// err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? AND state = 1 AND store_id = ?",
|
||
// v.ID, store.ID).Find(&demand).Error
|
||
// if err != nil {
|
||
// logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// if len(demand) > 0 {
|
||
// totalNeedCount += demand[0].Count
|
||
// demandData.List[i].NeedCount = demand[0].Count
|
||
// }
|
||
//
|
||
// // 查询某个门店某个商品的库存情况
|
||
// demandData.List[i].StockCount, _ = GetCommodityStockByStoreId(v.ID, store.ID)
|
||
// // 查询某个门店某件商品的上月销售数量
|
||
// demandData.List[i].LastMonthSales, _ = GetCommodityLastMonthSalesByStoreId(v.ID, store.ID)
|
||
// }
|
||
// totalCount += totalNeedCount
|
||
// demandData.TotalCount = totalCount
|
||
// demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice
|
||
// demandList = append(demandList, demandData)
|
||
// }
|
||
// resp.List = demandList
|
||
//
|
||
// return resp, nil
|
||
//}
|
||
//
|
||
//// GetCommodityStockByStoreId 查询某个门店某个商品的库存情况
|
||
//func GetCommodityStockByStoreId(commodityId, storeId uint32) (uint32, error) {
|
||
// var count int64
|
||
// err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? and state = 1",
|
||
// commodityId, storeId).Count(&count).Error
|
||
// if err != nil {
|
||
// logger.Error("GetCommodityStockByStoreId count err:", logger.Field("err", err))
|
||
// return 0, err
|
||
// }
|
||
//
|
||
// return uint32(count), nil
|
||
//}
|
||
//
|
||
//// GetCommodityLastMonthSalesByStoreId 查询某个门店某件商品的上月销售数量
|
||
//func GetCommodityLastMonthSalesByStoreId(commodityId, storeId uint32) (uint32, error) {
|
||
// var lastMonthSales uint32
|
||
//
|
||
// // 获取当前时间
|
||
// now := time.Now()
|
||
// year, month, _ := now.Date()
|
||
// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
|
||
// lastDay := firstDay.AddDate(0, 1, -1)
|
||
//
|
||
// // 执行查询
|
||
// err := orm.Eloquent.Model(&ErpOrderCommodity{}).
|
||
// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
|
||
// Select("SUM(erp_order_commodity.count) AS last_month_sales").
|
||
// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
|
||
// "AND erp_order_commodity.created_at BETWEEN ? AND ?",
|
||
// HavePaid, commodityId, storeId, firstDay, lastDay).
|
||
// Scan(&lastMonthSales).Error
|
||
// if err != nil {
|
||
// logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err))
|
||
// return 0, err
|
||
// }
|
||
//
|
||
// return lastMonthSales, nil
|
||
//}
|
||
//
|
||
//// GetCommodityLastWholesalePrice 查询某个商品的最近采购价
|
||
//func GetCommodityLastWholesalePrice(commodityId uint32) (float64, error) {
|
||
// var implementationPrice float64
|
||
//
|
||
// // 执行查询
|
||
// err := orm.Eloquent.Table("erp_purchase_inventory").
|
||
// Select("implementation_price").
|
||
// Where("erp_commodity_id = ? AND purchase_type = ?", 167, "procure").
|
||
// Order("created_at DESC").
|
||
// Limit(1).
|
||
// Scan(&implementationPrice).Error
|
||
// if err != nil {
|
||
// logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err))
|
||
// return 0, err
|
||
// }
|
||
//
|
||
// return implementationPrice, nil
|
||
//}
|
||
|
||
// 222222222
|
||
//// GetErpPurchaseDemand 获取采购需求
|
||
//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
|
||
// resp := &GetErpPurchaseDemandResp{
|
||
// PageIndex: req.PageIndex,
|
||
// PageSize: req.PageSize,
|
||
// }
|
||
// page := req.PageIndex - 1
|
||
// if page < 0 {
|
||
// page = 0
|
||
// }
|
||
// if req.PageSize == 0 {
|
||
// req.PageSize = 10
|
||
// }
|
||
//
|
||
// qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||
// if req.ErpCategoryId != 0 {
|
||
// qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
|
||
// }
|
||
//
|
||
// var commodities []ErpCommodity
|
||
// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
|
||
// if err != nil && err != RecordNotFound {
|
||
// return resp, err
|
||
// }
|
||
//
|
||
// // 批量查询门店信息
|
||
// stores, err := GetOnlineStores()
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// // 批量查询商品信息
|
||
// demandDataList := make([]DemandData, 0, len(commodities))
|
||
// for _, v := range commodities {
|
||
// demandData, err := convertToDemandData(v, stores)
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
// demandDataList = append(demandDataList, demandData)
|
||
// }
|
||
//
|
||
// resp.List = demandDataList
|
||
//
|
||
// return resp, nil
|
||
//}
|
||
//
|
||
//// convertToDemandData 将商品转换为采购需求数据
|
||
//func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
|
||
// demandData := DemandData{
|
||
// ErpCommodityID: commodity.ID,
|
||
// ErpCommoditySerialNumber: commodity.SerialNumber,
|
||
// ErpCommodityName: commodity.Name,
|
||
// ErpCategoryID: commodity.ErpCategoryId,
|
||
// ErpCategoryName: commodity.ErpCategoryName,
|
||
// RetailPrice: commodity.RetailPrice,
|
||
// }
|
||
//
|
||
// // 批量查询最近采购价
|
||
// lastWholesalePrices, err := GetCommodityLastWholesalePrices(commodity.ID)
|
||
// if err != nil {
|
||
// return DemandData{}, err
|
||
// }
|
||
//
|
||
// for i, store := range stores {
|
||
// demandData.List = append(demandData.List, struct {
|
||
// StoreID uint32 `json:"store_id"`
|
||
// StoreName string `json:"store_name"`
|
||
// LastMonthSales uint32 `json:"last_month_sales"`
|
||
// StockCount uint32 `json:"stock_count"`
|
||
// NeedCount uint32 `json:"need_count"`
|
||
// }{
|
||
// StoreID: store.ID,
|
||
// StoreName: store.Name,
|
||
// })
|
||
//
|
||
// // 批量查询库存情况
|
||
// stockCounts, err := GetCommodityStocksByStoreID(commodity.ID, store.ID)
|
||
// if err != nil {
|
||
// return DemandData{}, err
|
||
// }
|
||
// demandData.List[i].StockCount = stockCounts[store.ID]
|
||
//
|
||
// // 批量查询上月销售数量
|
||
// lastMonthSales, err := GetCommodityLastMonthSales(commodity.ID, store.ID)
|
||
// if err != nil {
|
||
// return DemandData{}, err
|
||
// }
|
||
// demandData.List[i].LastMonthSales = lastMonthSales
|
||
//
|
||
// // 设置最近采购价
|
||
// demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]
|
||
// }
|
||
//
|
||
// return demandData, nil
|
||
//}
|
||
//
|
||
//// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
|
||
//func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
|
||
// // 查询最近采购价
|
||
// var prices []struct {
|
||
// CommodityID uint32
|
||
// Price float64
|
||
// }
|
||
// err := orm.Eloquent.Table("erp_purchase_inventory").
|
||
// Select("erp_commodity_id, implementation_price AS price").
|
||
// Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
|
||
// Group("erp_commodity_id").
|
||
// Order("created_at DESC").
|
||
// Find(&prices).Error
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// // 构建结果
|
||
// result := make(map[uint32]float64)
|
||
// for _, p := range prices {
|
||
// result[p.CommodityID] = p.Price
|
||
// }
|
||
// return result, nil
|
||
//}
|
||
//
|
||
//// GetCommodityStocksByStoreID 批量查询商品的库存情况
|
||
//func GetCommodityStocksByStoreID(commodityID, storeID uint32) (map[uint32]uint32, error) {
|
||
// // 查询库存情况
|
||
// var stocks []struct {
|
||
// StoreID uint32
|
||
// CommodityID uint32
|
||
// StockCount uint32
|
||
// }
|
||
// err := orm.Eloquent.Table("erp_stock_commodity").
|
||
// Select("store_id, erp_commodity_id, COUNT(*) AS stock_count").
|
||
// Where("erp_commodity_id IN (?) AND store_id = ? AND state = 1", commodityID, storeID).
|
||
// Group("store_id, erp_commodity_id").
|
||
// Find(&stocks).Error
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// // 构建结果
|
||
// result := make(map[uint32]uint32)
|
||
// for _, s := range stocks {
|
||
// result[s.StoreID] = s.StockCount
|
||
// }
|
||
// return result, nil
|
||
//}
|
||
//
|
||
//// GetCommodityLastMonthSales 批量查询商品的上月销售数量
|
||
//func GetCommodityLastMonthSales(commodityID, storeID uint32) (uint32, error) {
|
||
// // 获取上个月的时间范围
|
||
// firstDay, lastDay := GetLastMonthRange()
|
||
//
|
||
// // 查询上月销售数量
|
||
// var lastMonthSales struct {
|
||
// Sales uint32
|
||
// }
|
||
// err := orm.Eloquent.Table("erp_order_commodity").
|
||
// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
|
||
// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
|
||
// "AND erp_order_commodity.created_at BETWEEN ? AND ?",
|
||
// HavePaid, commodityID, storeID, firstDay, lastDay).
|
||
// Select("SUM(erp_order_commodity.count) AS sales").
|
||
// Scan(&lastMonthSales).Error
|
||
// if err != nil {
|
||
// return 0, err
|
||
// }
|
||
//
|
||
// return lastMonthSales.Sales, nil
|
||
//}
|
||
//
|
||
//// GetLastMonthRange 获取上个月的时间范围
|
||
//func GetLastMonthRange() (time.Time, time.Time) {
|
||
// now := time.Now()
|
||
// year, month, _ := now.Date()
|
||
// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
|
||
// lastDay := firstDay.AddDate(0, 1, -1)
|
||
// return firstDay, lastDay
|
||
//}
|
||
//
|
||
//// GetOnlineStores 查询所有在线门店信息
|
||
//func GetOnlineStores() ([]Store, error) {
|
||
// var stores []Store
|
||
// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
// return stores, nil
|
||
//}
|
||
|
||
// 3333
|
||
//// GetErpPurchaseDemand 获取采购需求
|
||
//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
|
||
// resp := &GetErpPurchaseDemandResp{
|
||
// PageIndex: req.PageIndex,
|
||
// PageSize: req.PageSize,
|
||
// }
|
||
// page := req.PageIndex - 1
|
||
// if page < 0 {
|
||
// page = 0
|
||
// }
|
||
// if req.PageSize == 0 {
|
||
// req.PageSize = 10
|
||
// }
|
||
//
|
||
// qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||
// if req.ErpCategoryId != 0 {
|
||
// qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
|
||
// }
|
||
//
|
||
// var commodities []ErpCommodity
|
||
// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
|
||
// if err != nil && err != RecordNotFound {
|
||
// return resp, err
|
||
// }
|
||
//
|
||
// // 批量查询门店信息
|
||
// stores, err := GetOnlineStores()
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// // 并行查询需求数据
|
||
// var wg sync.WaitGroup
|
||
// demandDataList := make([]DemandData, len(commodities))
|
||
//
|
||
// for i, v := range commodities {
|
||
// wg.Add(1)
|
||
// go func(index int, commodity ErpCommodity) {
|
||
// defer wg.Done()
|
||
// demandData, err := convertToDemandData(commodity, stores)
|
||
// if err != nil {
|
||
// // Handle error
|
||
// return
|
||
// }
|
||
// demandDataList[index] = demandData
|
||
// }(i, v)
|
||
// }
|
||
//
|
||
// wg.Wait()
|
||
//
|
||
// resp.List = demandDataList
|
||
//
|
||
// return resp, nil
|
||
//}
|
||
//
|
||
//// convertToDemandData 将商品转换为采购需求数据
|
||
//func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
|
||
// demandData := DemandData{
|
||
// ErpCommodityID: commodity.ID,
|
||
// ErpCommoditySerialNumber: commodity.SerialNumber,
|
||
// ErpCommodityName: commodity.Name,
|
||
// ErpCategoryID: commodity.ErpCategoryId,
|
||
// ErpCategoryName: commodity.ErpCategoryName,
|
||
// RetailPrice: commodity.RetailPrice,
|
||
// }
|
||
//
|
||
// // 并行查询最近采购价、库存情况、上月销售数量
|
||
// var wg sync.WaitGroup
|
||
// wg.Add(3)
|
||
//
|
||
// var lastWholesalePrices map[uint32]float64
|
||
// var stockCounts map[uint32]uint32
|
||
// var lastMonthSales uint32
|
||
// var err1, err2, err3 error
|
||
//
|
||
// go func() {
|
||
// defer wg.Done()
|
||
// lastWholesalePrices, err1 = GetCommodityLastWholesalePrices(commodity.ID)
|
||
// }()
|
||
//
|
||
// go func() {
|
||
// defer wg.Done()
|
||
// stockCounts, err2 = GetCommodityStocksByStoreID(commodity.ID, stores)
|
||
// }()
|
||
//
|
||
// go func() {
|
||
// defer wg.Done()
|
||
// lastMonthSales, err3 = GetCommodityLastMonthSales(commodity.ID, stores)
|
||
// }()
|
||
//
|
||
// wg.Wait()
|
||
//
|
||
// if err1 != nil || err2 != nil || err3 != nil {
|
||
// // Handle error
|
||
// return DemandData{}, err1
|
||
// }
|
||
//
|
||
// // 构建需求数据
|
||
// demandData.List = make([]struct {
|
||
// StoreID uint32 `json:"store_id"`
|
||
// StoreName string `json:"store_name"`
|
||
// LastMonthSales uint32 `json:"last_month_sales"`
|
||
// StockCount uint32 `json:"stock_count"`
|
||
// NeedCount uint32 `json:"need_count"`
|
||
// }, len(stores))
|
||
//
|
||
// for i, store := range stores {
|
||
// demandData.List[i].StoreID = store.ID
|
||
// demandData.List[i].StoreName = store.Name
|
||
//
|
||
// demandData.List[i].StockCount = stockCounts[store.ID]
|
||
// demandData.List[i].LastMonthSales = lastMonthSales
|
||
//
|
||
// // 设置最近采购价
|
||
// demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]
|
||
// }
|
||
//
|
||
// return demandData, nil
|
||
//}
|
||
//
|
||
//// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
|
||
//func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
|
||
// // 查询最近采购价
|
||
// var prices []struct {
|
||
// CommodityID uint32
|
||
// Price float64
|
||
// }
|
||
// err := orm.Eloquent.Table("erp_purchase_inventory").
|
||
// Select("erp_commodity_id, implementation_price AS price").
|
||
// Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
|
||
// Group("erp_commodity_id").
|
||
// Order("created_at DESC").
|
||
// Find(&prices).Error
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// // 构建结果
|
||
// result := make(map[uint32]float64)
|
||
// for _, p := range prices {
|
||
// result[p.CommodityID] = p.Price
|
||
// }
|
||
// return result, nil
|
||
//}
|
||
//
|
||
//// GetCommodityStocksByStoreID 批量查询商品的库存情况
|
||
//func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) {
|
||
// // 并行查询库存情况
|
||
// var wg sync.WaitGroup
|
||
// wg.Add(len(stores))
|
||
//
|
||
// result := make(map[uint32]uint32)
|
||
//
|
||
// for _, store := range stores {
|
||
// go func(storeID uint32) {
|
||
// defer wg.Done()
|
||
// // 查询库存情况
|
||
// var stockCount int64
|
||
// err := orm.Eloquent.Table("erp_stock_commodity").
|
||
// Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID).
|
||
// Count(&stockCount).Error
|
||
// if err != nil {
|
||
// // Handle error
|
||
// return
|
||
// }
|
||
// result[storeID] = uint32(stockCount)
|
||
// }(store.ID)
|
||
// }
|
||
//
|
||
// wg.Wait()
|
||
//
|
||
// return result, nil
|
||
//}
|
||
//
|
||
//// GetCommodityLastMonthSales 批量查询商品的上月销售数量
|
||
//func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) {
|
||
// // 获取上个月的时间范围
|
||
// firstDay, lastDay := GetLastMonthRange()
|
||
//
|
||
// // 并行查询上月销售数量
|
||
// var wg sync.WaitGroup
|
||
// wg.Add(len(stores))
|
||
//
|
||
// var totalSales uint32
|
||
// var mu sync.Mutex // 用于保护 totalSales 的并发访问
|
||
//
|
||
// for _, store := range stores {
|
||
// go func(storeID uint32) {
|
||
// defer wg.Done()
|
||
// // 查询上月销售数量
|
||
// var sales uint32
|
||
// err := orm.Eloquent.Table("erp_order_commodity").
|
||
// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
|
||
// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
|
||
// "AND erp_order_commodity.created_at BETWEEN ? AND ?",
|
||
// HavePaid, commodityID, storeID, firstDay, lastDay).
|
||
// Select("SUM(erp_order_commodity.count) AS sales").
|
||
// Scan(&sales).Error
|
||
// if err != nil {
|
||
// // Handle error
|
||
// return
|
||
// }
|
||
//
|
||
// // 累加销售数量
|
||
// mu.Lock()
|
||
// totalSales += sales
|
||
// mu.Unlock()
|
||
// }(store.ID)
|
||
// }
|
||
//
|
||
// wg.Wait()
|
||
//
|
||
// return totalSales, nil
|
||
//}
|
||
//
|
||
//// GetLastMonthRange 获取上个月的时间范围
|
||
//func GetLastMonthRange() (time.Time, time.Time) {
|
||
// now := time.Now()
|
||
// year, month, _ := now.Date()
|
||
// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
|
||
// lastDay := firstDay.AddDate(0, 1, -1)
|
||
// return firstDay, lastDay
|
||
//}
|
||
//
|
||
//// GetOnlineStores 查询所有在线门店信息
|
||
//func GetOnlineStores() ([]Store, error) {
|
||
// var stores []Store
|
||
// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
// return stores, nil
|
||
//}
|
||
|
||
// GetErpPurchaseDemand 获取采购需求
|
||
func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq, c *gin.Context) (*GetErpPurchaseDemandResp, error) {
|
||
var err error
|
||
resp := new(GetErpPurchaseDemandResp)
|
||
if req.HideFlag == "ON" { // 隐藏无采购需求的商品
|
||
resp, err = getErpPurchaseDemandHide(req, c)
|
||
} else { // 展示所有
|
||
resp, err = getErpPurchaseDemandAll(req, c)
|
||
}
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 展示所有采购需求
|
||
func getErpPurchaseDemandAll(req *GetErpPurchaseDemandReq, c *gin.Context) (*GetErpPurchaseDemandResp, error) {
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
|
||
resp := &GetErpPurchaseDemandResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||
if req.ErpCategoryId != 0 {
|
||
categoryInfo, err := GetErpCategory(req.ErpCategoryId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("serial_number like ?", categoryInfo.Number+"%")
|
||
}
|
||
if req.ErpCommoditySerialNumber != "" {
|
||
qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber)
|
||
}
|
||
if req.ErpCommodityName != "" {
|
||
qs = qs.Where("name=?", req.ErpCommodityName)
|
||
}
|
||
|
||
var count int64
|
||
if err := qs.Count(&count).Error; err != nil {
|
||
logger.Error("count err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
var commodities []ErpCommodity
|
||
err := qs.Order("id DESC").Find(&commodities).Error
|
||
if err != nil && err != RecordNotFound {
|
||
return resp, err
|
||
}
|
||
|
||
// 按商品编号进行排序
|
||
SortCommodities(commodities)
|
||
|
||
// 批量查询门店信息
|
||
stores, err := GetOnlineStores(c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 并行查询需求数据
|
||
var wg sync.WaitGroup
|
||
demandDataList := make([]DemandData, len(commodities))
|
||
|
||
for i, v := range commodities {
|
||
wg.Add(1)
|
||
go func(index int, commodity ErpCommodity) {
|
||
defer wg.Done()
|
||
demandData, err := convertToDemandData(commodity, stores)
|
||
if err != nil {
|
||
// Handle error
|
||
return
|
||
}
|
||
demandDataList[index] = demandData
|
||
}(i, v)
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
if req.IsExport == 1 { // 导出excel
|
||
if len(demandDataList) == 0 {
|
||
return nil, errors.New("未查询到数据")
|
||
}
|
||
resp.ExportUrl, err = demandDataExport(demandDataList)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
} else {
|
||
// 计算分页所需的切片索引
|
||
startIndex := page * req.PageSize
|
||
endIndex := (page + 1) * req.PageSize
|
||
if endIndex > len(demandDataList) {
|
||
endIndex = len(demandDataList)
|
||
}
|
||
resp.List = demandDataList[startIndex:endIndex]
|
||
resp.Total = count
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 隐藏无采购需求的商品
|
||
func getErpPurchaseDemandHide(req *GetErpPurchaseDemandReq, c *gin.Context) (*GetErpPurchaseDemandResp, error) {
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
|
||
resp := &GetErpPurchaseDemandResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
// 查询采购需求单信息,筛选出有采购需求的商品id
|
||
var demand []ErpPurchaseDemand
|
||
err := orm.Eloquent.Table("erp_purchase_demand").
|
||
Where("state = 1").Find(&demand).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// 用 map 存储已经出现过的 ErpCommodityId
|
||
commodityIds := make(map[uint32]bool)
|
||
var uniqueCommodityIds []uint32
|
||
|
||
for _, d := range demand {
|
||
if _, ok := commodityIds[d.ErpCommodityId]; !ok {
|
||
commodityIds[d.ErpCommodityId] = true
|
||
uniqueCommodityIds = append(uniqueCommodityIds, d.ErpCommodityId)
|
||
}
|
||
}
|
||
|
||
// 查询商品信息
|
||
qs := orm.Eloquent.Debug().Table("erp_commodity")
|
||
if req.ErpCategoryId != 0 {
|
||
//qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
|
||
categoryInfo, err := GetErpCategory(req.ErpCategoryId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("serial_number like ?", categoryInfo.Number+"%")
|
||
}
|
||
if req.ErpCommoditySerialNumber != "" {
|
||
qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber)
|
||
}
|
||
if req.ErpCommodityName != "" {
|
||
qs = qs.Where("name=?", req.ErpCommodityName)
|
||
}
|
||
|
||
var count int64
|
||
if err := qs.Count(&count).Error; err != nil {
|
||
logger.Error("count err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
var commodities []ErpCommodity
|
||
if req.IsExport == 1 { // 导出excel
|
||
err := qs.Order("id DESC").Find(&commodities).Error
|
||
if err != nil && err != RecordNotFound {
|
||
return resp, err
|
||
}
|
||
} else {
|
||
err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
|
||
if err != nil && err != RecordNotFound {
|
||
return resp, err
|
||
}
|
||
}
|
||
|
||
// 匹配商品id,有则继续查询返回数据,没有则不返回
|
||
var matchedCommodities []ErpCommodity
|
||
for _, c := range commodities {
|
||
for _, uniqueID := range uniqueCommodityIds {
|
||
if c.ID == uniqueID {
|
||
matchedCommodities = append(matchedCommodities, c)
|
||
break // 找到匹配的商品后跳出内层循环,继续下一个商品
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(matchedCommodities) == 0 {
|
||
resp.List = nil
|
||
} else {
|
||
// 批量查询门店信息
|
||
stores, err := GetOnlineStores(c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 并行查询需求数据
|
||
var wg sync.WaitGroup
|
||
demandDataList := make([]DemandData, len(matchedCommodities))
|
||
|
||
for i, v := range matchedCommodities {
|
||
wg.Add(1)
|
||
go func(index int, commodity ErpCommodity) {
|
||
defer wg.Done()
|
||
demandData, err := convertToDemandData(commodity, stores)
|
||
if err != nil {
|
||
// Handle error
|
||
return
|
||
}
|
||
demandDataList[index] = demandData
|
||
}(i, v)
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
if req.IsExport == 1 { // 导出excel
|
||
if len(demandDataList) == 0 {
|
||
return nil, errors.New("未查询到数据")
|
||
}
|
||
resp.ExportUrl, err = demandDataExport(demandDataList)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
} else {
|
||
resp.List = demandDataList
|
||
resp.Total = int64(len(matchedCommodities))
|
||
}
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// convertToDemandData 将商品转换为采购需求数据
|
||
func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
|
||
// 查询采购商品的备注信息
|
||
var demandRemarkInfo ErpPurchaseDemandRemark
|
||
err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1",
|
||
commodity.ID).Find(&demandRemarkInfo).Error
|
||
if err != nil {
|
||
logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err))
|
||
return DemandData{}, err
|
||
}
|
||
|
||
demandData := DemandData{
|
||
ErpCommodityID: commodity.ID,
|
||
ErpCommoditySerialNumber: commodity.SerialNumber,
|
||
ErpCommodityName: commodity.Name,
|
||
ErpCategoryID: commodity.ErpCategoryId,
|
||
ErpCategoryName: commodity.ErpCategoryName,
|
||
RetailPrice: commodity.RetailPrice,
|
||
Remark: demandRemarkInfo.Remark,
|
||
}
|
||
|
||
// 查询采购需求单
|
||
demands, err := GetCommodityPurchaseDemands(commodity.ID, stores)
|
||
if err != nil {
|
||
// Handle error
|
||
return DemandData{}, err
|
||
}
|
||
//if len(demands) != 0 {
|
||
// demandData.Remark = demands[0].Remark
|
||
//}
|
||
|
||
//使用 WaitGroup 进行并行查询
|
||
var wg sync.WaitGroup
|
||
wg.Add(3)
|
||
|
||
var lastWholesalePrices map[uint32]float64
|
||
var stockCounts map[uint32]uint32
|
||
var lastMonthSales map[uint32]uint32
|
||
|
||
go func() {
|
||
defer wg.Done()
|
||
lastWholesalePrices, err = GetCommodityLastWholesalePrices(commodity.ID)
|
||
}()
|
||
|
||
go func() {
|
||
defer wg.Done()
|
||
stockCounts, err = GetCommodityStocksByStoreID(commodity.ID, stores)
|
||
}()
|
||
|
||
go func() {
|
||
defer wg.Done()
|
||
lastMonthSales, err = GetCommodityLastMonthSales(commodity.ID, stores)
|
||
}()
|
||
|
||
wg.Wait()
|
||
if err != nil {
|
||
// Handle error
|
||
//return DemandData{}, err 备注:有时会提示没记录,不做处理
|
||
}
|
||
|
||
var totalCount uint32 // 总需采购数量
|
||
// 构建需求数据
|
||
demandData.StoreList = make([]struct {
|
||
StoreID uint32 `json:"store_id"`
|
||
StoreName string `json:"store_name"`
|
||
LastMonthSales uint32 `json:"last_month_sales"`
|
||
StockCount uint32 `json:"stock_count"`
|
||
NeedCount uint32 `json:"need_count"`
|
||
}, len(stores))
|
||
|
||
for i, store := range stores {
|
||
demandData.StoreList[i].StoreID = store.ID
|
||
demandData.StoreList[i].StoreName = store.Name
|
||
|
||
demandData.StoreList[i].StockCount = stockCounts[store.ID]
|
||
demandData.StoreList[i].LastMonthSales = lastMonthSales[store.ID]
|
||
|
||
// 设置最近采购价
|
||
demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]
|
||
|
||
// 设置采购需求量
|
||
for _, demand := range demands {
|
||
if demand.StoreId == store.ID {
|
||
demandData.StoreList[i].NeedCount = demand.Count
|
||
totalCount += demand.Count
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
demandData.TotalCount = totalCount
|
||
demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice
|
||
|
||
return demandData, nil
|
||
}
|
||
|
||
// GetCommodityPurchaseDemands 查询商品的采购需求单
|
||
func GetCommodityPurchaseDemands(commodityID uint32, stores []Store) ([]ErpPurchaseDemand, error) {
|
||
var wg sync.WaitGroup
|
||
var mu sync.Mutex
|
||
var demands []ErpPurchaseDemand
|
||
wg.Add(len(stores))
|
||
|
||
for _, store := range stores {
|
||
go func(storeID uint32) {
|
||
defer wg.Done()
|
||
var demand ErpPurchaseDemand
|
||
err := orm.Eloquent.Table("erp_purchase_demand").
|
||
Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", commodityID, storeID).
|
||
First(&demand).Error
|
||
if err != nil {
|
||
// Handle error
|
||
return
|
||
}
|
||
|
||
mu.Lock()
|
||
defer mu.Unlock()
|
||
demands = append(demands, demand)
|
||
}(store.ID)
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
return demands, nil
|
||
}
|
||
|
||
// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
|
||
func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
|
||
// 查询最近采购价
|
||
var prices []struct {
|
||
ErpCommodityID uint32
|
||
Price float64
|
||
}
|
||
err := orm.Eloquent.Table("erp_purchase_inventory").
|
||
Select("erp_commodity_id, implementation_price AS price").
|
||
Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
|
||
//Group("erp_commodity_id").
|
||
Order("created_at DESC").
|
||
First(&prices).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 构建结果
|
||
result := make(map[uint32]float64)
|
||
for _, p := range prices {
|
||
result[p.ErpCommodityID] = p.Price
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
// GetCommodityStocksByStoreID 批量查询商品的库存情况
|
||
func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) {
|
||
// 并行查询库存情况
|
||
var wg sync.WaitGroup
|
||
wg.Add(len(stores))
|
||
|
||
result := make(map[uint32]uint32)
|
||
|
||
for _, store := range stores {
|
||
go func(storeID uint32) {
|
||
defer wg.Done()
|
||
// 查询库存情况
|
||
var stockCount int64
|
||
err := orm.Eloquent.Table("erp_stock_commodity").
|
||
Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID).
|
||
Count(&stockCount).Error
|
||
if err != nil {
|
||
// Handle error
|
||
return
|
||
}
|
||
result[storeID] = uint32(stockCount)
|
||
}(store.ID)
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
return result, nil
|
||
}
|
||
|
||
// GetCommodityStockByPurchaseId 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
|
||
func GetCommodityStockByPurchaseId(serialNumber string, orderId uint32) (uint32, error) {
|
||
var count int64
|
||
err := orm.Eloquent.Table("erp_stock_commodity").Where("original_sn = ? and erp_commodity_id = ? and state = ?",
|
||
serialNumber, orderId, InStock).Count(&count).Error
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
return uint32(count), nil
|
||
}
|
||
|
||
// GetCommodityLastMonthSales 批量查询商品的上月销售数量
|
||
func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (map[uint32]uint32, error) {
|
||
// 获取上个月的时间范围
|
||
firstDay, lastDay := GetLastMonthRange()
|
||
|
||
// 并行查询上月销售数量
|
||
var wg sync.WaitGroup
|
||
wg.Add(len(stores))
|
||
|
||
result := make(map[uint32]uint32)
|
||
var mu sync.Mutex // 用于保护 totalSales 的并发访问
|
||
|
||
for _, store := range stores {
|
||
go func(storeID uint32) {
|
||
defer wg.Done()
|
||
// 查询上月销售数量
|
||
var sales int64
|
||
err := orm.Eloquent.Table("erp_stock_commodity").
|
||
Where("state = ? AND erp_commodity_id = ? AND store_id = ? AND updated_at BETWEEN ? AND ?",
|
||
SoldOut, commodityID, storeID, firstDay, lastDay).Count(&sales).Error
|
||
if err != nil {
|
||
// Handle error
|
||
return
|
||
}
|
||
|
||
// 保护 totalSales 的并发访问
|
||
mu.Lock()
|
||
defer mu.Unlock()
|
||
result[storeID] = uint32(sales)
|
||
}(store.ID)
|
||
}
|
||
|
||
wg.Wait()
|
||
|
||
return result, nil
|
||
}
|
||
|
||
// GetLastMonthRange 获取上个月的时间范围
|
||
func GetLastMonthRange() (time.Time, time.Time) {
|
||
now := time.Now()
|
||
year, month, _ := now.Date()
|
||
firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
|
||
lastDay := firstDay.AddDate(0, 1, -1)
|
||
return firstDay, lastDay
|
||
}
|
||
|
||
// GetOnlineStores 查询所有在线门店信息
|
||
func GetOnlineStores(c *gin.Context) ([]Store, error) {
|
||
sysUser, err := GetSysUserByCtx(c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var stores []Store
|
||
err = orm.Eloquent.Table("store").Where("is_online = ? and cooperative_business_id = ? ", 1,
|
||
sysUser.CooperativeBusinessId).Find(&stores).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
return stores, nil
|
||
}
|
||
|
||
type Result struct {
|
||
TotalCount uint32 `gorm:"column:total_count"`
|
||
AvgImplementationPrice float64 `gorm:"column:avg_implementation_price"`
|
||
TotalAmount float64 `gorm:"column:total_amount"`
|
||
AvgEmployeePrice float64 `gorm:"column:avg_employee_price"`
|
||
}
|
||
|
||
// GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价
|
||
func GetTotalsAndAveragesByCommodityID(commodityID, orderID uint32) (Result, error) {
|
||
var result Result
|
||
err := orm.Eloquent.Table("erp_purchase_inventory").
|
||
Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+
|
||
"SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price").
|
||
Where("erp_commodity_id = ? and erp_purchase_order_id = ?", commodityID, orderID).
|
||
Scan(&result).Error
|
||
if err != nil {
|
||
return Result{}, err
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
|
||
type ResultPrice struct {
|
||
TotalWholesalePrice float64 `gorm:"column:total_wholesale_price"`
|
||
}
|
||
|
||
// GetTotalWholesalePrice 查询采购退货订单对应的采购金额
|
||
func GetTotalWholesalePrice(commodityID uint32, serialNumber string) (ResultPrice, error) {
|
||
var result ResultPrice
|
||
err := orm.Eloquent.Table("erp_stock_commodity").
|
||
Select("SUM(`wholesale_price`) AS total_wholesale_price").
|
||
Where("erp_commodity_id = ? and stock_sn = ?", commodityID, serialNumber).
|
||
Scan(&result).Error
|
||
if err != nil {
|
||
return ResultPrice{}, err
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
|
||
// UpdateRetailPrice 更新指导零售价
|
||
func UpdateRetailPrice(begin *gorm.DB, commodityId uint32, retailPrice float64) error {
|
||
// 更新商品信息表
|
||
err := begin.Table("erp_commodity").Where("id=?", commodityId).
|
||
Updates(map[string]interface{}{
|
||
"retail_price": retailPrice,
|
||
}).Error
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 更新库存表
|
||
err = begin.Table("erp_stock").Where("erp_commodity_id=?", commodityId).
|
||
Updates(map[string]interface{}{
|
||
"retail_price": retailPrice,
|
||
}).Error
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 更新库存商品表
|
||
err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", commodityId).
|
||
Updates(map[string]interface{}{
|
||
"retail_price": retailPrice,
|
||
}).Error
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 导出采购需求excel
|
||
func demandDataExport(list []DemandData) (string, error) {
|
||
file := excelize.NewFile()
|
||
fSheet := "Sheet1"
|
||
|
||
url := ExportUrl
|
||
fileName := time.Now().Format(TimeFormat) + "采购需求" + ".xlsx"
|
||
fmt.Println("url fileName:", url+fileName)
|
||
|
||
// 组合标题栏第一行数据
|
||
title1 := []interface{}{"商品编号", "商品名称", "商品分类", "指导零售价", "最近采购价"}
|
||
storeCount := len(list[0].StoreList)
|
||
var mergeCells []string // 存储需要合并的单元格范围
|
||
|
||
for _, v := range list[0].StoreList {
|
||
for i := 0; i < 3; i++ {
|
||
title1 = append(title1, v.StoreName)
|
||
}
|
||
}
|
||
|
||
for i := 0; i < storeCount; i++ {
|
||
// 计算每个商户名称的起始和结束单元格
|
||
startCol, _ := excelize.ColumnNumberToName(6 + i*3) // 从第6列开始,每个商户占3列
|
||
endCol, _ := excelize.ColumnNumberToName(8 + i*3)
|
||
mergeCell := startCol + "1:" + endCol + "1"
|
||
mergeCells = append(mergeCells, mergeCell)
|
||
}
|
||
|
||
title1 = append(title1, "需采购总数量")
|
||
title1 = append(title1, "需采购总金额")
|
||
title1 = append(title1, "备注")
|
||
|
||
// 合并单元格
|
||
for _, mergeCell := range mergeCells {
|
||
startCell, endCell := splitMergeCellCoordinates(mergeCell)
|
||
_ = file.MergeCell(fSheet, startCell, endCell)
|
||
}
|
||
|
||
// 组合标题栏第二行数据
|
||
title2 := []interface{}{"商品编号", "商品名称", "商品分类", "指导零售价", "最近采购价"}
|
||
for _, _ = range list[0].StoreList {
|
||
title2 = append(title2, "上月销售数")
|
||
title2 = append(title2, "库存数量")
|
||
title2 = append(title2, "需采购数")
|
||
}
|
||
title2 = append(title2, "需采购总数量")
|
||
title2 = append(title2, "需采购总金额")
|
||
title2 = append(title2, "备注")
|
||
|
||
for i, _ := range title1 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
|
||
err := file.SetCellValue(fSheet, cell, title1[i])
|
||
if err != nil {
|
||
logger.Error("file set value err:", logger.Field("err", err))
|
||
}
|
||
}
|
||
|
||
for i, _ := range title2 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+i, 2)
|
||
err := file.SetCellValue(fSheet, cell, title2[i])
|
||
if err != nil {
|
||
logger.Error("file set value err:", logger.Field("err", err))
|
||
}
|
||
}
|
||
|
||
var row []interface{}
|
||
nExcelStartRow := 0
|
||
for i := 0; i < len(list); i++ {
|
||
row = []interface{}{
|
||
list[i].ErpCommoditySerialNumber, // 商品编号
|
||
list[i].ErpCommodityName, // 商品名称
|
||
list[i].ErpCategoryName, // 商品分类名称
|
||
list[i].RetailPrice, // 指导零售价
|
||
list[i].LastWholesalePrice, // 最近采购价
|
||
}
|
||
|
||
for _, v := range list[i].StoreList {
|
||
row = append(row, v.LastMonthSales) // 上月销售数
|
||
row = append(row, v.StockCount) // 库存数量
|
||
row = append(row, v.NeedCount) // 需采购数
|
||
}
|
||
|
||
row = append(row, list[i].TotalCount) // 需采购总数量
|
||
row = append(row, list[i].TotalAmount) // 需采购总金额
|
||
row = append(row, list[i].Remark) // 备注
|
||
|
||
for j, _ := range row {
|
||
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
|
||
err := file.SetCellValue(fSheet, cell, row[j])
|
||
if err != nil {
|
||
logger.Error("file set value err:", logger.Field("err", err))
|
||
}
|
||
}
|
||
nExcelStartRow++
|
||
}
|
||
|
||
// 合并 "需采购总数量","需采购总金额" 和 "备注" 列的单元格
|
||
strTotalCountCol, strTotalAmountCol, strRemarkCol := computeExtraColumns("E", storeCount)
|
||
_ = file.MergeCell(fSheet, strTotalCountCol+"1", strTotalCountCol+"2")
|
||
_ = file.MergeCell(fSheet, strTotalAmountCol+"1", strTotalAmountCol+"2")
|
||
_ = file.MergeCell(fSheet, strRemarkCol+"1", strRemarkCol+"2")
|
||
|
||
// 设置所有单元格的样式: 居中、加边框
|
||
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}]}`)
|
||
|
||
endRow := fmt.Sprintf(strRemarkCol+"%d", nExcelStartRow+2)
|
||
// 应用样式到整个表格
|
||
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
|
||
|
||
_ = file.MergeCell(fSheet, "A1", "A2")
|
||
_ = file.MergeCell(fSheet, "B1", "B2")
|
||
_ = file.MergeCell(fSheet, "C1", "C2")
|
||
_ = file.MergeCell(fSheet, "D1", "D2")
|
||
_ = file.MergeCell(fSheet, "E1", "E2")
|
||
|
||
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
|
||
}
|
||
|
||
// 根据合并单元格的字符串获取左上角和右下角的坐标
|
||
func splitMergeCellCoordinates(cell string) (string, string) {
|
||
split := strings.Split(cell, ":")
|
||
if len(split) != 2 {
|
||
return "", ""
|
||
}
|
||
return split[0], split[1]
|
||
}
|
||
|
||
// 计算 "需采购总数量","需采购总金额" 和 "备注" 列的坐标字符串
|
||
func computeExtraColumns(startCol string, storeCount int) (string, string, string) {
|
||
// "需采购总数量" 列在商户列表结束后的下一列
|
||
totalCountCol := convertColumnToLetters(convertLettersToColumn(startCol) + storeCount*3 + 1)
|
||
|
||
// "需采购总金额" 列在 "需采购总数量" 列的下一列
|
||
totalAmountCol := convertColumnToLetters(convertLettersToColumn(totalCountCol) + 1)
|
||
|
||
// "备注" 列在 "需采购总金额" 列的下一列
|
||
remarkCol := convertColumnToLetters(convertLettersToColumn(totalAmountCol) + 1)
|
||
|
||
return totalCountCol, totalAmountCol, remarkCol
|
||
}
|
||
|
||
// 将列号转换为字母
|
||
func convertColumnToLetters(column int) string {
|
||
var result string
|
||
for column > 0 {
|
||
column--
|
||
result = string('A'+column%26) + result
|
||
column /= 26
|
||
}
|
||
return result
|
||
}
|
||
|
||
// 将字母转换为列号
|
||
func convertLettersToColumn(letters string) int {
|
||
result := 0
|
||
for _, letter := range letters {
|
||
result *= 26
|
||
result += int(letter) - 'A' + 1
|
||
}
|
||
return result
|
||
}
|
||
|
||
// GetReportByOrder 查询采购报表(按单)
|
||
func GetReportByOrder(req *ErpPurchaseReportByOrderReq, c *gin.Context) (*ErpPurchaseReportByOrderResp, error) {
|
||
var err error
|
||
resp := new(ErpPurchaseReportByOrderResp)
|
||
//if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
|
||
// // 先筛选商品入库信息表,然后再补充采购订单信息
|
||
// resp, err = getReportByOrderFromCommodityOrCategory(req, c)
|
||
//} else {
|
||
// // 先筛选采购订单表,再补充商品入库信息
|
||
// resp, err = getReportByOrderFromCommon(req, c)
|
||
//}
|
||
|
||
resp, err = getReportByOrderFromCommon(req, c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 查询采购报表(按单):先筛选商品入库信息表,然后再补充采购订单信息
|
||
func getReportByOrderFromCommodityOrCategory(req *ErpPurchaseReportByOrderReq, c *gin.Context) (
|
||
*ErpPurchaseReportByOrderResp, 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 {
|
||
req.StoreId = CompareLists(storeList, req.StoreId)
|
||
if len(req.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
|
||
return &ErpPurchaseReportByOrderResp{}, nil
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
resp := &ErpPurchaseReportByOrderResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
qs := orm.Eloquent.Table("erp_purchase_inventory")
|
||
if req.ErpCommodityName != "" {
|
||
qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
|
||
}
|
||
if req.ErpCategoryID != 0 {
|
||
qs = qs.Where("erp_category_id=?", req.ErpCategoryID)
|
||
}
|
||
|
||
var inventoryList []ErpPurchaseInventory
|
||
var err error
|
||
if req.IsExport == 1 { // 导出excel
|
||
err = qs.Order("id DESC").Find(&inventoryList).Error
|
||
} else {
|
||
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&inventoryList).Error
|
||
}
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
// 创建一个 map,用于存储不同的 ErpCommodityId
|
||
commodityMap := make(map[uint32]uint32)
|
||
|
||
// 遍历 inventoryList,将不同的 ErpCommodityId 存入 map 中
|
||
for _, inventory := range inventoryList {
|
||
//commodityMap[inventory.ErpCommodityId] = inventory.ErpPurchaseOrderId
|
||
commodityMap[inventory.ErpPurchaseOrderId] = inventory.ErpCommodityId
|
||
}
|
||
// 计算不同的 ErpCommodityId 的数量
|
||
differentCommodityCount := len(commodityMap)
|
||
|
||
var reportOrderDataList []ReportByOrderData
|
||
var nTotalAmount float64
|
||
var nTotalCount int32
|
||
// 查询采购订单信息
|
||
for k, _ := range commodityMap {
|
||
var purchaseOrder ErpPurchaseOrder
|
||
var commodityList []ErpPurchaseCommodityData
|
||
|
||
query := orm.Eloquent.Table("erp_purchase_order")
|
||
|
||
if len(req.ErpSupplierId) > 0 { // 供应商复选
|
||
query = query.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId)
|
||
}
|
||
if len(req.StoreId) > 0 { // 门店复选
|
||
query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
|
||
}
|
||
|
||
err = query.Where("id = ?", k).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
var reportByOrderData ReportByOrderData
|
||
reportByOrderData.ErpPurchaseOrderId = purchaseOrder.ID
|
||
reportByOrderData.SerialNumber = purchaseOrder.SerialNumber
|
||
reportByOrderData.PurchaseType = purchaseOrder.PurchaseType
|
||
reportByOrderData.StoreId = purchaseOrder.StoreId
|
||
reportByOrderData.StoreName = purchaseOrder.StoreName
|
||
reportByOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
|
||
reportByOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
|
||
reportByOrderData.HandlerId = purchaseOrder.HandlerId
|
||
reportByOrderData.HandlerName = purchaseOrder.HandlerName
|
||
reportByOrderData.MakerTime = purchaseOrder.MakerTime
|
||
reportByOrderData.MakerId = purchaseOrder.MakerId
|
||
reportByOrderData.MakerName = purchaseOrder.MakerName
|
||
reportByOrderData.AuditorId = purchaseOrder.AuditorId
|
||
reportByOrderData.AuditTime = purchaseOrder.AuditTime
|
||
reportByOrderData.AuditorName = purchaseOrder.AuditorName
|
||
reportByOrderData.State = purchaseOrder.State
|
||
reportByOrderData.Remark = purchaseOrder.Remark
|
||
|
||
if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
|
||
reportByOrderData.MakerTime = nil
|
||
} else {
|
||
reportByOrderData.MakerTime = purchaseOrder.MakerTime
|
||
}
|
||
|
||
if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
|
||
reportByOrderData.AuditTime = nil
|
||
} else {
|
||
reportByOrderData.AuditTime = purchaseOrder.AuditTime
|
||
}
|
||
|
||
var nAmount float64
|
||
var nCount int32
|
||
// 使用 map 来组合相同 ErpCommodityId 的数据
|
||
commodityMapInfo := make(map[uint32]ErpPurchaseCommodityData)
|
||
|
||
for _, inventory := range inventoryList {
|
||
if inventory.ErpPurchaseOrderId == purchaseOrder.ID {
|
||
var vCount int32
|
||
var vAmount float64
|
||
if inventory.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
|
||
vAmount = -inventory.Amount
|
||
vCount = -int32(inventory.Count)
|
||
} else {
|
||
vCount = int32(inventory.Count)
|
||
vAmount = inventory.Amount
|
||
}
|
||
|
||
if existingData, ok := commodityMapInfo[inventory.ErpCommodityId]; ok {
|
||
// 如果已经存在相同 ErpCommodityId 的数据,则累加 Amount 和 Count
|
||
existingData.Amount += vAmount
|
||
existingData.Count += vCount
|
||
existingData.Price = existingData.Amount / float64(existingData.Count)
|
||
commodityMapInfo[inventory.ErpCommodityId] = existingData
|
||
} else {
|
||
// 否则,创建新的数据
|
||
commodityMapInfo[inventory.ErpCommodityId] = ErpPurchaseCommodityData{
|
||
CommodityData: CommodityData{
|
||
ErpCommodityId: inventory.ErpCommodityId,
|
||
ErpCommodityName: inventory.ErpCommodityName,
|
||
ErpCategoryID: inventory.ErpCategoryID,
|
||
ErpCategoryName: inventory.ErpCategoryName,
|
||
},
|
||
Amount: vAmount,
|
||
Price: inventory.ImplementationPrice,
|
||
Count: vCount,
|
||
}
|
||
}
|
||
// 累加总金额和总数量
|
||
nAmount += vAmount
|
||
nCount += vCount
|
||
|
||
}
|
||
}
|
||
|
||
// 将 map 中的值转换为 slice
|
||
for _, data := range commodityMapInfo {
|
||
commodityList = append(commodityList, data)
|
||
}
|
||
|
||
reportByOrderData.CommodityData = commodityList
|
||
reportByOrderData.Amount = nAmount
|
||
reportByOrderData.Count = nCount
|
||
if nCount != 0 {
|
||
reportByOrderData.Price = nAmount / float64(nCount)
|
||
}
|
||
reportOrderDataList = append(reportOrderDataList, reportByOrderData)
|
||
|
||
nTotalAmount += nAmount
|
||
nTotalCount += nCount
|
||
}
|
||
|
||
resp.Total = differentCommodityCount
|
||
resp.List = reportOrderDataList
|
||
resp.Amount = nTotalAmount
|
||
resp.Count = nTotalCount
|
||
|
||
if req.IsExport == 1 {
|
||
filePath, err := reportByOrderExport(resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp = &ErpPurchaseReportByOrderResp{}
|
||
resp.ExportUrl = filePath
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 查询采购报表(按单): 先筛选采购订单表,再补充商品入库信息
|
||
func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context) (
|
||
*ErpPurchaseReportByOrderResp, 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 {
|
||
req.StoreId = CompareLists(storeList, req.StoreId)
|
||
if len(req.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
|
||
return &ErpPurchaseReportByOrderResp{}, nil
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
resp := &ErpPurchaseReportByOrderResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
qs := orm.Eloquent.Table("erp_purchase_order").Where("state != ?", ErpPurchaseOrderUnAudit) // 未审核订单不展示
|
||
if req.SerialNumber != "" { // 单据编号
|
||
qs = qs.Where("serial_number=?", req.SerialNumber)
|
||
}
|
||
if req.PurchaseType != "" { // 采购类型
|
||
qs = qs.Where("purchase_type=?", req.PurchaseType)
|
||
}
|
||
if len(req.ErpSupplierId) > 0 { // 供应商复选
|
||
var supplierIDs []uint32
|
||
for _, supplier := range req.ErpSupplierId {
|
||
supplierIDs = append(supplierIDs, supplier)
|
||
}
|
||
qs = qs.Where("erp_supplier_id IN (?)", supplierIDs)
|
||
}
|
||
if len(req.StoreId) > 0 { // 门店复选
|
||
var storeIDs []uint32
|
||
for _, store := range req.StoreId {
|
||
storeIDs = append(storeIDs, store)
|
||
}
|
||
qs = qs.Where("store_id IN (?)", storeIDs)
|
||
}
|
||
if req.HandlerId != 0 { // 经手人id
|
||
qs = qs.Where("handler_id=?", req.HandlerId)
|
||
}
|
||
if req.State != 0 { // 订单状态
|
||
qs = qs.Where("state=?", req.State)
|
||
}
|
||
if req.AuditTimeStart != "" { // 审核开始时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
|
||
if err != nil {
|
||
logger.Errorf("erpPurchaseOrderList err:", err)
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("audit_time > ?", parse)
|
||
}
|
||
if req.AuditTimeEnd != "" { // 审核结束时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
|
||
if err != nil {
|
||
logger.Errorf("erpPurchaseOrderList err:", err)
|
||
return nil, err
|
||
}
|
||
//parse = parse.AddDate(0, 0, 1)
|
||
qs = qs.Where("audit_time < ?", parse)
|
||
}
|
||
|
||
var count int64
|
||
err := qs.Count(&count).Error
|
||
if err != nil {
|
||
logger.Error("getReportByOrderFromCommon count err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
resp.Total = int(count)
|
||
var orders []ErpPurchaseOrder
|
||
if req.ErpCategoryID != 0 || req.ErpCommodityName != "" || req.IsExport == 1 {
|
||
err = qs.Order("id DESC").Find(&orders).Error
|
||
} else {
|
||
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
|
||
}
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("getReportByOrderFromCommon erp_purchase_order err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
var reportByOrderDataList []ReportByOrderData
|
||
var nTotalAmount float64
|
||
var nTotalCount int32
|
||
for _, v := range orders {
|
||
var reportByOrderData ReportByOrderData
|
||
var nAmount float64
|
||
var nCount int32
|
||
|
||
reportByOrderData.ErpPurchaseOrderId = v.ID
|
||
reportByOrderData.SerialNumber = v.SerialNumber
|
||
reportByOrderData.PurchaseType = v.PurchaseType
|
||
reportByOrderData.StoreId = v.StoreId
|
||
reportByOrderData.StoreName = v.StoreName
|
||
reportByOrderData.ErpSupplierId = v.ErpSupplierId
|
||
reportByOrderData.ErpSupplierName = v.ErpSupplierName
|
||
reportByOrderData.HandlerId = v.HandlerId
|
||
reportByOrderData.HandlerName = v.HandlerName
|
||
//reportByOrderData.MakerTime = v.MakerTime
|
||
reportByOrderData.MakerId = v.MakerId
|
||
reportByOrderData.MakerName = v.MakerName
|
||
reportByOrderData.AuditorId = v.AuditorId
|
||
//reportByOrderData.AuditTime = v.AuditTime
|
||
reportByOrderData.AuditorName = v.AuditorName
|
||
reportByOrderData.State = v.State
|
||
reportByOrderData.Remark = v.Remark
|
||
|
||
if v.MakerTime != nil && v.MakerTime.IsZero() {
|
||
reportByOrderData.MakerTime = nil
|
||
} else {
|
||
reportByOrderData.MakerTime = v.MakerTime
|
||
}
|
||
|
||
if v.AuditTime != nil && v.AuditTime.IsZero() {
|
||
reportByOrderData.AuditTime = nil
|
||
} else {
|
||
reportByOrderData.AuditTime = v.AuditTime
|
||
}
|
||
|
||
reportByOrderData.CommodityData, nAmount, nCount, err = getOrderInventoryInfo(req, v.ID)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if reportByOrderData.CommodityData == nil {
|
||
continue
|
||
}
|
||
|
||
//if reportByOrderData.CommodityData == nil {
|
||
// continue
|
||
//}
|
||
|
||
reportByOrderData.Amount = nAmount
|
||
reportByOrderData.Count = nCount
|
||
if nCount != 0 {
|
||
reportByOrderData.Price = nAmount / float64(nCount)
|
||
}
|
||
reportByOrderDataList = append(reportByOrderDataList, reportByOrderData)
|
||
nTotalAmount += nAmount
|
||
nTotalCount += nCount
|
||
}
|
||
|
||
if req.ErpCategoryID != 0 || req.ErpCommodityName != "" {
|
||
resp.Total = len(reportByOrderDataList)
|
||
// 计算分页所需的切片索引
|
||
startIndex := page * req.PageSize
|
||
endIndex := (page + 1) * req.PageSize
|
||
if endIndex > len(reportByOrderDataList) {
|
||
endIndex = len(reportByOrderDataList)
|
||
}
|
||
|
||
resp.List = reportByOrderDataList[startIndex:endIndex]
|
||
} else {
|
||
resp.List = reportByOrderDataList
|
||
}
|
||
|
||
resp.Amount = nTotalAmount
|
||
resp.Count = nTotalCount
|
||
//resp.Total = int(count)
|
||
|
||
if req.IsExport == 1 {
|
||
filePath, err := reportByOrderExport(resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp = &ErpPurchaseReportByOrderResp{}
|
||
resp.ExportUrl = filePath
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 查询采购订单的入库信息
|
||
func getOrderInventoryInfo(req *ErpPurchaseReportByOrderReq, erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, int32, error) {
|
||
var inventoryList []ErpPurchaseInventory
|
||
err := orm.Eloquent.Table("erp_purchase_inventory").
|
||
Where("erp_purchase_order_id = ?", erpPurchaseOrderId).
|
||
Find(&inventoryList).Error
|
||
if err != nil {
|
||
logger.Error("getOrderInventoryInfo err:", logger.Field("err", err))
|
||
return nil, 0, 0, err
|
||
}
|
||
|
||
if len(inventoryList) == 0 {
|
||
//return nil, 0, 0, errors.New("未查询到采购订单的入库信息")
|
||
return nil, 0, 0, nil
|
||
}
|
||
|
||
// 使用 map 来组合相同 ErpCommodityId 的数据
|
||
commodityMap := make(map[uint32]ErpPurchaseCommodityData)
|
||
var nAmount float64
|
||
var nCount int32
|
||
|
||
// 遍历库存列表,组合相同 ErpCommodityId 的数据
|
||
for _, v := range inventoryList {
|
||
var vCount int32
|
||
var vAmount float64
|
||
|
||
// 商品名称和分类筛选
|
||
if req.ErpCommodityName != "" && v.ErpCommodityName != req.ErpCommodityName {
|
||
continue
|
||
}
|
||
if req.ErpCategoryID != 0 && v.ErpCategoryID != req.ErpCategoryID {
|
||
continue
|
||
}
|
||
|
||
if v.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
|
||
vAmount = -v.Amount
|
||
vCount = -int32(v.Count)
|
||
} else {
|
||
vCount = int32(v.Count)
|
||
vAmount = v.Amount
|
||
}
|
||
|
||
if existingData, ok := commodityMap[v.ErpCommodityId]; ok {
|
||
// 如果已经存在相同 ErpCommodityId 的数据,则累加 Amount 和 Count
|
||
existingData.Amount += vAmount
|
||
existingData.Count += vCount
|
||
existingData.Price = existingData.Amount / float64(existingData.Count)
|
||
commodityMap[v.ErpCommodityId] = existingData
|
||
} else {
|
||
// 否则,创建新的数据
|
||
commodityMap[v.ErpCommodityId] = ErpPurchaseCommodityData{
|
||
CommodityData: CommodityData{
|
||
ErpCommodityId: v.ErpCommodityId,
|
||
ErpCommodityName: v.ErpCommodityName,
|
||
ErpCategoryID: v.ErpCategoryID,
|
||
ErpCategoryName: v.ErpCategoryName,
|
||
},
|
||
Amount: vAmount,
|
||
Price: v.ImplementationPrice,
|
||
Count: vCount,
|
||
}
|
||
}
|
||
// 累加总金额和总数量
|
||
nAmount += vAmount
|
||
nCount += vCount
|
||
}
|
||
|
||
// 将 map 中的值转换为 slice
|
||
var resp []ErpPurchaseCommodityData
|
||
for _, data := range commodityMap {
|
||
resp = append(resp, data)
|
||
}
|
||
|
||
return resp, nAmount, nCount, nil
|
||
}
|
||
|
||
// 导出采购报表(按单)excel
|
||
func reportByOrderExport(req *ErpPurchaseReportByOrderResp) (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{}
|
||
var row2 []interface{}
|
||
nExcelStartRow := 0
|
||
for _, orderData := range req.List {
|
||
var orderType string
|
||
switch orderData.PurchaseType {
|
||
case "procure":
|
||
orderType = "采购入库"
|
||
case "reject":
|
||
orderType = "采购退货"
|
||
}
|
||
|
||
var orderStatus string
|
||
switch orderData.State { // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
|
||
case ErpPurchaseOrderUnAudit:
|
||
orderStatus = "待审核"
|
||
case ErpPurchaseOrderWaitInventory:
|
||
orderStatus = "待入库"
|
||
case ErpPurchaseOrderWaitReject:
|
||
orderStatus = "待退货"
|
||
case ErpPurchaseOrderFinished:
|
||
orderStatus = "已完成"
|
||
case ErpPurchaseOrderEnd:
|
||
orderStatus = "已终止"
|
||
}
|
||
|
||
var strTime string
|
||
if orderData.AuditTime != nil {
|
||
strTime = orderData.AuditTime.Format(TimeFormat)
|
||
} else {
|
||
strTime = "--"
|
||
}
|
||
|
||
row1 = []interface{}{
|
||
orderData.SerialNumber, // 单据编号
|
||
orderType, // 类型
|
||
orderData.StoreName, // 店铺名称
|
||
orderData.Remark, // 备注
|
||
orderData.ErpSupplierName, // 供应商
|
||
orderData.HandlerName, // 经手人
|
||
orderData.MakerName, // 制单人
|
||
strTime, // 审核时间
|
||
orderStatus, // 订单状态
|
||
"--", // 商品名称
|
||
"--", // 商品分类
|
||
orderData.Amount, // 已执行金额
|
||
orderData.Price, // 执行单价
|
||
orderData.Count, // 已执行数量
|
||
}
|
||
|
||
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++
|
||
|
||
for _, commodity := range orderData.CommodityData {
|
||
row2 = []interface{}{
|
||
"", // 单据编号
|
||
"", // 类型
|
||
"", // 店铺名称
|
||
"", // 备注
|
||
"", // 供应商
|
||
"", // 经手人
|
||
"", // 制单人
|
||
"", // 审核时间
|
||
"", // 订单状态
|
||
commodity.ErpCommodityName, // 商品名称
|
||
commodity.ErpCategoryName, // 商品分类
|
||
commodity.Amount, // 已执行金额
|
||
commodity.Price, // 执行单价
|
||
commodity.Count, // 已执行数量
|
||
}
|
||
|
||
for j, _ := range row2 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
|
||
err := file.SetCellValue(fSheet, cell, row2[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.Amount, "--", req.Count}
|
||
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", "C", "C", 25)
|
||
file.SetColWidth("Sheet1", "H", "H", 20)
|
||
file.SetColWidth("Sheet1", "J", "J", 18)
|
||
|
||
endRow := fmt.Sprintf("N"+"%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
|
||
}
|
||
|
||
// GetReportByCommodity 查询采购报表(按商品)
|
||
func GetReportByCommodity(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (*ErpPurchaseReportByCommodityResp, error) {
|
||
var err error
|
||
resp := new(ErpPurchaseReportByCommodityResp)
|
||
//if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
|
||
// // 先筛选商品入库信息表,然后再补充采购订单信息
|
||
// resp, err = getReportByCommodityFromCommodityOrCategory(req, c)
|
||
//} else {
|
||
// // 先筛选采购订单表,再补充商品入库信息
|
||
// resp, err = getReportByCommodityFromCommon(req, c)
|
||
//}
|
||
|
||
resp, err = getReportByCommodityFromCommon(req, c)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 查询采购报表(按商品):先筛选商品入库信息表,然后再补充采购订单信息
|
||
func getReportByCommodityFromCommodityOrCategory(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (
|
||
*ErpPurchaseReportByCommodityResp, 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 {
|
||
req.StoreId = CompareLists(storeList, req.StoreId)
|
||
if len(req.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
|
||
return &ErpPurchaseReportByCommodityResp{}, nil
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
resp := &ErpPurchaseReportByCommodityResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
qs := orm.Eloquent.Table("erp_purchase_inventory")
|
||
if req.ErpCommodityName != "" {
|
||
qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
|
||
}
|
||
if req.ErpCategoryID != 0 {
|
||
qs = qs.Where("erp_category_id=?", req.ErpCategoryID)
|
||
}
|
||
|
||
var count int64
|
||
err := qs.Count(&count).Error
|
||
if err != nil {
|
||
logger.Error("getReportByOrderFromCommodityOrCategory count err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
var inventoryList []ErpPurchaseInventory
|
||
err = qs.Order("id DESC").Find(&inventoryList).Error
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
commodityIDMap := make(map[uint32]map[uint32]ErpPurchaseInventory)
|
||
// 遍历 inventoryList
|
||
for _, inventory := range inventoryList {
|
||
// 如果该商品id已经在map中,则将该订单id加入到对应的set中
|
||
if ids, ok := commodityIDMap[inventory.ErpCommodityId]; ok {
|
||
ids[inventory.ErpPurchaseOrderId] = inventory
|
||
} else {
|
||
// 如果该商品id不在map中,则创建一个新的map并加入订单id及其对应的 ErpPurchaseInventory
|
||
commodityIDMap[inventory.ErpCommodityId] = map[uint32]ErpPurchaseInventory{
|
||
inventory.ErpPurchaseOrderId: inventory,
|
||
}
|
||
}
|
||
}
|
||
resp.Total = len(commodityIDMap)
|
||
|
||
var reportByCommodityDataList []ReportByCommodityData
|
||
var totalData PurchaseData
|
||
|
||
// 遍历 map 获取去重的 ErpPurchaseOrderId
|
||
for _, orderIdSet := range commodityIDMap {
|
||
var reportByCommodityData ReportByCommodityData
|
||
if len(orderIdSet) != 0 {
|
||
for _, item := range orderIdSet {
|
||
reportByCommodityData.ErpCommodityId = item.ErpCommodityId
|
||
reportByCommodityData.ErpCommodityName = item.ErpCommodityName
|
||
reportByCommodityData.ErpCategoryID = item.ErpCategoryID
|
||
reportByCommodityData.ErpCategoryName = item.ErpCategoryName
|
||
break
|
||
}
|
||
}
|
||
|
||
var totalPurchaseData PurchaseData
|
||
var purchaseOrderDataList []ErpCommodityPurchaseOrderData
|
||
for orderId := range orderIdSet {
|
||
purchaseOrderData, err := getPurchaseOrderData(orderId, req)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
purchaseOrderDataList = append(purchaseOrderDataList, purchaseOrderData)
|
||
|
||
totalPurchaseData.PlanCount += purchaseOrderData.PlanCount
|
||
totalPurchaseData.PlanPrice += purchaseOrderData.PlanPrice
|
||
totalPurchaseData.PlanAmount += purchaseOrderData.PlanAmount
|
||
totalPurchaseData.Amount += purchaseOrderData.Amount
|
||
totalPurchaseData.Price += purchaseOrderData.Price
|
||
totalPurchaseData.Count += purchaseOrderData.Count
|
||
totalPurchaseData.NonExecutionAmount += purchaseOrderData.NonExecutionAmount
|
||
totalPurchaseData.NonExecutionCount += purchaseOrderData.NonExecutionCount
|
||
}
|
||
|
||
reportByCommodityData.PlanCount = totalPurchaseData.PlanCount
|
||
reportByCommodityData.PlanPrice = totalPurchaseData.PlanPrice
|
||
reportByCommodityData.PlanAmount = totalPurchaseData.PlanAmount
|
||
reportByCommodityData.Amount = totalPurchaseData.Amount
|
||
reportByCommodityData.Price = totalPurchaseData.Price
|
||
reportByCommodityData.Count = totalPurchaseData.Count
|
||
reportByCommodityData.NonExecutionAmount = totalPurchaseData.NonExecutionAmount
|
||
reportByCommodityData.NonExecutionCount = totalPurchaseData.NonExecutionCount
|
||
|
||
totalData.PlanCount += reportByCommodityData.PlanCount
|
||
totalData.PlanAmount += reportByCommodityData.PlanAmount
|
||
totalData.Amount += reportByCommodityData.Amount
|
||
totalData.Count += reportByCommodityData.Count
|
||
totalData.NonExecutionAmount += reportByCommodityData.NonExecutionAmount
|
||
totalData.NonExecutionCount += reportByCommodityData.NonExecutionCount
|
||
|
||
reportByCommodityData.OrderInfo = purchaseOrderDataList
|
||
reportByCommodityDataList = append(reportByCommodityDataList, reportByCommodityData)
|
||
}
|
||
|
||
sortByCommodityIDDesc(reportByCommodityDataList)
|
||
resp.Total = len(reportByCommodityDataList)
|
||
|
||
// 计算分页所需的切片索引
|
||
startIndex := page * req.PageSize
|
||
endIndex := (page + 1) * req.PageSize
|
||
if endIndex > len(reportByCommodityDataList) {
|
||
endIndex = len(reportByCommodityDataList)
|
||
}
|
||
|
||
resp.List = reportByCommodityDataList[startIndex:endIndex]
|
||
resp.PlanCount = totalData.PlanCount
|
||
resp.PlanAmount = totalData.PlanAmount
|
||
resp.Amount = totalData.Amount
|
||
resp.Count = totalData.Count
|
||
resp.NonExecutionAmount = totalData.NonExecutionAmount
|
||
resp.NonExecutionCount = totalData.NonExecutionCount
|
||
|
||
if req.IsExport == 1 {
|
||
filePath, err := reportByCommodityExport(resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp = &ErpPurchaseReportByCommodityResp{}
|
||
resp.ExportUrl = filePath
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 查询采购订单信息
|
||
func getPurchaseOrderData(orderID uint32, req *ErpPurchaseReportByCommodityReq) (ErpCommodityPurchaseOrderData, error) {
|
||
var purchaseOrderData ErpCommodityPurchaseOrderData
|
||
// 查询采购订单信息
|
||
var purchaseOrder ErpPurchaseOrder
|
||
qs := orm.Eloquent.Table("erp_purchase_order")
|
||
|
||
if len(req.ErpSupplierId) > 0 { // 供应商复选
|
||
qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId)
|
||
}
|
||
if len(req.StoreId) > 0 { // 门店复选
|
||
qs = qs.Where("store_id IN (?)", req.StoreId)
|
||
}
|
||
err := qs.Where("id = ?", orderID).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
return purchaseOrderData, err
|
||
}
|
||
|
||
// 查询采购订单的计划和执行信息
|
||
purchaseData, err := getPurchaseData(purchaseOrder.ID)
|
||
if err != nil {
|
||
return purchaseOrderData, err
|
||
}
|
||
|
||
// 组合数据
|
||
purchaseOrderData.ErpPurchaseOrderId = purchaseOrder.ID
|
||
purchaseOrderData.SerialNumber = purchaseOrder.SerialNumber
|
||
purchaseOrderData.PurchaseType = purchaseOrder.PurchaseType
|
||
purchaseOrderData.StoreId = purchaseOrder.StoreId
|
||
purchaseOrderData.StoreName = purchaseOrder.StoreName
|
||
purchaseOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
|
||
purchaseOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
|
||
purchaseOrderData.HandlerId = purchaseOrder.HandlerId
|
||
purchaseOrderData.HandlerName = purchaseOrder.HandlerName
|
||
//purchaseOrderData.MakerTime = purchaseOrder.MakerTime
|
||
purchaseOrderData.MakerId = purchaseOrder.MakerId
|
||
purchaseOrderData.MakerName = purchaseOrder.MakerName
|
||
purchaseOrderData.AuditorId = purchaseOrder.AuditorId
|
||
//purchaseOrderData.AuditTime = purchaseOrder.AuditTime
|
||
purchaseOrderData.AuditorName = purchaseOrder.AuditorName
|
||
|
||
if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
|
||
purchaseOrderData.MakerTime = nil
|
||
} else {
|
||
purchaseOrderData.MakerTime = purchaseOrder.MakerTime
|
||
}
|
||
if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
|
||
purchaseOrderData.AuditTime = nil
|
||
} else {
|
||
purchaseOrderData.AuditTime = purchaseOrder.AuditTime
|
||
}
|
||
|
||
purchaseOrderData.PlanCount = purchaseData.PlanCount
|
||
purchaseOrderData.PlanPrice = purchaseData.PlanPrice
|
||
purchaseOrderData.PlanAmount = purchaseData.PlanAmount
|
||
purchaseOrderData.Amount = purchaseData.Amount
|
||
purchaseOrderData.Price = purchaseData.Price
|
||
purchaseOrderData.Count = purchaseData.Count
|
||
purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount
|
||
purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount
|
||
|
||
if purchaseOrder.PurchaseType == ErpRejectOrder { // 退货单
|
||
purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount
|
||
purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount
|
||
purchaseOrderData.Amount = -purchaseOrderData.Amount
|
||
purchaseOrderData.Count = -purchaseOrderData.Count
|
||
purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount
|
||
purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount
|
||
}
|
||
|
||
return purchaseOrderData, nil
|
||
}
|
||
|
||
// getPurchaseData 根据 ErpPurchaseCommodity 表查询采购数据
|
||
func getPurchaseData(erpPurchaseOrderId uint32) (PurchaseData, error) {
|
||
var purchaseData PurchaseData
|
||
|
||
err := orm.Eloquent.Raw(`
|
||
SELECT
|
||
SUM(pc.count) AS plan_count,
|
||
AVG(pc.price) AS plan_price,
|
||
SUM(pc.amount) AS plan_amount,
|
||
SUM(pi.count) AS count,
|
||
AVG(pi.implementation_price) AS price,
|
||
SUM(pi.amount) AS amount
|
||
FROM
|
||
erp_purchase_commodity pc
|
||
JOIN
|
||
erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
|
||
WHERE
|
||
pc.erp_purchase_order_id = ?
|
||
GROUP BY
|
||
pc.erp_purchase_order_id
|
||
`, erpPurchaseOrderId).Scan(&purchaseData).Error
|
||
if err != nil {
|
||
logger.Error("getPurchaseData err:", logger.Field("err", err))
|
||
return purchaseData, err
|
||
}
|
||
|
||
// 计算未执行金额和未执行数量
|
||
purchaseData.NonExecutionAmount = purchaseData.PlanAmount - purchaseData.Amount
|
||
purchaseData.NonExecutionCount = purchaseData.PlanCount - purchaseData.Count
|
||
|
||
return purchaseData, nil
|
||
}
|
||
|
||
// 查询采购报表(按商品):先筛选采购订单表,再补充商品入库信息
|
||
func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (
|
||
*ErpPurchaseReportByCommodityResp, 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 {
|
||
req.StoreId = CompareLists(storeList, req.StoreId)
|
||
if len(req.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
|
||
return &ErpPurchaseReportByCommodityResp{}, nil
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
resp := &ErpPurchaseReportByCommodityResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
qs := orm.Eloquent.Table("erp_purchase_order").Where("state != ?", ErpPurchaseOrderUnAudit)
|
||
if req.SerialNumber != "" { // 单据编号
|
||
qs = qs.Where("serial_number=?", req.SerialNumber)
|
||
}
|
||
if req.PurchaseType != "" { // 采购类型
|
||
qs = qs.Where("purchase_type=?", req.PurchaseType)
|
||
}
|
||
if len(req.ErpSupplierId) > 0 { // 供应商复选
|
||
qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId)
|
||
}
|
||
if len(req.StoreId) > 0 { // 门店复选
|
||
qs = qs.Where("store_id IN (?)", req.StoreId)
|
||
}
|
||
if req.HandlerId != 0 { // 经手人id
|
||
qs = qs.Where("handler_id=?", req.HandlerId)
|
||
}
|
||
if req.State != 0 { // 订单状态
|
||
qs = qs.Where("state=?", req.State)
|
||
}
|
||
if req.AuditTimeStart != "" { // 审核开始时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
|
||
if err != nil {
|
||
logger.Errorf("erpPurchaseOrderList err:", err)
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("audit_time > ?", parse)
|
||
}
|
||
if req.AuditTimeEnd != "" { // 审核结束时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
|
||
if err != nil {
|
||
logger.Errorf("erpPurchaseOrderList err:", err)
|
||
return nil, err
|
||
}
|
||
//parse = parse.AddDate(0, 0, 1)
|
||
qs = qs.Where("audit_time < ?", parse)
|
||
}
|
||
|
||
var count int64
|
||
err := qs.Count(&count).Error
|
||
if err != nil {
|
||
logger.Error("getReportByOrderFromCommon count err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
var orders []ErpPurchaseOrder
|
||
err = qs.Order("id DESC").Find(&orders).Error
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("getReportByOrderFromCommon erp_purchase_order err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
// 查询所有商品id及其对应的orderId
|
||
commodityAndOrderIdMap, err := getAllOrderCommodity(page, req.PageSize, int(req.IsExport))
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
tempDataMap := make(map[uint32][]TempData)
|
||
|
||
//// 补充所有采购订单的商品信息和采购执行数量
|
||
//for _, v := range orders {
|
||
// commodityIds := findCommodityIDsByOrderID(v.ID, commodityAndOrderIdMap)
|
||
// // 获取每个采购订单的每个商品的采购和执行信息
|
||
// for _, commodityId := range commodityIds {
|
||
// purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(v.ID, commodityId)
|
||
// if err != nil {
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// tempData := TempData{
|
||
// CommodityData: commodityData,
|
||
// ErpCommodityPurchaseOrderData: purchaseOrderData,
|
||
// }
|
||
// tempDataMap[commodityId] = append(tempDataMap[commodityId], tempData)
|
||
// }
|
||
//}
|
||
|
||
var wg sync.WaitGroup
|
||
ch := make(chan TempData, len(orders)*len(commodityAndOrderIdMap))
|
||
|
||
// 并发查询每个采购订单的每个商品的采购和执行信息
|
||
for _, v := range orders {
|
||
commodityIds := findCommodityIDsByOrderID(v.ID, commodityAndOrderIdMap)
|
||
for _, commodityID := range commodityIds {
|
||
wg.Add(1)
|
||
go getPurchaseOrderAndCommodityDataAsync(v.ID, commodityID, ch, &wg)
|
||
}
|
||
}
|
||
|
||
wg.Wait()
|
||
close(ch)
|
||
|
||
for data := range ch {
|
||
tempDataMap[data.ErpCommodityId] = append(tempDataMap[data.ErpCommodityId], data)
|
||
}
|
||
|
||
var dataList []ReportByCommodityData
|
||
var totalData PurchaseData
|
||
// tempDataList,按照商品id进行归类
|
||
for _, tempDataList := range tempDataMap {
|
||
var reportData ReportByCommodityData
|
||
for _, v := range tempDataList {
|
||
// 商品名称和分类筛选
|
||
if req.ErpCommodityName != "" && v.ErpCommodityName != req.ErpCommodityName {
|
||
continue
|
||
}
|
||
if req.ErpCategoryID != 0 && v.ErpCategoryID != req.ErpCategoryID {
|
||
continue
|
||
}
|
||
reportData.ErpCategoryID = v.ErpCategoryID
|
||
reportData.ErpCategoryName = v.ErpCategoryName
|
||
reportData.ErpCommodityId = v.ErpCommodityId
|
||
reportData.ErpCommodityName = v.ErpCommodityName
|
||
|
||
reportData.PlanCount += v.PlanCount
|
||
reportData.PlanAmount += v.PlanAmount
|
||
reportData.Amount += v.Amount
|
||
reportData.Count += v.Count
|
||
reportData.NonExecutionAmount += v.NonExecutionAmount
|
||
reportData.NonExecutionCount += v.NonExecutionCount
|
||
if reportData.PlanCount != 0 {
|
||
reportData.PlanPrice = reportData.PlanAmount / float64(reportData.PlanCount)
|
||
reportData.PlanPrice = math.Round(reportData.PlanPrice*100) / 100
|
||
}
|
||
if reportData.Count != 0 {
|
||
reportData.Price = reportData.Amount / float64(reportData.Count)
|
||
reportData.Price = math.Round(reportData.Price*100) / 100
|
||
}
|
||
|
||
purchaseOrderData := ErpCommodityPurchaseOrderData{
|
||
CommonData{
|
||
ErpPurchaseOrderId: v.ErpPurchaseOrderId,
|
||
SerialNumber: v.SerialNumber,
|
||
PurchaseType: v.PurchaseType,
|
||
StoreId: v.StoreId,
|
||
StoreName: v.StoreName,
|
||
ErpSupplierId: v.ErpSupplierId,
|
||
ErpSupplierName: v.ErpSupplierName,
|
||
HandlerId: v.HandlerId,
|
||
HandlerName: v.HandlerName,
|
||
//MakerTime: v.MakerTime,
|
||
MakerId: v.MakerId,
|
||
MakerName: v.MakerName,
|
||
AuditorId: v.AuditorId,
|
||
//AuditTime: v.AuditTime,
|
||
AuditorName: v.AuditorName,
|
||
},
|
||
PurchaseData{
|
||
PlanCount: v.PlanCount,
|
||
PlanPrice: v.PlanPrice,
|
||
PlanAmount: v.PlanAmount,
|
||
Amount: v.Amount,
|
||
Price: v.Price,
|
||
Count: v.Count,
|
||
NonExecutionAmount: v.NonExecutionAmount,
|
||
NonExecutionCount: v.NonExecutionCount,
|
||
},
|
||
}
|
||
|
||
if v.PurchaseType == ErpRejectOrder { // 退货单
|
||
reportData.PlanCount = -reportData.PlanCount
|
||
reportData.PlanAmount = -reportData.PlanAmount
|
||
reportData.Amount = -reportData.Amount
|
||
reportData.Count = -reportData.Count
|
||
reportData.NonExecutionAmount = -reportData.NonExecutionAmount
|
||
reportData.NonExecutionCount = -reportData.NonExecutionCount
|
||
|
||
purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount
|
||
purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount
|
||
purchaseOrderData.Amount = -purchaseOrderData.Amount
|
||
purchaseOrderData.Count = -purchaseOrderData.Count
|
||
purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount
|
||
purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount
|
||
}
|
||
|
||
if v.MakerTime != nil && v.MakerTime.IsZero() {
|
||
purchaseOrderData.MakerTime = nil
|
||
} else {
|
||
purchaseOrderData.MakerTime = v.MakerTime
|
||
}
|
||
|
||
if v.AuditTime != nil && v.AuditTime.IsZero() {
|
||
purchaseOrderData.AuditTime = nil
|
||
} else {
|
||
purchaseOrderData.AuditTime = v.AuditTime
|
||
}
|
||
|
||
reportData.OrderInfo = append(reportData.OrderInfo, purchaseOrderData)
|
||
}
|
||
if reportData.ErpCategoryID == 0 || len(reportData.OrderInfo) == 0 {
|
||
continue
|
||
}
|
||
|
||
dataList = append(dataList, reportData)
|
||
|
||
totalData.PlanCount += reportData.PlanCount
|
||
totalData.PlanAmount += reportData.PlanAmount
|
||
totalData.Amount += reportData.Amount
|
||
totalData.Count += reportData.Count
|
||
totalData.NonExecutionAmount += reportData.NonExecutionAmount
|
||
totalData.NonExecutionCount += reportData.NonExecutionCount
|
||
}
|
||
|
||
sortByCommodityIDDesc(dataList)
|
||
resp.Total = len(dataList)
|
||
|
||
// 计算分页所需的切片索引
|
||
startIndex := page * req.PageSize
|
||
endIndex := (page + 1) * req.PageSize
|
||
if endIndex > len(dataList) {
|
||
endIndex = len(dataList)
|
||
}
|
||
|
||
resp.List = dataList[startIndex:endIndex]
|
||
resp.PlanCount = totalData.PlanCount
|
||
resp.PlanAmount = totalData.PlanAmount
|
||
resp.Amount = totalData.Amount
|
||
resp.Count = totalData.Count
|
||
resp.NonExecutionAmount = totalData.NonExecutionAmount
|
||
resp.NonExecutionCount = totalData.NonExecutionCount
|
||
|
||
if req.IsExport == 1 {
|
||
filePath, err := reportByCommodityExport(resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp = &ErpPurchaseReportByCommodityResp{}
|
||
resp.ExportUrl = filePath
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
func getPurchaseOrderAndCommodityDataAsync(orderID, commodityID uint32, ch chan<- TempData, wg *sync.WaitGroup) {
|
||
defer wg.Done()
|
||
|
||
purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(orderID, commodityID)
|
||
if err != nil {
|
||
logger.Errorf("getPurchaseOrderAndCommodityDataAsync err:", err)
|
||
return
|
||
}
|
||
|
||
tempData := TempData{
|
||
CommodityData: commodityData,
|
||
ErpCommodityPurchaseOrderData: purchaseOrderData,
|
||
}
|
||
ch <- tempData
|
||
}
|
||
|
||
// 按照商品ID进行倒序排序的 less 函数
|
||
func sortByCommodityIDDesc(dataList []ReportByCommodityData) {
|
||
sort.Slice(dataList, func(i, j int) bool {
|
||
return dataList[i].ErpCommodityId > dataList[j].ErpCommodityId
|
||
})
|
||
}
|
||
|
||
// 查询采购订单信息
|
||
func getPurchaseOrderAndCommodityData(orderID, commodityId uint32) (ErpCommodityPurchaseOrderData, CommodityData, error) {
|
||
var purchaseOrderData ErpCommodityPurchaseOrderData
|
||
// 查询采购订单信息
|
||
var purchaseOrder ErpPurchaseOrder
|
||
err := orm.Eloquent.Table("erp_purchase_order").Where("id = ?", orderID).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
return ErpCommodityPurchaseOrderData{}, CommodityData{}, err
|
||
}
|
||
|
||
// 查询采购订单的计划和执行信息
|
||
purchaseData, commodityData, err := getSignalPurchaseData(purchaseOrder.ID, commodityId)
|
||
if err != nil {
|
||
return ErpCommodityPurchaseOrderData{}, CommodityData{}, err
|
||
}
|
||
|
||
// 组合数据
|
||
purchaseOrderData.ErpPurchaseOrderId = purchaseOrder.ID
|
||
purchaseOrderData.SerialNumber = purchaseOrder.SerialNumber
|
||
purchaseOrderData.PurchaseType = purchaseOrder.PurchaseType
|
||
purchaseOrderData.StoreId = purchaseOrder.StoreId
|
||
purchaseOrderData.StoreName = purchaseOrder.StoreName
|
||
purchaseOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
|
||
purchaseOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
|
||
purchaseOrderData.HandlerId = purchaseOrder.HandlerId
|
||
purchaseOrderData.HandlerName = purchaseOrder.HandlerName
|
||
purchaseOrderData.MakerId = purchaseOrder.MakerId
|
||
purchaseOrderData.MakerName = purchaseOrder.MakerName
|
||
purchaseOrderData.AuditorId = purchaseOrder.AuditorId
|
||
purchaseOrderData.AuditTime = purchaseOrder.AuditTime
|
||
purchaseOrderData.AuditorName = purchaseOrder.AuditorName
|
||
|
||
if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
|
||
purchaseOrderData.MakerTime = nil
|
||
} else {
|
||
purchaseOrderData.MakerTime = purchaseOrder.MakerTime
|
||
}
|
||
|
||
if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
|
||
purchaseOrderData.AuditTime = nil
|
||
} else {
|
||
purchaseOrderData.AuditTime = purchaseOrder.AuditTime
|
||
}
|
||
|
||
purchaseOrderData.PlanCount = purchaseData.PlanCount
|
||
purchaseOrderData.PlanPrice = purchaseData.PlanPrice
|
||
purchaseOrderData.PlanAmount = purchaseData.PlanAmount
|
||
purchaseOrderData.Amount = purchaseData.Amount
|
||
purchaseOrderData.Price = purchaseData.Price
|
||
purchaseOrderData.Count = purchaseData.Count
|
||
purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount
|
||
purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount
|
||
|
||
return purchaseOrderData, commodityData, nil
|
||
}
|
||
|
||
// getSignalPurchaseData 根据 ErpPurchaseCommodity 表查询采购数据
|
||
func getSignalPurchaseData(erpPurchaseOrderId, commodityId uint32) (PurchaseData, CommodityData, error) {
|
||
var purchaseData PurchaseData
|
||
var commodityData CommodityData
|
||
|
||
//err := orm.Eloquent.Raw(`
|
||
// SELECT
|
||
// SUM(pc.count) AS plan_count,
|
||
// AVG(pc.price) AS plan_price,
|
||
// SUM(pc.amount) AS plan_amount,
|
||
// SUM(pi.count) AS count,
|
||
// AVG(pi.implementation_price) AS price,
|
||
// SUM(pi.amount) AS amount
|
||
// FROM
|
||
// erp_purchase_commodity pc
|
||
// JOIN
|
||
// erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
|
||
// WHERE
|
||
// pc.erp_purchase_order_id = ? and pc.erp_commodity_id = ?
|
||
// GROUP BY
|
||
// pc.erp_purchase_order_id
|
||
//`, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
|
||
|
||
err := orm.Eloquent.Raw(`
|
||
SELECT
|
||
plan.plan_count AS plan_count,
|
||
plan.plan_price AS plan_price,
|
||
plan.plan_amount AS plan_amount,
|
||
inventory.count AS count,
|
||
inventory.price AS price,
|
||
inventory.amount AS amount
|
||
FROM
|
||
(
|
||
SELECT
|
||
SUM(pc.count) AS plan_count,
|
||
AVG(pc.price) AS plan_price,
|
||
SUM(pc.amount) AS plan_amount
|
||
FROM
|
||
erp_purchase_commodity pc
|
||
WHERE
|
||
pc.erp_purchase_order_id = ? AND pc.erp_commodity_id = ?
|
||
GROUP BY
|
||
pc.erp_purchase_order_id
|
||
) AS plan
|
||
JOIN
|
||
(
|
||
SELECT
|
||
SUM(pi.count) AS count,
|
||
AVG(pi.implementation_price) AS price,
|
||
SUM(pi.amount) AS amount
|
||
FROM
|
||
erp_purchase_inventory pi
|
||
WHERE
|
||
pi.erp_purchase_order_id = ? AND pi.erp_commodity_id = ?
|
||
GROUP BY
|
||
pi.erp_purchase_order_id
|
||
) AS inventory ON 1 = 1
|
||
`, erpPurchaseOrderId, commodityId, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
|
||
if err != nil {
|
||
logger.Error("getPurchaseData err:", logger.Field("err", err))
|
||
return PurchaseData{}, CommodityData{}, err
|
||
}
|
||
|
||
// 计算未执行金额和未执行数量
|
||
purchaseData.NonExecutionAmount = purchaseData.PlanAmount - purchaseData.Amount
|
||
purchaseData.NonExecutionCount = purchaseData.PlanCount - purchaseData.Count
|
||
|
||
// 查询订单对应的商品信息
|
||
commodityInfo, err := GetCommodity(commodityId)
|
||
if err != nil {
|
||
return PurchaseData{}, CommodityData{}, err
|
||
}
|
||
|
||
commodityData.ErpCommodityId = commodityInfo.ID
|
||
commodityData.ErpCommodityName = commodityInfo.Name
|
||
commodityData.ErpCategoryID = commodityInfo.ErpCategoryId
|
||
commodityData.ErpCategoryName = commodityInfo.ErpCategoryName
|
||
|
||
return purchaseData, commodityData, nil
|
||
}
|
||
|
||
//// 查询所有商品信息
|
||
//func getAllOrderCommodity(pageIndex, pageSize int) (map[uint32][]uint32, error) {
|
||
// qs := orm.Eloquent.Table("erp_purchase_commodity")
|
||
//
|
||
// var count int64
|
||
// err := qs.Count(&count).Error
|
||
// if err != nil {
|
||
// logger.Error("getAllOrderCommodity count err:", logger.Field("err", err))
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// var commodityList []ErpPurchaseCommodity
|
||
// err = qs.Order("id DESC").Offset(pageIndex * pageSize).Limit(pageSize).Find(&commodityList).Error
|
||
// if err != nil && err != RecordNotFound {
|
||
// logger.Error("getAllOrderCommodity erp_purchase_commodity err:", logger.Field("err", err))
|
||
// return nil, err
|
||
// }
|
||
//
|
||
// commodityMap := make(map[uint32][]uint32)
|
||
// for _, v := range commodityList {
|
||
// if !contains(commodityMap[v.ErpCommodityId], v.ErpPurchaseOrderId) {
|
||
// commodityMap[v.ErpCommodityId] = append(commodityMap[v.ErpCommodityId], v.ErpPurchaseOrderId)
|
||
// }
|
||
// }
|
||
//
|
||
// return commodityMap, nil
|
||
//}
|
||
//
|
||
//func contains(slice []uint32, item uint32) bool {
|
||
// for _, value := range slice {
|
||
// if value == item {
|
||
// return true
|
||
// }
|
||
// }
|
||
// return false
|
||
//}
|
||
|
||
// 查询所有商品信息,每页展示不同商品ID及其对应的订单ID
|
||
func getAllOrderCommodity(pageIndex, pageSize, isExport int) (map[uint32][]uint32, error) {
|
||
var commodityMap = make(map[uint32][]uint32)
|
||
var query string
|
||
// if isExport == 1 { //导出excel
|
||
// // 执行原生 SQL 查询,联结表格,按照每个商品ID列出所有的订单ID
|
||
// query = fmt.Sprintf(`
|
||
// SELECT erp_commodity_id, GROUP_CONCAT(erp_purchase_order_id) AS order_ids FROM erp_purchase_commodity
|
||
//GROUP BY erp_commodity_id`)
|
||
// } else {
|
||
// // 执行原生 SQL 查询,联结表格,按照每个商品ID列出所有的订单ID
|
||
// query = fmt.Sprintf(`
|
||
// SELECT erp_commodity_id, GROUP_CONCAT(erp_purchase_order_id) AS order_ids FROM erp_purchase_commodity
|
||
//GROUP BY erp_commodity_id
|
||
// LIMIT %d OFFSET %d`, pageSize, pageIndex*pageSize)
|
||
// }
|
||
|
||
// 执行原生 SQL 查询,联结表格,按照每个商品ID列出所有的订单ID
|
||
query = fmt.Sprintf(`
|
||
SELECT erp_commodity_id, GROUP_CONCAT(erp_purchase_order_id) AS order_ids FROM erp_purchase_commodity
|
||
GROUP BY erp_commodity_id`)
|
||
|
||
rows, err := orm.Eloquent.Raw(query).Rows()
|
||
if err != nil {
|
||
logger.Error("getAllOrderCommodity erp_purchase_commodity err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
|
||
for rows.Next() {
|
||
var commodityID uint32
|
||
var orderIDs string
|
||
if err := rows.Scan(&commodityID, &orderIDs); err != nil {
|
||
logger.Error("getAllOrderCommodity rows scan err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
// 将 orderIDs 字符串拆分为字符串数组
|
||
orderIDStrList := strings.Split(orderIDs, ",")
|
||
|
||
// 去重并转换为 uint32 数组
|
||
var orderIDList []uint32
|
||
seen := make(map[uint32]bool)
|
||
for _, idStr := range orderIDStrList {
|
||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||
if err != nil {
|
||
logger.Error("getAllOrderCommodity parse orderID err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
// 如果该订单ID未被添加过,则添加到列表中
|
||
if _, ok := seen[uint32(id)]; !ok {
|
||
orderIDList = append(orderIDList, uint32(id))
|
||
seen[uint32(id)] = true
|
||
}
|
||
}
|
||
|
||
// 添加到 map 中
|
||
commodityMap[commodityID] = orderIDList
|
||
}
|
||
|
||
return commodityMap, nil
|
||
}
|
||
|
||
func findCommodityIDsByOrderID(orderID uint32, commodityMap map[uint32][]uint32) []uint32 {
|
||
var commodityIDs []uint32
|
||
|
||
for commodityID, orderIDs := range commodityMap {
|
||
for _, id := range orderIDs {
|
||
if id == orderID {
|
||
commodityIDs = append(commodityIDs, commodityID)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
return commodityIDs
|
||
}
|
||
|
||
// 导出采购报表(按商品)excel
|
||
func reportByCommodityExport(req *ErpPurchaseReportByCommodityResp) (string, error) {
|
||
file := excelize.NewFile()
|
||
fSheet := "Sheet1"
|
||
|
||
url := ExportUrl
|
||
fileName := time.Now().Format(TimeFormat) + "采购报表(按商品)" + ".xlsx"
|
||
fmt.Println("url fileName:", url+fileName)
|
||
|
||
// 组合标题栏数据
|
||
title1 := []interface{}{"商品名称", "商品分类", "单据编号", "类型", "店铺名称", "供应商", "经手人", "制单人", "审核时间",
|
||
"计划采购", "", "", "已执行", "", "", "未执行", ""}
|
||
title2 := []interface{}{"商品名称", "商品分类", "单据编号", "类型", "店铺名称", "供应商", "经手人", "制单人", "审核时间",
|
||
"采购金额", "采购单价", "采购数量", "已执行金额", "执行单价", "已执行数量", "未执行金额", "未执行数量"}
|
||
for i, _ := range title1 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
|
||
err := file.SetCellValue(fSheet, cell, title1[i])
|
||
if err != nil {
|
||
logger.Errorf("file set value err:", err)
|
||
}
|
||
}
|
||
|
||
for i, _ := range title2 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+i, 2)
|
||
err := file.SetCellValue(fSheet, cell, title2[i])
|
||
if err != nil {
|
||
logger.Errorf("file set value err:", err)
|
||
}
|
||
}
|
||
|
||
var row1 []interface{}
|
||
var row2 []interface{}
|
||
nExcelStartRow := 0
|
||
for _, commodityData := range req.List {
|
||
row1 = []interface{}{
|
||
commodityData.ErpCommodityName, // 商品名称
|
||
commodityData.ErpCategoryName, // 商品分类
|
||
"", // 单据编号
|
||
"", // 类型
|
||
"", // 店铺名称
|
||
"", // 供应商
|
||
"", // 经手人
|
||
"", // 制单人
|
||
"", // 审核时间
|
||
commodityData.PlanAmount, // 计划采购金额
|
||
commodityData.PlanPrice, // 计划采购单价
|
||
commodityData.PlanCount, // 计划采购数量
|
||
commodityData.Amount, // 已执行金额
|
||
commodityData.Price, // 已执行单价
|
||
commodityData.Count, // 已执行数量
|
||
commodityData.NonExecutionAmount, // 未执行金额
|
||
commodityData.NonExecutionCount, // 未执行数量
|
||
}
|
||
|
||
for j, _ := range row1 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
|
||
err := file.SetCellValue(fSheet, cell, row1[j])
|
||
if err != nil {
|
||
logger.Error("file set value err:", logger.Field("err", err))
|
||
}
|
||
}
|
||
nExcelStartRow++
|
||
|
||
for _, orderData := range commodityData.OrderInfo {
|
||
var orderType string
|
||
switch orderData.PurchaseType {
|
||
case "procure":
|
||
orderType = "采购入库"
|
||
case "reject":
|
||
orderType = "采购退货"
|
||
}
|
||
|
||
var strTime string
|
||
if orderData.AuditTime != nil {
|
||
strTime = orderData.AuditTime.Format(TimeFormat)
|
||
} else {
|
||
strTime = "--"
|
||
}
|
||
|
||
row2 = []interface{}{
|
||
"", // 商品名称
|
||
"", // 商品分类
|
||
orderData.SerialNumber, // 单据编号
|
||
orderType, // 类型
|
||
orderData.StoreName, // 店铺名称
|
||
orderData.ErpSupplierName, // 供应商
|
||
orderData.HandlerName, // 经手人
|
||
orderData.MakerName, // 制单人
|
||
strTime, // 审核时间
|
||
orderData.PlanAmount, // 计划采购金额
|
||
orderData.PlanPrice, // 计划采购单价
|
||
orderData.PlanCount, // 计划采购数量
|
||
orderData.Amount, // 已执行金额
|
||
orderData.Price, // 已执行单价
|
||
orderData.Count, // 已执行数量
|
||
orderData.NonExecutionAmount, // 未执行金额
|
||
orderData.NonExecutionCount, // 未执行数量
|
||
}
|
||
|
||
for j, _ := range row2 {
|
||
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
|
||
err := file.SetCellValue(fSheet, cell, row2[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.PlanAmount, // 计划采购金额
|
||
"--", // 计划采购单价
|
||
req.PlanCount, // 计划采购数量
|
||
req.Amount, // 已执行金额
|
||
"--", // 已执行单价
|
||
req.Count, // 已执行数量
|
||
req.NonExecutionAmount, // 未执行金额
|
||
req.NonExecutionCount, // 未执行数量
|
||
}
|
||
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.MergeCell(fSheet, "A1", "A2")
|
||
_ = file.MergeCell(fSheet, "B1", "B2")
|
||
_ = file.MergeCell(fSheet, "C1", "C2")
|
||
_ = file.MergeCell(fSheet, "D1", "D2")
|
||
_ = file.MergeCell(fSheet, "E1", "E2")
|
||
_ = file.MergeCell(fSheet, "F1", "F2")
|
||
_ = file.MergeCell(fSheet, "G1", "G2")
|
||
_ = file.MergeCell(fSheet, "H1", "H2")
|
||
_ = file.MergeCell(fSheet, "I1", "I2")
|
||
|
||
_ = file.MergeCell(fSheet, "J1", "L1")
|
||
_ = file.MergeCell(fSheet, "M1", "O1")
|
||
_ = file.MergeCell(fSheet, "P1", "Q1")
|
||
|
||
//设置单元格高度
|
||
file.SetRowHeight("Sheet1", 1, 20)
|
||
file.SetRowHeight("Sheet1", 2, 20)
|
||
|
||
// 设置单元格大小
|
||
file.SetColWidth("Sheet1", "A", "A", 15)
|
||
file.SetColWidth("Sheet1", "B", "B", 10)
|
||
file.SetColWidth("Sheet1", "C", "C", 13)
|
||
file.SetColWidth("Sheet1", "E", "E", 25)
|
||
|
||
endRow := fmt.Sprintf("Q"+"%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
|
||
}
|
||
|
||
// GetReportBySupplier 查询供应商采购汇总
|
||
func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq, c *gin.Context) (
|
||
*ErpPurchaseReportBySupplierResp, 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 {
|
||
req.StoreList = CompareLists(storeList, req.StoreList)
|
||
if len(req.StoreList) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
|
||
return &ErpPurchaseReportBySupplierResp{}, nil
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
resp := &ErpPurchaseReportBySupplierResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
}
|
||
|
||
// 构建查询条件
|
||
query := orm.Eloquent.Model(&ErpPurchaseInventory{}).
|
||
Select("erp_purchase_inventory.erp_purchase_order_id, " +
|
||
"erp_purchase_inventory.purchase_type, erp_purchase_inventory.serial_number, " +
|
||
"erp_purchase_order.store_id, erp_purchase_order.store_name, erp_purchase_order.erp_supplier_id, " +
|
||
"erp_purchase_order.erp_supplier_name, " +
|
||
"erp_purchase_inventory.erp_commodity_id, erp_purchase_inventory.erp_commodity_name, " +
|
||
"erp_purchase_inventory.erp_category_id, erp_purchase_inventory.erp_category_name, " +
|
||
"SUM(erp_purchase_inventory.count) AS count, " +
|
||
"SUM(erp_purchase_inventory.amount) AS amount").
|
||
Joins("JOIN erp_purchase_order ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
|
||
Group("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.erp_commodity_id, " +
|
||
"erp_purchase_inventory.erp_commodity_name, erp_purchase_inventory.erp_category_id")
|
||
|
||
countQuery := orm.Eloquent.Model(&ErpPurchaseInventory{}).
|
||
Select("erp_purchase_inventory.erp_purchase_order_id, " +
|
||
"erp_purchase_inventory.purchase_type, erp_purchase_inventory.serial_number, " +
|
||
"erp_purchase_order.store_id, erp_purchase_order.store_name, erp_purchase_order.erp_supplier_id, " +
|
||
"erp_purchase_order.erp_supplier_name, " +
|
||
"erp_purchase_inventory.erp_commodity_id, erp_purchase_inventory.erp_commodity_name, " +
|
||
"erp_purchase_inventory.erp_category_id, erp_purchase_inventory.erp_category_name, " +
|
||
"SUM(erp_purchase_inventory.count) AS count, " +
|
||
"SUM(erp_purchase_inventory.amount) AS amount").
|
||
Joins("JOIN erp_purchase_order ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
|
||
Group("erp_purchase_inventory.erp_purchase_order_id, erp_purchase_inventory.erp_commodity_id, " +
|
||
"erp_purchase_inventory.erp_commodity_name, erp_purchase_inventory.erp_category_id")
|
||
|
||
// 根据请求参数过滤数据
|
||
if req.PurchaseType != "" {
|
||
query = query.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType)
|
||
}
|
||
if len(req.ErpCommodityName) > 0 {
|
||
query = query.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
|
||
}
|
||
|
||
if len(req.ErpCategoryID) > 0 {
|
||
query = query.Where("erp_purchase_inventory.erp_category_id IN (?)", req.ErpCategoryID)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.erp_category_id IN (?)", req.ErpCategoryID)
|
||
}
|
||
|
||
if req.StartTime != "" { // 入/出库开始时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
|
||
if err != nil {
|
||
logger.Errorf("GetReportDetail err:", err)
|
||
return nil, err
|
||
}
|
||
query = query.Where("erp_purchase_inventory.created_at >= ?", parse)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.created_at >= ?", parse)
|
||
}
|
||
|
||
if req.EndTime != "" { // 入/出库结束时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.EndTime)
|
||
if err != nil {
|
||
logger.Errorf("GetReportDetail err:", err)
|
||
return nil, err
|
||
}
|
||
query = query.Where("erp_purchase_inventory.created_at <= ?", parse)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.created_at <= ?", parse)
|
||
}
|
||
|
||
if len(req.StoreList) > 0 {
|
||
query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
|
||
countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
|
||
}
|
||
|
||
//获取总数
|
||
var total int64
|
||
countQuery.Count(&total)
|
||
resp.Total = int(total)
|
||
|
||
var err error
|
||
err = query.Find(&resp.List).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var esData []PurchaseReportData
|
||
|
||
if len(req.ErpSupplierId) > 0 {
|
||
var purchaseOrder []ErpPurchaseOrder
|
||
err = orm.Eloquent.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 循环遍历采购订单
|
||
for _, po := range purchaseOrder {
|
||
// 在resp.List中查找匹配的订单
|
||
for _, respItem := range resp.List {
|
||
if po.ID == respItem.ErpPurchaseOrderId {
|
||
// 如果找到匹配的订单,将其添加到esData中
|
||
data := PurchaseReportData{
|
||
ErpPurchaseOrderId: po.ID,
|
||
StoreId: po.StoreId,
|
||
StoreName: po.StoreName,
|
||
PurchaseType: respItem.PurchaseType,
|
||
ErpSupplierId: po.ErpSupplierId,
|
||
ErpSupplierName: po.ErpSupplierName,
|
||
ErpCommodityId: respItem.ErpCommodityId,
|
||
ErpCommodityName: respItem.ErpCommodityName,
|
||
ErpCategoryID: respItem.ErpCategoryID,
|
||
ErpCategoryName: respItem.ErpCategoryName,
|
||
Count: respItem.Count,
|
||
Amount: respItem.Amount,
|
||
RejectAmount: respItem.RejectAmount,
|
||
Difference: respItem.Difference,
|
||
}
|
||
|
||
if data.PurchaseType == "reject" {
|
||
//// 查询退货商品的采购金额
|
||
//var oldOrderInfo ErpPurchaseOrder
|
||
//err = orm.Eloquent.Where("serial_number = ?", po.SerialNumber).First(&oldOrderInfo).Error
|
||
//if err != nil {
|
||
// return nil, err
|
||
//}
|
||
|
||
// 查找对应的采购入库记录
|
||
var resultInfo ResultPrice
|
||
resultInfo, err = GetTotalWholesalePrice(respItem.ErpCommodityId, respItem.SerialNumber)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
data.Difference = -(resultInfo.TotalWholesalePrice - data.Amount)
|
||
data.RejectAmount = -data.Amount
|
||
data.Amount = -resultInfo.TotalWholesalePrice
|
||
data.Count = -data.Count
|
||
}
|
||
|
||
esData = append(esData, data)
|
||
}
|
||
}
|
||
}
|
||
resp.List = esData
|
||
} else {
|
||
// 补充关联的供应商和店铺信息
|
||
for i := range resp.List {
|
||
var purchaseOrderInfo ErpPurchaseOrder
|
||
err = orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrderInfo).Error
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
resp.List[i].StoreId = purchaseOrderInfo.StoreId
|
||
resp.List[i].StoreName = purchaseOrderInfo.StoreName
|
||
resp.List[i].ErpSupplierId = purchaseOrderInfo.ErpSupplierId
|
||
resp.List[i].ErpSupplierName = purchaseOrderInfo.ErpSupplierName
|
||
|
||
if resp.List[i].PurchaseType == "reject" {
|
||
//// 查询退货商品的采购金额
|
||
//var oldOrderInfo ErpPurchaseOrder
|
||
//err = orm.Eloquent.Where("serial_number = ?", purchaseOrderInfo.SerialNumber).First(&oldOrderInfo).Error
|
||
//if err != nil {
|
||
// return nil, err
|
||
//}
|
||
|
||
// 查找对应的采购入库记录
|
||
var resultInfo ResultPrice
|
||
resultInfo, err = GetTotalWholesalePrice(resp.List[i].ErpCommodityId, resp.List[i].SerialNumber)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp.List[i].Difference = -(resultInfo.TotalWholesalePrice - resp.List[i].Amount)
|
||
resp.List[i].RejectAmount = -resp.List[i].Amount
|
||
resp.List[i].Amount = -resultInfo.TotalWholesalePrice
|
||
resp.List[i].Count = -resp.List[i].Count
|
||
}
|
||
}
|
||
}
|
||
|
||
mergedData := mergeData(resp.List)
|
||
|
||
// 统计总计数量和金额
|
||
var totalAmount float64
|
||
var totalCount int32
|
||
var totalRejectAmount float64
|
||
var totalDifference float64
|
||
for _, item := range mergedData {
|
||
totalAmount += item.Amount
|
||
totalCount += item.Count
|
||
totalRejectAmount += item.RejectAmount
|
||
totalDifference += item.Difference
|
||
}
|
||
|
||
resp.Amount = totalAmount
|
||
resp.Count = totalCount
|
||
resp.RejectAmount = totalRejectAmount
|
||
resp.Difference = totalDifference
|
||
resp.Total = len(mergedData)
|
||
|
||
// 排序规则:供应商编号小>商品编号小>店铺编号小>类型为采购入库
|
||
sort.Slice(mergedData, func(i, j int) bool {
|
||
if mergedData[i].ErpSupplierId != mergedData[j].ErpSupplierId {
|
||
return mergedData[i].ErpSupplierId < mergedData[j].ErpSupplierId
|
||
}
|
||
if mergedData[i].ErpCommodityId != mergedData[j].ErpCommodityId {
|
||
return mergedData[i].ErpCommodityId < mergedData[j].ErpCommodityId
|
||
}
|
||
if mergedData[i].StoreId != mergedData[j].StoreId {
|
||
return mergedData[i].StoreId < mergedData[j].StoreId
|
||
}
|
||
if mergedData[i].PurchaseType == ErpProcureOrder && mergedData[j].PurchaseType != ErpProcureOrder {
|
||
return true
|
||
}
|
||
if mergedData[i].PurchaseType != ErpProcureOrder && mergedData[j].PurchaseType == ErpProcureOrder {
|
||
return false
|
||
}
|
||
return false // 默认情况下相等
|
||
})
|
||
|
||
// 分页处理
|
||
startIdx := (resp.PageIndex - 1) * resp.PageSize
|
||
endIdx := resp.PageIndex * resp.PageSize
|
||
|
||
// 确保不超出索引范围
|
||
if startIdx >= len(mergedData) {
|
||
resp.List = []PurchaseReportData{}
|
||
} else if endIdx > len(mergedData) {
|
||
resp.List = mergedData[startIdx:]
|
||
} else {
|
||
resp.List = mergedData[startIdx:endIdx]
|
||
}
|
||
|
||
if req.IsExport == 1 {
|
||
filePath, err := reportBySupplierExport(resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp = &ErpPurchaseReportBySupplierResp{}
|
||
resp.ExportUrl = filePath
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
//func mergeData(esData []PurchaseReportData) []PurchaseReportData {
|
||
// mergedMap := make(map[string]*PurchaseReportData)
|
||
//
|
||
// // 遍历 esData 数据
|
||
// for _, data := range esData {
|
||
// key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType)
|
||
// if _, ok := mergedMap[key]; !ok {
|
||
// // 如果键不存在,创建新条目
|
||
// mergedMap[key] = &PurchaseReportData{
|
||
// StoreId: data.StoreId,
|
||
// ErpSupplierId: data.ErpSupplierId,
|
||
// ErpCommodityId: data.ErpCommodityId,
|
||
// StoreName: data.StoreName,
|
||
// PurchaseType: data.PurchaseType,
|
||
// ErpSupplierName: data.ErpSupplierName,
|
||
// ErpCommodityName: data.ErpCommodityName,
|
||
// ErpCategoryID: data.ErpCategoryID,
|
||
// ErpCategoryName: data.ErpCategoryName,
|
||
// Count: data.Count,
|
||
// Amount: data.Amount,
|
||
// RejectAmount: data.RejectAmount,
|
||
// Difference: data.Difference,
|
||
// }
|
||
// } else {
|
||
// // 如果键已存在,进行累加操作
|
||
// mergedMap[key].Count += data.Count
|
||
// mergedMap[key].Amount += data.Amount
|
||
// mergedMap[key].RejectAmount += data.RejectAmount
|
||
// mergedMap[key].Difference += data.Difference
|
||
// }
|
||
// }
|
||
//
|
||
// // 将合并后的数据转换为数组返回
|
||
// var mergedData []PurchaseReportData
|
||
// for _, v := range mergedMap {
|
||
// mergedData = append(mergedData, *v)
|
||
// }
|
||
//
|
||
// return mergedData
|
||
//}
|
||
|
||
func mergeData(esData []PurchaseReportData) []PurchaseReportData {
|
||
mergedMap := make(map[string]*PurchaseReportData)
|
||
var keys []string // 用于记录键的顺序
|
||
|
||
// 遍历 esData 数据
|
||
for _, data := range esData {
|
||
key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType)
|
||
if _, ok := mergedMap[key]; !ok {
|
||
// 如果键不存在,创建新条目
|
||
mergedMap[key] = &PurchaseReportData{
|
||
StoreId: data.StoreId,
|
||
ErpSupplierId: data.ErpSupplierId,
|
||
ErpCommodityId: data.ErpCommodityId,
|
||
StoreName: data.StoreName,
|
||
PurchaseType: data.PurchaseType,
|
||
ErpSupplierName: data.ErpSupplierName,
|
||
ErpCommodityName: data.ErpCommodityName,
|
||
ErpCategoryID: data.ErpCategoryID,
|
||
ErpCategoryName: data.ErpCategoryName,
|
||
Count: data.Count,
|
||
Amount: data.Amount,
|
||
RejectAmount: data.RejectAmount,
|
||
Difference: data.Difference,
|
||
}
|
||
|
||
keys = append(keys, key) // 将键添加到有序的键列表中
|
||
} else {
|
||
// 如果键已存在,进行累加操作
|
||
mergedMap[key].Count += data.Count
|
||
mergedMap[key].Amount += data.Amount
|
||
mergedMap[key].RejectAmount += data.RejectAmount
|
||
mergedMap[key].Difference += data.Difference
|
||
}
|
||
}
|
||
|
||
// 根据有序的键列表顺序构建返回的数组
|
||
var mergedData []PurchaseReportData
|
||
for _, key := range keys {
|
||
mergedData = append(mergedData, *mergedMap[key])
|
||
}
|
||
|
||
return mergedData
|
||
}
|
||
|
||
// 导出供应商采购汇总excel
|
||
func reportBySupplierExport(req *ErpPurchaseReportBySupplierResp) (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.Errorf("file set value err:", err)
|
||
}
|
||
}
|
||
|
||
var row []interface{}
|
||
nExcelStartRow := 0
|
||
for _, supplierData := range req.List {
|
||
var orderType string
|
||
switch supplierData.PurchaseType {
|
||
case "procure":
|
||
orderType = "采购入库"
|
||
case "reject":
|
||
orderType = "采购退货"
|
||
}
|
||
row = []interface{}{
|
||
supplierData.StoreName, // 店铺名称
|
||
orderType, // 采购类型
|
||
supplierData.ErpSupplierName, // 供应商
|
||
supplierData.ErpCommodityName, // 商品名称
|
||
supplierData.ErpCategoryName, // 商品分类
|
||
supplierData.Count, // 采购数量
|
||
supplierData.Amount, // 采购金额
|
||
supplierData.RejectAmount, // 退货金额
|
||
supplierData.Difference, // 差额
|
||
}
|
||
|
||
for j, _ := range row {
|
||
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
|
||
err := file.SetCellValue(fSheet, cell, row[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.Count, // 采购数量
|
||
req.Amount, // 采购金额
|
||
req.RejectAmount, // 退货金额
|
||
req.Difference, // 差额
|
||
}
|
||
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", 25)
|
||
file.SetColWidth("Sheet1", "D", "D", 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
|
||
}
|
||
|
||
// GetReportDetail 查询采购明细
|
||
func GetReportDetail(req *ErpPurchaseReportDetailReq, c *gin.Context) (*ErpPurchaseReportDetailResp, 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 {
|
||
req.StoreId = CompareLists(storeList, req.StoreId)
|
||
if len(req.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
|
||
return &ErpPurchaseReportDetailResp{}, nil
|
||
}
|
||
} else {
|
||
return nil, errors.New("用户未绑定门店")
|
||
}
|
||
}
|
||
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
resp := &ErpPurchaseReportDetailResp{
|
||
PageIndex: page + 1,
|
||
PageSize: req.PageSize,
|
||
List: make([]struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
|
||
OrderSerialNumber string `json:"order_serial_number"`
|
||
SerialNumber string `json:"serial_number"`
|
||
PurchaseType string `json:"purchase_type"`
|
||
ExecuteTime *time.Time `json:"execute_time"`
|
||
StoreId uint32 `json:"store_id"`
|
||
StoreName string `json:"store_name"`
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"`
|
||
ErpSupplierName string `json:"erp_supplier_name"`
|
||
ErpCommodityId uint32 `json:"erp_commodity_id"`
|
||
ErpCommodityName string `json:"erp_commodity_name"`
|
||
ErpCategoryID uint32 `json:"erp_category_id"`
|
||
ErpCategoryName string `json:"erp_category_name"`
|
||
IMEIType uint32 `json:"imei_type"`
|
||
IMEI string `json:"imei"`
|
||
Price float64 `json:"price"`
|
||
EmployeePrice float64 `json:"employee_price"`
|
||
RejectPrice float64 `json:"reject_price"`
|
||
DifferencePrice float64 `json:"difference_price"`
|
||
}, 0),
|
||
}
|
||
|
||
qs := orm.Eloquent.Debug().Table("erp_purchase_order").
|
||
Select("erp_purchase_order.id as erp_purchase_order_id, "+
|
||
"erp_purchase_order.serial_number as order_serial_number, "+
|
||
"erp_purchase_inventory.serial_number, "+
|
||
"erp_purchase_order.purchase_type, "+
|
||
"erp_purchase_inventory.created_at as execute_time, "+
|
||
"erp_purchase_order.store_id, "+
|
||
"erp_purchase_order.store_name, "+
|
||
"erp_purchase_order.erp_supplier_id, "+
|
||
"erp_purchase_order.erp_supplier_name, "+
|
||
"erp_purchase_inventory.erp_commodity_id, "+
|
||
"erp_purchase_inventory.erp_commodity_name, "+
|
||
"erp_purchase_inventory.erp_category_id, "+
|
||
"erp_purchase_inventory.erp_category_name, "+
|
||
"erp_purchase_inventory.imei_type, "+
|
||
"erp_purchase_inventory.imei, "+
|
||
"CASE "+
|
||
"WHEN erp_purchase_order.purchase_type = 'procure' THEN erp_purchase_inventory.implementation_price "+
|
||
"WHEN erp_purchase_order.purchase_type = 'reject' THEN erp_purchase_inventory.implementation_price "+
|
||
"ELSE 0 END AS price, "+
|
||
"CASE "+
|
||
"WHEN erp_purchase_order.purchase_type = 'procure' THEN 0 "+
|
||
"WHEN erp_purchase_order.purchase_type = 'reject' THEN erp_purchase_inventory.implementation_price "+
|
||
"ELSE 0 END AS reject_price, "+
|
||
"erp_purchase_inventory.employee_price, "+
|
||
"(erp_purchase_inventory.implementation_price - erp_purchase_inventory.employee_price) as difference_price").
|
||
Joins("JOIN erp_purchase_inventory ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
|
||
Where("erp_purchase_order.state <> ?", 5) // 排除已终止的订单
|
||
|
||
// 创建一个新的查询对象,用于 count 查询
|
||
countQuery := orm.Eloquent.Debug().Table("erp_purchase_order").
|
||
Joins("JOIN erp_purchase_inventory ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
|
||
Where("erp_purchase_order.state <> ?", 5) // 排除已终止的订单
|
||
|
||
if req.SerialNumber != "" {
|
||
qs = qs.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
|
||
countQuery = countQuery.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
|
||
}
|
||
if req.PurchaseType != "" {
|
||
qs = qs.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
|
||
countQuery = countQuery.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
|
||
}
|
||
if req.ErpCommodityName != "" {
|
||
qs = qs.Where("erp_purchase_inventory.erp_commodity_name LIKE ?", "%"+req.ErpCommodityName+"%")
|
||
countQuery = countQuery.Where("erp_purchase_inventory.erp_commodity_name LIKE ?", "%"+req.ErpCommodityName+"%")
|
||
}
|
||
if req.ErpCategoryID != 0 {
|
||
qs = qs.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
|
||
}
|
||
if req.ErpSupplierId != 0 {
|
||
qs = qs.Where("erp_purchase_order.erp_supplier_id = ?", req.ErpSupplierId)
|
||
countQuery = countQuery.Where("erp_purchase_order.erp_supplier_id = ?", req.ErpSupplierId)
|
||
}
|
||
if req.IMEI != "" {
|
||
qs = qs.Where("erp_purchase_inventory.imei = ?", req.IMEI)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.imei = ?", req.IMEI)
|
||
}
|
||
if req.StartTime != "" { // 入/出库开始时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
|
||
if err != nil {
|
||
logger.Errorf("GetReportDetail err:", err)
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("erp_purchase_inventory.created_at >= ?", parse)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.created_at >= ?", parse)
|
||
}
|
||
if req.EndTime != "" { // 入/出库结束时间
|
||
parse, err := time.Parse(QueryTimeFormat, req.EndTime)
|
||
if err != nil {
|
||
logger.Errorf("GetReportDetail err:", err)
|
||
return nil, err
|
||
}
|
||
qs = qs.Where("erp_purchase_inventory.created_at <= ?", parse)
|
||
countQuery = countQuery.Where("erp_purchase_inventory.created_at <= ?", parse)
|
||
}
|
||
|
||
if len(req.StoreId) > 0 {
|
||
qs = qs.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
|
||
countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
|
||
}
|
||
|
||
var count int64
|
||
err := countQuery.Count(&count).Error
|
||
if err != nil {
|
||
logger.Errorf("GetReportDetail count err:", err)
|
||
return nil, err
|
||
}
|
||
|
||
offset := (req.PageIndex - 1) * req.PageSize
|
||
err = qs.Order("erp_purchase_inventory.created_at desc").
|
||
Offset(offset).
|
||
Limit(req.PageSize).
|
||
Scan(&resp.List).Error
|
||
if err != nil {
|
||
logger.Errorf("GetReportDetail scan err:", err)
|
||
return nil, err
|
||
}
|
||
|
||
// 根据订单类型调整价格的正负性
|
||
for i := range resp.List {
|
||
resp.List[i].DifferencePrice = 0
|
||
|
||
if resp.List[i].PurchaseType == "reject" {
|
||
// 采购退货单查询采购价:根据采购入库编号
|
||
price, err := getPrice(resp.List[i].SerialNumber)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
resp.List[i].Price = -price
|
||
resp.List[i].DifferencePrice = -resp.List[i].DifferencePrice
|
||
resp.List[i].RejectPrice = -resp.List[i].RejectPrice
|
||
resp.List[i].EmployeePrice = -resp.List[i].EmployeePrice
|
||
|
||
resp.List[i].DifferencePrice = resp.List[i].Price - resp.List[i].RejectPrice
|
||
}
|
||
}
|
||
|
||
resp.Total = int(count)
|
||
resp.Price, resp.EmployeePrice, resp.RejectPrice, resp.DifferencePrice = calculatePrices(resp.List)
|
||
|
||
if req.IsExport == 1 {
|
||
filePath, err := reportDetailExport(resp)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
resp = &ErpPurchaseReportDetailResp{}
|
||
resp.ExportUrl = filePath
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// 根据采购单据号查询入库采购价
|
||
func getPrice(serialNumber string) (float64, error) {
|
||
var stockCommodity ErpStockCommodity
|
||
err := orm.Eloquent.Table("erp_stock_commodity").Where("stock_sn = ?", serialNumber).
|
||
Find(&stockCommodity).Error
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
|
||
return stockCommodity.WholesalePrice, nil
|
||
}
|
||
|
||
// 计算价格信息
|
||
func calculatePrices(list []struct {
|
||
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
|
||
OrderSerialNumber string `json:"order_serial_number"`
|
||
SerialNumber string `json:"serial_number"`
|
||
PurchaseType string `json:"purchase_type"`
|
||
ExecuteTime *time.Time `json:"execute_time"`
|
||
StoreId uint32 `json:"store_id"`
|
||
StoreName string `json:"store_name"`
|
||
ErpSupplierId uint32 `json:"erp_supplier_id"`
|
||
ErpSupplierName string `json:"erp_supplier_name"`
|
||
ErpCommodityId uint32 `json:"erp_commodity_id"`
|
||
ErpCommodityName string `json:"erp_commodity_name"`
|
||
ErpCategoryID uint32 `json:"erp_category_id"`
|
||
ErpCategoryName string `json:"erp_category_name"`
|
||
IMEIType uint32 `json:"imei_type"`
|
||
IMEI string `json:"imei"`
|
||
Price float64 `json:"price"`
|
||
EmployeePrice float64 `json:"employee_price"`
|
||
RejectPrice float64 `json:"reject_price"`
|
||
DifferencePrice float64 `json:"difference_price"`
|
||
}) (price, employeePrice, rejectPrice, differencePrice float64) {
|
||
for _, item := range list {
|
||
price += item.Price
|
||
employeePrice += item.EmployeePrice
|
||
rejectPrice += item.RejectPrice
|
||
differencePrice += item.DifferencePrice
|
||
}
|
||
return
|
||
}
|
||
|
||
// 导出采购明细excel
|
||
func reportDetailExport(req *ErpPurchaseReportDetailResp) (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.Errorf("file set value err:", err)
|
||
}
|
||
}
|
||
|
||
var row []interface{}
|
||
nExcelStartRow := 0
|
||
for _, detailData := range req.List {
|
||
var orderType string
|
||
switch detailData.PurchaseType {
|
||
case "procure":
|
||
orderType = "采购入库"
|
||
case "reject":
|
||
orderType = "采购退货"
|
||
}
|
||
|
||
var IMEIType string
|
||
switch detailData.IMEIType {
|
||
case 1:
|
||
IMEIType = "非串码"
|
||
case 2, 3:
|
||
IMEIType = "串码类"
|
||
}
|
||
|
||
row = []interface{}{
|
||
detailData.OrderSerialNumber, // 单据编号
|
||
orderType, // 单据类型
|
||
detailData.ExecuteTime.Format(TimeFormat), // 出/入库时间
|
||
detailData.StoreName, // 店铺名称
|
||
detailData.ErpSupplierName, // 供应商
|
||
detailData.ErpCommodityName, // 商品名称
|
||
detailData.ErpCategoryName, // 商品分类
|
||
IMEIType, // 是否串码
|
||
detailData.IMEI, // 串码
|
||
detailData.Price, // 采购价
|
||
detailData.EmployeePrice, // 员工成本价
|
||
detailData.RejectPrice, // 退货价
|
||
detailData.DifferencePrice, // 差价
|
||
}
|
||
|
||
for j, _ := range row {
|
||
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
|
||
err := file.SetCellValue(fSheet, cell, row[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.Price, // 采购价
|
||
req.EmployeePrice, // 员工成本价
|
||
req.RejectPrice, // 退货价
|
||
req.DifferencePrice, // 差价
|
||
}
|
||
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", 15)
|
||
file.SetColWidth("Sheet1", "C", "C", 20)
|
||
file.SetColWidth("Sheet1", "D", "D", 26)
|
||
file.SetColWidth("Sheet1", "F", "F", 18)
|
||
file.SetColWidth("Sheet1", "I", "I", 18)
|
||
|
||
endRow := fmt.Sprintf("M"+"%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
|
||
}
|
||
|
||
// CancelAuditUpdateStock 反审核后更新库存信息
|
||
// 查询订单有无入库信息
|
||
// 采购单,有入库信息,则退库;如果有已审核的退货单则不能反审核,报错提示
|
||
// 退货单,有入库信息,则入库
|
||
func CancelAuditUpdateStock(begin *gorm.DB, req ErpPurchaseOrder) error {
|
||
var purchaseOrder ErpPurchaseOrder
|
||
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ID).Find(&purchaseOrder).Error
|
||
if err != nil {
|
||
logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
var inventoryList []ErpPurchaseInventory
|
||
err = orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", req.ID).
|
||
Find(&inventoryList).Error
|
||
if err != nil {
|
||
logger.Error("purchase commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
|
||
if len(inventoryList) == 0 { // 还没有入库记录,直接取消审核
|
||
return nil
|
||
}
|
||
|
||
if req.PurchaseType == ErpProcureOrder { // 采购单反审核
|
||
// 查询有无退货订单
|
||
var count int64
|
||
stateList := []int{ErpPurchaseOrderUnAudit, ErpPurchaseOrderEnd}
|
||
err = orm.Eloquent.Table("erp_purchase_order").Where("rejected_serial_number = ? and state NOT IN (?)",
|
||
req.SerialNumber, stateList).Count(&count).Error
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if count > 0 { // 有已审核的退货单
|
||
return errors.New("取消审核失败:已存在采购退库订单,请先将其取消")
|
||
}
|
||
|
||
//// 更新入库的商品为"采购退库"
|
||
//reqParam := &ErpPurchaseInventoryReq{
|
||
// ErpPurchaseOrderId: req.ID,
|
||
// PurchaseType: ErpRejectOrder,
|
||
// Inventories: inventoryList,
|
||
//}
|
||
|
||
// 按照采购退货更新库存
|
||
err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder)
|
||
if err != nil {
|
||
return fmt.Errorf("取消审核失败:%s", err.Error())
|
||
}
|
||
|
||
// 更新采购商品表的入库数量
|
||
for _, v := range inventoryList {
|
||
err = begin.Model(&ErpPurchaseCommodity{}).
|
||
Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
|
||
UpdateColumn("inventory_count", gorm.Expr("inventory_count - ?", v.Count)).Error
|
||
if err != nil {
|
||
logger.Error("update inventory count err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
} else if req.PurchaseType == ErpRejectOrder { // 退货单反审核
|
||
// 更新入库的商品为"采购退库"
|
||
reqParam := &ErpPurchaseInventoryReq{
|
||
ErpPurchaseOrderId: req.ID,
|
||
PurchaseType: ErpProcureOrder,
|
||
Inventories: inventoryList,
|
||
}
|
||
|
||
// 采购退货单反审核更新库存
|
||
err = ErpRejectOrderCancelAuditUpdateStock(begin, reqParam, purchaseOrder)
|
||
if err != nil {
|
||
return fmt.Errorf("取消审核失败:%s", err.Error())
|
||
}
|
||
|
||
// 更新采购商品表的入库数量
|
||
for _, v := range inventoryList {
|
||
err = begin.Model(&ErpPurchaseCommodity{}).
|
||
Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
|
||
UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error
|
||
if err != nil {
|
||
logger.Error("update inventory count err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
} else {
|
||
return errors.New("取消审核失败:采购类型有误")
|
||
}
|
||
|
||
// 删除采购入库的记录
|
||
err = begin.Table("erp_purchase_inventory").Where("erp_purchase_order_id = ? and purchase_type = ?",
|
||
req.ID, req.PurchaseType).Delete(&ErpPurchaseInventory{}).Error
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// ErpRejectOrderCancelAuditUpdateStock 采购退货单反审核更新库存
|
||
func ErpRejectOrderCancelAuditUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error {
|
||
// 遍历采购入库商品信息
|
||
var stockList []ErpStockCommodity
|
||
for _, v := range req.Inventories {
|
||
commodityInfo, err := GetCommodity(v.ErpCommodityId)
|
||
if err != nil {
|
||
logger.Errorf("GetCommodity err:", err)
|
||
return err
|
||
}
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
|
||
purchaseOrder.StoreId, v.ErpCommodityId))
|
||
if err != nil {
|
||
logger.Errorf("exist err:", err)
|
||
return err
|
||
}
|
||
if exist {
|
||
err = gdb.Exec(fmt.Sprintf(
|
||
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;",
|
||
v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error
|
||
if err != nil {
|
||
logger.Errorf("update stock err:", err)
|
||
return err
|
||
}
|
||
} else {
|
||
return errors.New("未查询到商品库存信息")
|
||
}
|
||
|
||
// 更新商品库存信息
|
||
// 串码商品直接更新状态为:在库
|
||
if v.IMEIType == 2 || v.IMEIType == 3 { // 串码商品
|
||
if v.IMEI == "" {
|
||
return fmt.Errorf("商品[%s]串码为空", v.ErpCommodityName)
|
||
}
|
||
|
||
err = gdb.Table("erp_stock_commodity").Where("imei = ?", v.IMEI).
|
||
Update("state", InStock).Error // 状态更新为采购退货
|
||
if err != nil {
|
||
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
|
||
return err
|
||
}
|
||
}
|
||
|
||
// 非串码商品则新建
|
||
nowTime := time.Now()
|
||
stockCommodity := ErpStockCommodity{
|
||
StoreId: purchaseOrder.StoreId,
|
||
StoreName: purchaseOrder.StoreName,
|
||
ErpCommodityId: v.ErpCommodityId,
|
||
ErpCommodityName: v.ErpCommodityName,
|
||
CommoditySerialNumber: v.CommoditySerialNumber,
|
||
ErpCategoryId: commodityInfo.ErpCategoryId,
|
||
ErpCategoryName: commodityInfo.ErpCategoryName,
|
||
ErpSupplierId: purchaseOrder.ErpSupplierId,
|
||
ErpSupplierName: purchaseOrder.ErpSupplierName,
|
||
StaffCostPrice: tools.RoundToTwoDecimalPlaces(v.EmployeePrice - v.ImplementationPrice),
|
||
WholesalePrice: tools.RoundToTwoDecimalPlaces(v.ImplementationPrice),
|
||
State: InStock,
|
||
StorageType: PurchaseInventory, // 采购入库
|
||
FirstStockTime: nowTime,
|
||
StockTime: nowTime,
|
||
Count: v.Count,
|
||
ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码
|
||
IMEIType: v.IMEIType,
|
||
IMEI: v.IMEI,
|
||
Remark: "",
|
||
MemberDiscount: commodityInfo.MemberDiscount,
|
||
MinRetailPrice: commodityInfo.MinRetailPrice,
|
||
RetailPrice: commodityInfo.RetailPrice,
|
||
OriginalSn: purchaseOrder.SerialNumber,
|
||
}
|
||
stockList = append(stockList, stockCommodity)
|
||
}
|
||
|
||
err := gdb.Debug().Create(&stockList).Error
|
||
if err != nil {
|
||
logger.Errorf("create stock commodity err:", err)
|
||
return err
|
||
}
|
||
|
||
return nil
|
||
}
|