mh_goadmin_server/app/admin/models/purchase.go
chenlin 55b2ddd8ef 1.修复缺陷;
2.新增系统生成串码接口;
2024-04-22 09:51:41 +08:00

5507 lines
195 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

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

package models
import (
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"go-admin/tools/config"
"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
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
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("操作失败:交货日期为空")
}
} else if req.PurchaseType == ErpRejectOrder { // 退货单
if req.PurchaseOrderSn == "" {
return errors.New("操作失败:采购退货单据编号为空")
}
} 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 {
v.SerialNumber = GetPurchaseInventorySn()
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++ { // 采购入库记录表都是单笔数据
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
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,
}
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)
}
err := gdb.Debug().Create(&stockList).Error
if err != nil {
logger.Errorf("create stock commodity err:", err)
return err
}
return nil
}
// 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, purchaseOrder.StoreId, 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 {
// 获取商品信息
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) (*GetErpPurchaseDemandResp, error) {
var err error
resp := new(GetErpPurchaseDemandResp)
if req.HideFlag == "ON" { // 隐藏无采购需求的商品
resp, err = getErpPurchaseDemandHide(req)
} else { // 展示所有
resp, err = getErpPurchaseDemandAll(req)
}
if err != nil {
return nil, err
}
return resp, nil
}
// 展示所有采购需求
func getErpPurchaseDemandAll(req *GetErpPurchaseDemandReq) (*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
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
}
}
// 批量查询门店信息
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()
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 = count
}
return resp, nil
}
// 隐藏无采购需求的商品
func getErpPurchaseDemandHide(req *GetErpPurchaseDemandReq) (*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()
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 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
// 设置最近采购价
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) (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
}
// 保护 totalSales 的并发访问
mu.Lock()
defer mu.Unlock()
totalSales += sales
}(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
}
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
}
// 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)
}
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
}
// 计算不同的 ErpCommodityId 的数量
differentCommodityCount := len(commodityMap)
var reportOrderDataList []ReportByOrderData
var nTotalAmount float64
var nTotalCount int32
// 查询采购订单信息
for _, v := 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 = ?", v).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 != 1") // 未审核订单不展示
if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber)
} else {
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.IsExport == 1 { // 导出excel
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(v.ID)
if err != nil {
return nil, err
}
reportByOrderData.Amount = nAmount
reportByOrderData.Count = nCount
if nCount != 0 {
reportByOrderData.Price = nAmount / float64(nCount)
}
reportByOrderDataList = append(reportByOrderDataList, reportByOrderData)
nTotalAmount += nAmount
nTotalCount += nCount
}
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(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 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)
}
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
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
}
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 {
reportByCommodityData.ErpCommodityId = orderIdSet[0].ErpPurchaseCommodityId
reportByCommodityData.ErpCommodityName = orderIdSet[0].ErpCommodityName
reportByCommodityData.ErpCategoryID = orderIdSet[0].ErpCategoryID
reportByCommodityData.ErpCategoryName = orderIdSet[0].ErpCategoryName
}
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)
}
resp.List = reportByCommodityDataList
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 != 1")
if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber)
} else {
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 {
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)
}
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)
resp.List = dataList
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
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)
}
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_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_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
if req.IsExport == 1 { // 导出excel
err = query.Find(&resp.List).Error
} else {
//err = query.Offset((req.PageIndex - 1) * req.PageSize).Limit(req.PageSize).Find(&resp.List).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 Result
resultInfo, err = GetTotalsAndAveragesByCommodityID(respItem.ErpCommodityId, oldOrderInfo.ID)
if err != nil {
return nil, err
}
data.RejectAmount = -data.Amount
data.Amount = -resultInfo.AvgImplementationPrice * float64(data.Count)
data.Difference = data.RejectAmount - data.Amount
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 Result
resultInfo, err = GetTotalsAndAveragesByCommodityID(resp.List[i].ErpCommodityId, oldOrderInfo.ID)
if err != nil {
return nil, err
}
resp.List[i].RejectAmount = -resp.List[i].Amount
resp.List[i].Amount = -resultInfo.AvgImplementationPrice * float64(resp.List[i].Count)
resp.List[i].Difference = resp.List[i].RejectAmount - resp.List[i].Amount
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)
// 分页处理
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.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
}