mh_goadmin_server/app/admin/models/purchase.go

4339 lines
152 KiB
Go
Raw Normal View History

package models
import (
"errors"
"fmt"
"github.com/xuri/excelize/v2"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools/config"
"gorm.io/gorm"
"math/rand"
"sort"
"strconv"
"strings"
2024-02-23 10:06:21 +00:00
"sync"
"time"
)
const (
ErpPurchaseOrderUnAudit = 1 // 待审核
ErpPurchaseOrderWaitInventory = 2 // 待入库
ErpPurchaseOrderWaitReject = 3 // 待退货
ErpPurchaseOrderFinished = 4 // 已完成
ErpPurchaseOrderEnd = 5 // 已终止
ErpPurchaseOrderInInventory = 6 // 入库中,部分入库
ErpPurchaseOrderInReject = 7 // 退货中,部分退货
ErpProcureOrder = "procure" // 采购入库订单
ErpRejectOrder = "reject" // 采购退货订单
2024-02-23 10:06:21 +00:00
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"` // 供应商名称
2024-02-23 10:06:21 +00:00
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-已终止
RejectedPurchaseOrderId uint32 `json:"rejected_purchase_order_id"` // 退货采购订单id
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"` // 银行卡号
2024-02-23 10:06:21 +00:00
DeliveryTime string `json:"delivery_time"` // 交货日期2024-02-23
DeliveryAddress string `json:"delivery_address"` // 交货地址
Remark string `json:"remark"` // 备注
Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"`
}
// ErpPurchaseCommodity 采购订单商品表
type ErpPurchaseCommodity struct {
Model
2024-02-23 10:06:21 +00:00
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 uint32 `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:"-"` // 执行金额
}
// ErpPurchaseInventory 采购入库执行信息
type ErpPurchaseInventory struct {
Model
2024-02-23 10:06:21 +00:00
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"` // 商品分类名称
2024-02-23 10:06:21 +00:00
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
Count uint32 `json:"count"` // 执行数量
ImplementationPrice float64 `json:"implementation_price"` // 执行单价
Amount float64 `json:"amount"` // 执行金额
EmployeePrice float64 `json:"employee_price"` // 员工成本价
}
// 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" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式
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" binding:"required"` // 门店id
DeliveryAddress string `json:"delivery_address" binding:"required"` // 交货地址
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 供应商id
ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式
AccountHolder string `json:"account_holder"` // 收款人
OpeningBank string `json:"opening_bank" validate:"required"` // 开户行
BankAccount string `json:"bank_account" validate:"required"` // 银行卡号
DeliveryTime string `json:"delivery_time" binding:"required"` // 交货日期
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-已终止
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
2024-02-23 10:06:21 +00:00
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"` // 备注
}
// ErpPurchaseExecuteResp 执行(入库/退货)出参
type ErpPurchaseExecuteResp struct {
2024-02-23 10:06:21 +00:00
List []ExecuteData `json:"list"`
Total int `json:"total"` // 总条数
}
// ExecuteData 库存执行数据
type ExecuteData struct {
2024-02-23 10:06:21 +00:00
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 库存执行表
2024-02-23 10:06:21 +00:00
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
PurchaserId uint32 `json:"purchaser_id"` // 采购人id
FinishTime *time.Time `json:"finish_time"` // 完成采购时间
Remark string `json:"remark"` // 备注
}
// GetErpPurchaseDemandReq 获取采购需求入参
2024-02-23 10:06:21 +00:00
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-导出
2024-02-23 10:06:21 +00:00
}
// DemandData 采购需求数据
2024-02-23 10:06:21 +00:00
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 uint32 `json:"retail_price"` // 指导零售价
LastWholesalePrice float64 `json:"last_wholesale_price"` // 最近采购价
TotalCount uint32 `json:"total_count"` // 需采购总数量
TotalAmount float64 `json:"total_amount"` // 需采购总金额
Remark string `json:"remark"` // 备注
2024-02-23 10:06:21 +00:00
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 获取采购需求出参
2024-02-23 10:06:21 +00:00
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 创建采购需求入参
2024-02-23 10:06:21 +00:00
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 完成采购需求入参
2024-02-23 10:06:21 +00:00
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"` // 1-待审核 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 uint32 `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 uint32 `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 {
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 uint32 `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"` // 1-待审核 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 uint32 `json:"plan_count"` // 计划采购数量
PlanPrice float64 `json:"plan_price"` // 计划采购单价
PlanAmount float64 `json:"plan_amount"` // 计划采购金额
Amount float64 `json:"amount"` // 已执行金额
Price float64 `json:"price"` // 已执行单价
Count uint32 `json:"count"` // 已执行数量
NonExecutionAmount float64 `json:"non_execution_amount"` // 未执行金额
NonExecutionCount uint32 `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:"startTime"` // 入/出库,开始时间
EndTime string `json:"endTime"` // 入/出库,结束时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
StoreList []struct {
StoreID uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
} `json:"store_list"` // 门店复选
}
// ErpPurchaseReportBySupplierResp 供应商采购汇总出参
type ErpPurchaseReportBySupplierResp struct {
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
Count uint32 `json:"count"` // 采购数量
Amount float64 `json:"amount"` // 采购金额
RejectAmount float64 `json:"reject_amount"` // 退货金额
Difference float64 `json:"difference"` // 差额
ExportUrl string `json:"export_url"` // 导出excel路径
List []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 uint32 `json:"count"` // 采购数量
Amount float64 `json:"amount"` // 采购金额
RejectAmount float64 `json:"reject_amount"` // 退货金额
Difference float64 `json:"difference"` // 差额
} `json:"list"` // 供应商采购汇总信息
}
// 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"` // 页面条数
StoreList []struct {
StoreID uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
} `json:"store_list"` // 门店复选
}
// 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 {
OrderSerialNumber string `json:"order_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() (*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-已终止
stateList = []int{2, 4, 5}
qs = qs.Where("state IN ?", stateList)
}
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 m.ErpSupplierId != 0 {
qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId)
}
if m.State != 0 {
qs = qs.Where("state=?", 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)
}
}
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
}
resp.List = orders
return resp, nil
}
// NewErpPurchaseSn 生成采购订单号
func NewErpPurchaseSn() string {
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create sn err")
return ""
}
random := rand.Int31n(9999) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE serial_number='%s'", sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
}
max++
}
}
func ErpPurchaseCommodityListPerfectInfo(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 {
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 {
2024-02-23 10:06:21 +00:00
purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price
}
if purchaseCommodities[i].RejectedCount != 0 {
2024-02-23 10:06:21 +00:00
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 ""
}
}
// CreateErpPurchaseOrder 新增采购订单
func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
var err error
nowTime := time.Now()
purchaseOrder := &ErpPurchaseOrder{}
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgr" + NewErpPurchaseSn(),
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 { // 采购退货订单
2024-02-23 10:06:21 +00:00
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: "cgt" + NewErpPurchaseSn(),
PurchaseType: req.PurchaseType,
StoreId: erpPurchaseOrder.StoreId,
ErpSupplierId: erpPurchaseOrder.ErpSupplierId,
MakerTime: nowTime,
2024-02-23 10:06:21 +00:00
HandlerId: req.HandlerId,
HandlerName: req.HandlerName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpPurchaseOrderUnAudit, // 1-待审核
ErpCashierId: req.ErpCashierId,
Remark: req.Remark,
}
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.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("订单不是待审核状态")
}
begin := orm.Eloquent.Begin()
// 1-更新采购订单信息
purchaseOrder.StoreId = req.StoreId
purchaseOrder.ErpSupplierId = req.ErpSupplierId
2024-02-23 10:06:21 +00:00
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 {
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) error {
err := checkPurchaseInventory(req)
if err != nil {
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
return err
}
begin := orm.Eloquent.Begin()
for _, v := range req.Inventories {
2024-02-23 10:06:21 +00:00
v.SerialNumber = GetPurchaseInventorySn()
// 更新采购商品表的执行数量
2024-02-23 10:06:21 +00:00
// todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息可能采购价不同需要区分入库的是哪一条(已修改)
err = begin.Model(&ErpPurchaseCommodity{}).
2024-02-23 10:06:21 +00:00
Where("id = ?", v.ErpPurchaseCommodityId).
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
}
// 新建采购入库记录
err = begin.Create(&v).Error
if err != nil {
begin.Rollback()
logger.Error("create erp inventory commodity err:", logger.Field("err", err))
return err
}
2024-02-23 10:06:21 +00:00
}
// 查询采购订单信息
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 purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单
err = InventoryErpPurchaseUpdateStock(begin, req, purchaseOrder)
} else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单
err = InventoryErpPurchaseUpdateRejectStock(begin, req, 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
}
return nil
}
2024-02-23 10:06:21 +00:00
// InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息
func InventoryErpPurchaseUpdateStock(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 {
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: uint32(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: uint32(v.ImplementationPrice),
State: 1,
StorageType: 1,
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,
}
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, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error {
for i, _ := range req.Inventories {
if req.Inventories[i].IMEIType == 2 { // 串码商品
if req.Inventories[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[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 = ?", req.Inventories[i].IMEI).
Update("state", PurchaseReturn).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, req.Inventories[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 { // 非串码商品
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 = ?", req.Inventories[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1).
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")
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID).
Update("state", PurchaseReturn).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, req.Inventories[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
}
2024-02-23 10:06:21 +00:00
countMap := make(map[uint32]uint32)
for _, inventory := range req.Inventories {
2024-02-23 10:06:21 +00:00
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)
}
}
}
// 入库的商品信息有误,不在之前的商品列表中
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 {
2024-02-23 10:06:21 +00:00
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)
}
}
}
}
return nil
}
// ExecuteErpPurchase 执行(入库/退货)
func ExecuteErpPurchase(req *ErpPurchaseInventoryReq) (*ErpPurchaseExecuteResp, error) {
err := checkPurchaseInventory(req)
if err != nil {
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
return nil, err
}
resp := &ErpPurchaseExecuteResp{
List: make([]ExecuteData, 0),
}
for _, inventory := range req.Inventories {
if inventory.IMEIType == 2 || inventory.IMEIType == 3 {
2024-02-23 10:06:21 +00:00
// 如果是串码商品,根据 Count 拆分成对应数量的数据
for i := 0; i < int(inventory.Count); i++ {
imei := "" // 默认退货单执行时不需要串码
if inventory.PurchaseType == ErpProcureOrder { // 采购单
// 调用函数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 inventory.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,
})
}
}
2024-02-23 10:06:21 +00:00
resp.Total = len(resp.List)
return resp, nil
}
2024-02-23 10:06:21 +00:00
// 生成串码
func generateIMEI(commodityId uint32) (string, error) {
commodity, err := GetCommodity(commodityId)
if err != nil {
return "", err
}
return GenerateSerialCode(commodity.ErpCategoryId)
}
2024-02-23 10:06:21 +00:00
// CreateErpPurchaseDemand 创建采购需求单
func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error {
var demandInfo ErpPurchaseDemand
var demandList []ErpPurchaseDemand
demandInfo.ErpCommodityId = req.ErpCommodityID
demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber
demandInfo.ErpCommodityName = req.ErpCommodityName
demandInfo.Remark = req.Remark
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)
}
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(v).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
}
}
}
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=?", 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) {
2024-02-23 10:06:21 +00:00
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 {
qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
}
if req.ErpCommoditySerialNumber != "" {
qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber)
}
if req.ErpCommodityName != "" {
qs = qs.Where("name=?", req.ErpCommodityName)
}
2024-02-23 10:06:21 +00:00
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
}
2024-02-23 10:06:21 +00:00
}
// 批量查询门店信息
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)
}
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))
}
}
2024-02-23 10:06:21 +00:00
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,
}
// 查询采购需求单
demands, err := GetCommodityPurchaseDemands(commodity.ID, stores)
if err != nil {
// Handle error
return DemandData{}, err
}
if len(demands) != 0 {
demandData.Remark = demands[0].Remark
}
2024-02-23 10:06:21 +00:00
// 使用 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 {
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
}
// 保护 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 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 = ?", commodityID).
Scan(&result).Error
if err != nil {
return Result{}, err
}
return result, nil
}
// UpdateRetailPrice 更新指导零售价
func UpdateRetailPrice(begin *gorm.DB, commodityId, retailPrice uint32) 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) (*ErpPurchaseReportByOrderResp, error) {
var err error
resp := new(ErpPurchaseReportByOrderResp)
if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
// 先筛选商品入库信息表,然后再补充采购订单信息
resp, err = getReportByOrderFromCommodityOrCategory(req)
} else {
// 先筛选采购订单表,再补充商品入库信息
resp, err = getReportByOrderFromCommon(req)
}
if err != nil {
return nil, err
}
return resp, nil
}
// 查询采购报表(按单):先筛选商品入库信息表,然后再补充采购订单信息
func getReportByOrderFromCommodityOrCategory(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseReportByOrderResp, error) {
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpPurchaseReportByOrderResp{
PageIndex: req.PageIndex + 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 uint32
// 查询采购订单信息
for _, v := range commodityMap {
var purchaseOrder ErpPurchaseOrder
var commodityList []ErpPurchaseCommodityData
err = orm.Eloquent.Table("erp_purchase_order").Where("id = ?", v).Find(&purchaseOrder).Error
if err != nil {
return nil, err
}
var reportByOrderData ReportByOrderData
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
var nAmount float64
var nCount uint32
for _, inventory := range inventoryList {
var commodityData ErpPurchaseCommodityData
if inventory.ErpPurchaseOrderId == purchaseOrder.ID {
commodityData.ErpCommodityId = inventory.ErpCommodityId
commodityData.ErpCommodityName = inventory.ErpCommodityName
commodityData.ErpCategoryID = inventory.ErpCategoryID
commodityData.ErpCategoryName = inventory.ErpCategoryName
commodityData.Amount = inventory.Amount
commodityData.Price = inventory.ImplementationPrice
commodityData.Count = inventory.Count
commodityList = append(commodityList, commodityData)
nAmount += inventory.Amount
nCount += inventory.Count
}
}
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) (*ErpPurchaseReportByOrderResp, error) {
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpPurchaseReportByOrderResp{
PageIndex: req.PageIndex + 1,
PageSize: req.PageSize,
}
qs := orm.Eloquent.Table("erp_purchase_order")
if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber)
} else {
if req.PurchaseType != "" { // 采购类型
qs = qs.Where("purchase_type=?", req.PurchaseType)
}
if req.StoreId != 0 { // 门店id
qs = qs.Where("store_id=?", req.StoreId)
}
if req.ErpSupplierId != 0 { // 供应商id
qs = qs.Where("erp_supplier_id=?", req.ErpSupplierId)
}
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 uint32
for _, v := range orders {
var reportByOrderData ReportByOrderData
var nAmount float64
var nCount uint32
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
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, uint32, 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
}
var resp []ErpPurchaseCommodityData
var nAmount float64
var nCount uint32
for _, v := range inventoryList {
var purchaseCommodityData ErpPurchaseCommodityData
purchaseCommodityData.ErpCommodityId = v.ErpCommodityId
purchaseCommodityData.ErpCommodityName = v.ErpCommodityName
purchaseCommodityData.ErpCategoryID = v.ErpCategoryID
purchaseCommodityData.ErpCategoryName = v.ErpCategoryName
purchaseCommodityData.Amount = v.Amount
purchaseCommodityData.Price = v.ImplementationPrice
purchaseCommodityData.Count = v.Count
resp = append(resp, purchaseCommodityData)
nAmount += v.Amount
nCount += v.Count
}
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 = "已终止"
}
row1 = []interface{}{
orderData.SerialNumber, // 单据编号
orderType, // 类型
orderData.StoreName, // 店铺名称
orderData.Remark, // 备注
orderData.ErpSupplierName, // 供应商
orderData.HandlerName, // 经手人
orderData.MakerName, // 制单人
orderData.AuditTime.Format(TimeFormat), // 审核时间
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) (*ErpPurchaseReportByCommodityResp, error) {
var err error
resp := new(ErpPurchaseReportByCommodityResp)
if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
// 先筛选商品入库信息表,然后再补充采购订单信息
resp, err = getReportByCommodityFromCommodityOrCategory(req)
} else {
// 先筛选采购订单表,再补充商品入库信息
resp, err = getReportByCommodityFromCommon(req)
}
if err != nil {
return nil, err
}
return resp, nil
}
// 查询采购报表(按商品):先筛选商品入库信息表,然后再补充采购订单信息
func getReportByCommodityFromCommodityOrCategory(req *ErpPurchaseReportByCommodityReq) (*ErpPurchaseReportByCommodityResp, error) {
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpPurchaseReportByCommodityResp{
PageIndex: req.PageIndex + 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)
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) (ErpCommodityPurchaseOrderData, error) {
var purchaseOrderData ErpCommodityPurchaseOrderData
// 查询采购订单信息
var purchaseOrder ErpPurchaseOrder
err := orm.Eloquent.Table("erp_purchase_order").Where("id = ?", orderID).Find(&purchaseOrder).Error
if err != nil {
return purchaseOrderData, err
}
// 查询采购订单的计划和执行信息
purchaseData, err := getPurchaseData(purchaseOrder.ID)
if err != nil {
return purchaseOrderData, err
}
// 组合数据
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
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, 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) (*ErpPurchaseReportByCommodityResp, error) {
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")
if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber)
} else {
if req.PurchaseType != "" { // 采购类型
qs = qs.Where("purchase_type=?", req.PurchaseType)
}
if req.StoreId != 0 { // 门店id
qs = qs.Where("store_id=?", req.StoreId)
}
if req.ErpSupplierId != 0 { // 供应商id
qs = qs.Where("erp_supplier_id=?", req.ErpSupplierId)
}
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.PlanPrice += v.PlanPrice
reportData.PlanAmount += v.PlanAmount
reportData.Amount += v.Amount
reportData.Price += v.Price
reportData.Count += v.Count
reportData.NonExecutionAmount += v.NonExecutionAmount
reportData.NonExecutionCount += v.NonExecutionCount
purchaseOrderData := ErpCommodityPurchaseOrderData{
CommonData{
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,
},
}
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.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
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, is_export int) (map[uint32][]uint32, error) {
var commodityMap = make(map[uint32][]uint32)
var query string
if is_export == 1 { //导出excel
// 执行原生 SQL 查询联结表格按照每个商品ID列出所有的订单ID
query = fmt.Sprintf(`
SELECT pc1.erp_commodity_id, GROUP_CONCAT(pc2.erp_purchase_order_id) AS order_ids
FROM erp_purchase_commodity pc1
JOIN erp_purchase_commodity pc2
ON pc1.erp_commodity_id = pc2.erp_commodity_id
GROUP BY pc1.erp_commodity_id`)
} else {
// 执行原生 SQL 查询联结表格按照每个商品ID列出所有的订单ID
query = fmt.Sprintf(`
SELECT pc1.erp_commodity_id, GROUP_CONCAT(pc2.erp_purchase_order_id) AS order_ids
FROM erp_purchase_commodity pc1
JOIN erp_purchase_commodity pc2
ON pc1.erp_commodity_id = pc2.erp_commodity_id
GROUP BY pc1.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 = "采购退货"
}
row2 = []interface{}{
"", // 商品名称
"", // 商品分类
orderData.SerialNumber, // 单据编号
orderType, // 类型
orderData.StoreName, // 店铺名称
orderData.ErpSupplierName, // 供应商
orderData.HandlerName, // 经手人
orderData.MakerName, // 制单人
orderData.AuditTime.Format(TimeFormat), // 审核时间
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) (*ErpPurchaseReportBySupplierResp, error) {
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 total_count, " +
"SUM(erp_purchase_inventory.amount) AS total_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)
}
if req.ErpCommodityName != "" {
query = query.Where("erp_purchase_inventory.erp_commodity_name = ?", req.ErpCommodityName)
}
if req.ErpCategoryID != 0 {
query = query.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
}
if req.ErpSupplierId != 0 {
query = query.Where("erp_purchase_inventory.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
}
query = query.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)
}
if len(req.StoreList) > 0 {
var storeIDs []uint32
for _, store := range req.StoreList {
storeIDs = append(storeIDs, store.StoreID)
}
query = query.Where("erp_purchase_order.store_id IN (?)", storeIDs)
}
// 获取总数
var total int64
query.Count(&total)
resp.Total = int(total)
// 分页查询
if req.IsExport == 1 { // 导出excel
query.Find(&resp.List)
} else {
query.Offset((req.PageIndex - 1) * req.PageSize).Limit(req.PageSize).Find(&resp.List)
}
// 补充关联的供应商和店铺信息
for i := range resp.List {
var purchaseOrder ErpPurchaseOrder
orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrder)
resp.List[i].StoreId = purchaseOrder.StoreId
resp.List[i].StoreName = purchaseOrder.StoreName
resp.List[i].ErpSupplierId = purchaseOrder.ErpSupplierId
resp.List[i].ErpSupplierName = purchaseOrder.ErpSupplierName
if resp.List[i].PurchaseType == "reject" {
resp.List[i].Amount = -resp.List[i].Amount
resp.List[i].RejectAmount = -resp.List[i].RejectAmount
resp.List[i].Difference = resp.List[i].Amount + resp.List[i].RejectAmount
}
}
// 统计总计数量和金额
var totalAmount float64
var totalCount uint32
for _, item := range resp.List {
totalAmount += item.Amount
totalCount += item.Count
}
resp.Amount = totalAmount
resp.Count = totalCount
if req.IsExport == 1 {
filePath, err := reportBySupplierExport(resp)
if err != nil {
return nil, err
}
resp = &ErpPurchaseReportBySupplierResp{}
resp.ExportUrl = filePath
}
return resp, nil
}
// 导出供应商采购汇总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) (*ErpPurchaseReportDetailResp, error) {
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 {
OrderSerialNumber string `json:"order_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.serial_number as order_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.implementation_price as 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) // 排除已终止的订单
if req.SerialNumber != "" {
qs = qs.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
}
if req.PurchaseType != "" {
qs = qs.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
}
if req.ErpCommodityName != "" {
qs = qs.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)
}
if req.ErpSupplierId != 0 {
qs = qs.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)
}
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)
}
if len(req.StoreList) > 0 {
var storeIDs []uint32
for _, store := range req.StoreList {
storeIDs = append(storeIDs, store.StoreID)
}
qs = qs.Where("erp_purchase_order.store_id IN (?)", storeIDs)
}
es := qs
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 {
if resp.List[i].PurchaseType == "reject" {
resp.List[i].Price = -resp.List[i].Price
resp.List[i].DifferencePrice = -resp.List[i].DifferencePrice
resp.List[i].RejectPrice = -resp.List[i].RejectPrice
}
}
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Errorf("GetReportDetail count err:", err)
return nil, err
}
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 calculatePrices(list []struct {
OrderSerialNumber string `json:"order_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
}