mh_goadmin_server/app/admin/models/purchase.go

5279 lines
187 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"
2024-03-27 10:01:38 +00:00
"math"
"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 // 已终止
ErpProcureOrder = "procure" // 采购入库订单
ErpRejectOrder = "reject" // 采购退货订单
2024-02-23 10:06:21 +00:00
ErpDemandStateWait = 1 // 待采购
ErpDemandStateFinish = 2 // 完成采购
)
// ErpPurchaseOrder 采购订单表
type ErpPurchaseOrder struct {
Model
2024-03-18 11:53:42 +00:00
SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号
PurchaseType string `json:"purchase_type"` // 类型:procure-采购 reject-退货
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
MakerTime *time.Time `json:"maker_time"` // 制单时间
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
MakerName string `json:"maker_name"` // 制单人名称
AuditTime *time.Time `json:"audit_time"` // 审核时间
AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id
AuditorName string `json:"auditor_name"` // 审核人名称
2024-03-27 10:01:38 +00:00
State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
2024-03-18 11:53:42 +00:00
RejectedSerialNumber string `json:"rejected_serial_number"` // 退货的采购订单单据编号
ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式/收款方式id
ErpCashierName string `json:"erp_cashier_name"` // 付款方式/收款方式名称
AccountHolder string `json:"account_holder"` // 收款人
OpeningBank string `json:"opening_bank"` // 开户行
BankAccount string `json:"bank_account"` // 银行卡号
DeliveryTime string `json:"delivery_time"` // 交货日期2024-02-23
DeliveryAddress string `json:"delivery_address"` // 交货地址
Remark string `json:"remark"` // 备注
Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"` //
InventoryId uint32 `json:"inventory_id" gorm:"-"` // 最近入库人id
InventoryName string `json:"inventory_name" gorm:"-"` // 最近入库人名称
}
// ErpPurchaseCommodity 采购订单商品表
type ErpPurchaseCommodity struct {
Model
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:"-"` // 执行金额
DefaultEmployeePrice float64 `json:"default_employee_price" gorm:"-"` // 默认员工成本价
2024-03-27 10:01:38 +00:00
EffectiveCount uint32 `json:"effective_count" gorm:"-"` // 有效数量(该商品实际库存详情处剩余有效数,不包含已出库的数量)
ErpCategoryID uint32 `json:"erp_category_id" gorm:"-"` // 商品分类id
ErpCategoryName string `json:"erp_category_name" gorm:"-"` // 商品分类名称
2024-02-23 10:06:21 +00:00
}
// 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-03-27 10:01:38 +00:00
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加)
2024-02-23 10:06:21 +00:00
IMEI string `json:"imei"` // 商品串码
Count uint32 `json:"count"` // 执行数量
ImplementationPrice float64 `json:"implementation_price"` // 执行单价
Amount float64 `json:"amount"` // 执行金额
EmployeePrice float64 `json:"employee_price"` // 员工成本价
2024-03-18 11:53:42 +00:00
InventoryId uint32 `json:"inventory_id"` // 最近入库人id
InventoryName string `json:"inventory_name"` // 最近入库人名称
2024-03-27 10:01:38 +00:00
ErpStockCommodityID uint32 `json:"erp_stock_commodity_id"` // 库存商品表主键id
}
// ErpPurchaseCreateReq 新建采购订单入参
type ErpPurchaseCreateReq struct {
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型procure-采购 reject-退货
PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号:出库必传
StoreId uint32 `json:"store_id"` // 门店id:入库必传
DeliveryAddress string `json:"delivery_address"` // 交货地址:入库必传
HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id:入库必传
ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式
AccountHolder string `json:"account_holder"` // 收款人:入库必传
OpeningBank string `json:"opening_bank"` // 开户行:入库必传
BankAccount string `json:"bank_account" ` // 银行卡号:入库必传
DeliveryTime string `json:"delivery_time" ` // 交货日期:入库必传
Remark string `json:"remark"` // 备注
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodity" binding:"required"` // 采购商品信息
}
// ErpPurchaseEditReq 编辑采购订单入参
type ErpPurchaseEditReq struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型procure-采购 reject-退货
PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号:出库必传
StoreId uint32 `json:"store_id"` // 门店id:入库必传
DeliveryAddress string `json:"delivery_address"` // 交货地址:入库必传
HandlerId uint32 `json:"handler_id" binding:"required"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id:入库必传
ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式
AccountHolder string `json:"account_holder"` // 收款人:入库必传
OpeningBank string `json:"opening_bank"` // 开户行:入库必传
BankAccount string `json:"bank_account" ` // 银行卡号:入库必传
DeliveryTime string `json:"delivery_time"` // 交货日期:入库必传
Remark string `json:"remark"` // 备注
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodity" binding:"required"` // 采购商品信息
}
// ErpPurchaseOrderListReq 查询采购订单列表入参
type ErpPurchaseOrderListReq struct {
2024-03-27 10:01:38 +00:00
SerialNumber string `json:"serial_number"` // 单据编号
PurchaseType string `json:"purchase_type"` // 采购类型procure-采购 reject-退货
StoreId uint32 `json:"store_id"` // 门店id
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
AuditFlag string `json:"audit_flag"` // 审核标记默认展示所有ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成/入库中
State []uint32 `json:"state"` // 状态1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
HandlerId uint32 `json:"handler_id"` // 经手人id
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// ErpPurchaseOrderListResp 查询采购订单列表出参
type ErpPurchaseOrderListResp struct {
List []ErpPurchaseOrder `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// ErpPurchaseDetailReq 查询采购订单详情入参
type ErpPurchaseDetailReq struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
}
2024-03-18 11:53:42 +00:00
// ErpPurchaseInventoryReq 入库(退货)入参
type ErpPurchaseInventoryReq struct {
2024-03-18 11:53:42 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
2024-03-27 10:01:38 +00:00
InventoryId uint32 `json:"inventory_id"` // 最近入库人id
InventoryName string `json:"inventory_name"` // 最近入库人名称
2024-03-18 11:53:42 +00:00
Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息
}
// ErpPurchaseExecuteReq 执行(入库/退货)入参
type ErpPurchaseExecuteReq 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"` // 备注
}
// ErpPurchaseDeleteReq 删除采购单入参
type ErpPurchaseDeleteReq struct {
SerialNumber string `json:"serial_number" 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"` // 员工成本价
}
2024-03-27 10:01:38 +00:00
// 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
FinishTime *time.Time `json:"finish_time"` // 完成采购时间
2024-03-27 10:01:38 +00:00
//PurchaserId uint32 `json:"purchaser_id"` // 采购人id
//Remark string `json:"remark"` // 备注
}
// ErpPurchaseDemandRemark 采购需求备注表
type ErpPurchaseDemandRemark struct {
Model
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
State uint32 `json:"state"` // 1-待采购 2-已采购
MakerId uint32 `json:"maker_id"` // 制单人id
FinishTime *time.Time `json:"finish_time"` // 完成采购时间
Remark string `json:"remark"` // 备注
2024-02-23 10:06:21 +00:00
}
// 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 {
2024-03-18 11:53:42 +00:00
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
2024-03-27 10:01:38 +00:00
State uint32 `json:"state"` // 2-待入库 3-待退货 4-已完成 5-已终止
2024-03-18 11:53:42 +00:00
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"` // 已执行金额
2024-03-27 10:01:38 +00:00
Count int32 `json:"count"` // 已执行数量
ExportUrl string `json:"export_url"` // 导出excel路径
List []ReportByOrderData `json:"list"` // 采购报表信息
}
type ReportByOrderData struct {
CommonData
State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
Remark string `json:"remark"` // 备注
Amount float64 `json:"amount"` // 已执行金额
Price float64 `json:"price"` // 执行单价
2024-03-27 10:01:38 +00:00
Count int32 `json:"count"` // 已执行数量
CommodityData []ErpPurchaseCommodityData `json:"commodity_data"` // 商品信息
}
type CommodityData struct {
ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
}
type CommonData struct {
2024-03-18 11:53:42 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
SerialNumber string `json:"serial_number"` // 单据编号
PurchaseType string `json:"purchase_type"` // 单据类型:procure-采购 reject-退货
StoreId uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
HandlerId uint32 `json:"handler_id"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
MakerTime *time.Time `json:"maker_time"` // 制单时间
MakerId uint32 `json:"maker_id"` // 制单人id
MakerName string `json:"maker_name"` // 制单人名称
AuditTime *time.Time `json:"audit_time"` // 审核时间
AuditorId uint32 `json:"auditor_id"` // 审核人id
AuditorName string `json:"auditor_name"` // 审核人名称
}
// ErpPurchaseCommodityData 采购订单商品信息
type ErpPurchaseCommodityData struct {
CommodityData
Amount float64 `json:"amount"` // 已执行金额
Price float64 `json:"price"` // 已执行单价
2024-03-27 10:01:38 +00:00
Count int32 `json:"count"` // 已执行数量
}
// ErpPurchaseReportByCommodityReq 采购报表(按商品)入参
type ErpPurchaseReportByCommodityReq struct {
2024-03-18 11:53:42 +00:00
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
2024-03-27 10:01:38 +00:00
State uint32 `json:"state"` // 2-待入库 3-待退货 4-已完成 5-已终止
2024-03-18 11:53:42 +00:00
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
2024-03-27 10:01:38 +00:00
PlanCount int32 `json:"plan_count"` // 计划采购数量
PlanPrice float64 `json:"plan_price"` // 计划采购单价
PlanAmount float64 `json:"plan_amount"` // 计划采购金额
Amount float64 `json:"amount"` // 已执行金额
Price float64 `json:"price"` // 已执行单价
2024-03-27 10:01:38 +00:00
Count int32 `json:"count"` // 已执行数量
NonExecutionAmount float64 `json:"non_execution_amount"` // 未执行金额
2024-03-27 10:01:38 +00:00
NonExecutionCount int32 `json:"non_execution_count"` // 未执行数量
}
// ErpPurchaseReportBySupplierReq 供应商采购汇总入参
type ErpPurchaseReportBySupplierReq struct {
PurchaseType string `json:"purchase_type"` // 采购类型procure-采购 reject-退货
ErpCommodityName []string `json:"erp_commodity_name"` // 商品名称
ErpCategoryID []uint32 `json:"erp_category_id"` // 商品分类id
ErpSupplierId []uint32 `json:"erp_supplier_id"` // 供应商id
StartTime string `json:"start_time"` // 入/出库,开始时间
EndTime string `json:"end_time"` // 入/出库,结束时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
StoreList []uint32 `json:"store_list"` // 门店复选
}
// ErpPurchaseReportBySupplierResp 供应商采购汇总出参
type ErpPurchaseReportBySupplierResp struct {
2024-03-27 10:01:38 +00:00
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 []PurchaseReportData `json:"list"` // 供应商采购汇总信息
}
type PurchaseReportData struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
StoreId uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
ErpCategoryName string `json:"erp_category_name"` // 商品分类名称
Count uint32 `json:"count"` // 采购数量
Amount float64 `json:"amount"` // 采购金额
RejectAmount float64 `json:"reject_amount"` // 退货金额
Difference float64 `json:"difference"` // 差额
}
// ErpPurchaseReportDetailReq 采购明细入参
type ErpPurchaseReportDetailReq struct {
2024-03-18 11:53:42 +00:00
SerialNumber string `json:"serial_number"` // 单据编号
PurchaseType string `json:"purchase_type"` // 采购类型procure-采购 reject-退货
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
StartTime string `json:"startTime"` // 入/出库,开始时间
EndTime string `json:"endTime"` // 入/出库,结束时间
IsExport uint32 `json:"is_export"` // 1-导出
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
StoreId []uint32 `json:"store_id"` // 门店id
}
// ErpPurchaseReportDetailResp 采购明细出参
type ErpPurchaseReportDetailResp struct {
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
Price float64 `json:"price"` // 采购价
EmployeePrice float64 `json:"employee_price"` // 员工成本价
RejectPrice float64 `json:"reject_price"` // 退货价
DifferencePrice float64 `json:"difference_price"` // 差价
ExportUrl string `json:"export_url"` // 导出excel路径
List []struct {
2024-03-18 11:53:42 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
OrderSerialNumber string `json:"order_serial_number"` // 单据编号
2024-03-27 10:01:38 +00:00
SerialNumber string `json:"serial_number"` // 采购入库编号
2024-03-18 11:53:42 +00:00
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
2024-03-27 10:01:38 +00:00
if m.AuditFlag == "ON" { //2-待入库 4-已完成 5-已终止 6-入库中
stateList = []int{2, 4, 5, 6}
qs = qs.Where("state IN ?", stateList)
2024-03-18 11:53:42 +00:00
qs = qs.Where("purchase_type=?", ErpProcureOrder)
}
if m.SerialNumber != "" {
qs = qs.Where("serial_number=?", m.SerialNumber)
} else {
if m.PurchaseType != "" {
qs = qs.Where("purchase_type=?", m.PurchaseType)
}
if m.StoreId != 0 {
qs = qs.Where("store_id=?", m.StoreId)
}
if m.ErpSupplierId != 0 {
qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId)
}
2024-03-27 10:01:38 +00:00
if len(m.State) > 0 {
qs = qs.Where("state IN (?)", m.State)
}
if m.AuditTimeStart != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
qs = qs.Where("audit_time > ?", parse)
}
if m.AuditTimeEnd != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
//parse = parse.AddDate(0, 0, 1)
qs = qs.Where("audit_time < ?", parse)
}
if m.HandlerId != 0 {
qs = qs.Where("handler_id=?", m.HandlerId)
}
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
resp.Total = int(count)
var orders []ErpPurchaseOrder
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
2024-03-18 11:53:42 +00:00
// 校验时间如果为01-01-01 08:05则赋值为空
for i, v := range orders {
if v.MakerTime != nil && v.MakerTime.IsZero() {
orders[i].MakerTime = nil
}
if v.AuditTime != nil && v.AuditTime.IsZero() {
orders[i].AuditTime = nil
}
}
resp.List = orders
return resp, nil
}
// NewErpPurchaseSn 生成采购订单号
func NewErpPurchaseSn() string {
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create sn err")
return ""
}
random := rand.Intn(9000) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE serial_number='%s'", sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
}
max++
}
}
2024-03-27 10:01:38 +00:00
func ErpPurchaseCommodityListPerfectInfo(serialNumber string, purchaseCommodities []ErpPurchaseCommodity) error {
commodityIds := make([]uint32, 0, len(purchaseCommodities))
for i, _ := range purchaseCommodities {
commodityIds = append(commodityIds, purchaseCommodities[i].ID)
}
commodityMap, err := GetErpCommodityMap(commodityIds)
if err != nil {
logger.Error("purchase commodities err:", logger.Field("err", err))
return err
}
for i, _ := range purchaseCommodities {
2024-03-27 10:01:38 +00:00
if serialNumber != "" { // 采购退货单才需判断
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
nCount, err := GetCommodityStockByPurchaseId(serialNumber, purchaseCommodities[i].ErpCommodityId)
if err != nil {
logger.Error("ErpPurchaseCommodityListPerfectInfo GetCommodityStockByPurchaseId err:", logger.Field("err", err))
return err
}
// 如果库存数量不够则报错
if nCount < purchaseCommodities[i].RejectedCount {
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", purchaseCommodities[i].ErpCommodityName)
}
}
v, ok := commodityMap[purchaseCommodities[i].ErpCommodityId]
if ok {
purchaseCommodities[i].CommoditySerialNumber = v.SerialNumber
purchaseCommodities[i].IMEIType = v.IMEIType
//purchaseCommodities[i].IMEI = v.IMEI
purchaseCommodities[i].ErpCommodityName = v.Name
if purchaseCommodities[i].Count != 0 {
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 ""
}
}
// CheckCreateErpPurchaseOrderParam 新增采购订单-检查参数
func CheckCreateErpPurchaseOrderParam(req *ErpPurchaseCreateReq) error {
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
if req.StoreId == 0 {
return errors.New("操作失败:门店id为空")
}
if req.DeliveryAddress == "" {
return errors.New("操作失败:交货地址为空")
}
if req.ErpSupplierId == 0 {
return errors.New("操作失败:供应商id为空")
}
if req.AccountHolder == "" {
return errors.New("操作失败:收款人为空")
}
if req.OpeningBank == "" {
return errors.New("操作失败:开户行为空")
}
if req.BankAccount == "" {
return errors.New("操作失败:银行卡号为空")
}
if req.DeliveryTime == "" {
return errors.New("操作失败:交货日期为空")
}
} else if req.PurchaseType == ErpRejectOrder { // 退货单
if req.PurchaseOrderSn == "" {
return errors.New("操作失败:采购退货单据编号为空")
}
} else {
return errors.New("操作失败:采购类型有误")
}
return nil
}
// CheckEditErpPurchaseOrderParam 编辑采购订单-检查参数
func CheckEditErpPurchaseOrderParam(req *ErpPurchaseEditReq) error {
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
if req.StoreId == 0 {
return errors.New("操作失败:门店id为空")
}
if req.DeliveryAddress == "" {
return errors.New("操作失败:交货地址为空")
}
if req.ErpSupplierId == 0 {
return errors.New("操作失败:供应商id为空")
}
if req.AccountHolder == "" {
return errors.New("操作失败:收款人为空")
}
if req.OpeningBank == "" {
return errors.New("操作失败:开户行为空")
}
if req.BankAccount == "" {
return errors.New("操作失败:银行卡号为空")
}
if req.DeliveryTime == "" {
return errors.New("操作失败:交货日期为空")
}
} else if req.PurchaseType == ErpRejectOrder { // 退货单
if req.PurchaseOrderSn == "" {
return errors.New("操作失败:采购退货单据编号为空")
}
} else {
return errors.New("操作失败:采购类型有误")
}
return nil
}
// CreateErpPurchaseOrder 新增采购订单
func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
var err error
nowTime := time.Now()
purchaseOrder := &ErpPurchaseOrder{}
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgr" + NewErpPurchaseSn(),
PurchaseType: req.PurchaseType,
StoreId: req.StoreId,
ErpSupplierId: req.ErpSupplierId,
2024-03-18 11:53:42 +00:00
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{
2024-03-18 11:53:42 +00:00
SerialNumber: "cgt" + NewErpPurchaseSn(),
PurchaseType: req.PurchaseType,
StoreId: erpPurchaseOrder.StoreId,
ErpSupplierId: erpPurchaseOrder.ErpSupplierId,
MakerTime: &nowTime,
HandlerId: req.HandlerId,
HandlerName: req.HandlerName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpPurchaseOrderUnAudit, // 1-待审核
ErpCashierId: req.ErpCashierId,
Remark: req.Remark,
RejectedSerialNumber: req.PurchaseOrderSn,
}
err = purchaseOrder.IdInit()
} else {
logger.Errorf("purchase_type err:", req.PurchaseType)
return nil, errors.New("操作失败:采购类型有误")
}
if err != nil {
logger.Error("info err:", logger.Field("err", err))
return nil, err
}
2024-03-27 10:01:38 +00:00
err = ErpPurchaseCommodityListPerfectInfo(req.PurchaseOrderSn, req.ErpPurchaseCommodities)
if err != nil {
logger.Error("info err:", logger.Field("err", err))
return nil, err
}
begin := orm.Eloquent.Begin()
err = begin.Create(purchaseOrder).Error
if err != nil {
begin.Rollback()
logger.Error("create purchase order err:", logger.Field("err", err))
return nil, err
}
for i, _ := range req.ErpPurchaseCommodities {
req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = purchaseOrder.ID
req.ErpPurchaseCommodities[i].InventoryCount = 0 // todo 数量待核实
err = begin.Create(&req.ErpPurchaseCommodities[i]).Error
if err != nil {
begin.Rollback()
logger.Error("create purchase commodity err:", logger.Field("err", err))
return nil, err
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit purchase commodity err:", logger.Field("err", err))
return nil, err
}
return purchaseOrder, nil
}
// EditErpPurchaseOrder 编辑采购订单
func EditErpPurchaseOrder(req *ErpPurchaseEditReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
// 查询订单信息
var purchaseOrder ErpPurchaseOrder
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
if err != nil {
logger.Error("purchase order err:", logger.Field("err", err))
return nil, err
}
if purchaseOrder.State != ErpPurchaseOrderUnAudit { // 只有待审核的订单才能编辑
return nil, errors.New("订单不是待审核状态")
}
if req.StoreId == 0 && req.PurchaseType == ErpProcureOrder {
return nil, errors.New("操作失败:门店id为空")
}
begin := orm.Eloquent.Begin()
// 1-更新采购订单信息
purchaseOrder.StoreId = req.StoreId
purchaseOrder.ErpSupplierId = req.ErpSupplierId
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()
2024-03-27 10:01:38 +00:00
var inventoryList []ErpPurchaseInventory
for i, v := range req.Inventories {
2024-02-23 10:06:21 +00:00
v.SerialNumber = GetPurchaseInventorySn()
2024-03-27 10:01:38 +00:00
req.Inventories[i].SerialNumber = v.SerialNumber
// 更新采购商品表的执行数量
2024-02-23 10:06:21 +00:00
// todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息可能采购价不同需要区分入库的是哪一条(已修改)
err = begin.Model(&ErpPurchaseCommodity{}).
2024-03-27 10:01:38 +00:00
Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
2024-02-23 10:06:21 +00:00
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
}
2024-03-18 11:53:42 +00:00
v.PurchaseType = req.PurchaseType // 记录采购类型
v.InventoryId = req.InventoryId // 记录入库人id
v.InventoryName = req.InventoryName // 记录入库人姓名
2024-03-27 10:01:38 +00:00
nCount := v.Count
nAmount := v.Amount
for i := 0; i < int(nCount); i++ { // 采购入库记录表都是单笔数据
v.ID = 0
v.Count = 1
v.Amount = nAmount / float64(nCount) // 前端传的执行金额是总金额
// 新建采购入库记录
err = begin.Create(&v).Error
if err != nil {
begin.Rollback()
logger.Error("create erp inventory commodity err:", logger.Field("err", err))
return err
}
inventoryList = append(inventoryList, v)
}
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 { //采购入库订单
2024-03-27 10:01:38 +00:00
err = InventoryErpPurchaseUpdateStock(begin, inventoryList, purchaseOrder)
2024-02-23 10:06:21 +00:00
} else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单
2024-03-27 10:01:38 +00:00
err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder)
2024-02-23 10:06:21 +00:00
} 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
}
2024-03-27 10:01:38 +00:00
// 查询采购订单商品表入库或退库情况,如果都已经完成了,则更新采购订单的状态为:已完成
_ = CheckAndUpdatePurchaseOrderState(req.ErpPurchaseOrderId)
return nil
}
// CheckAndUpdatePurchaseOrderState
// 查询采购订单商品表入库或退库情况,如果都已经完成了,则更新采购订单的状态为:已完成
func CheckAndUpdatePurchaseOrderState(orderId uint32) error {
var order ErpPurchaseOrder
if err := orm.Eloquent.Where("id = ?", orderId).First(&order).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("purchase order with ID %d not found", orderId)
}
return err
}
if order.State == ErpPurchaseOrderFinished {
return nil // Order is already marked as completed
}
var commodities []ErpPurchaseCommodity
if err := orm.Eloquent.Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error; err != nil {
return err
}
for _, commodity := range commodities {
if (order.PurchaseType == "procure" && commodity.Count != uint32(commodity.InventoryCount)) ||
(order.PurchaseType == "reject" && commodity.RejectedCount != uint32(commodity.InventoryCount)) {
return nil // Order not completed, exit early
}
}
// If all commodities are checked and everything is in order, update the state to completed
if err := orm.Eloquent.Model(&order).Update("state", ErpPurchaseOrderFinished).Update("audit_time", time.Now()).Error; err != nil {
return err
}
return nil
}
2024-03-18 11:53:42 +00:00
// GetInventoryIdAndName 获取采购单最近入库人信息
func GetInventoryIdAndName(orderId uint32) (uint32, string, error) {
var purchaseInventory ErpPurchaseInventory
err := orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", orderId).
2024-03-27 10:01:38 +00:00
Order("created_at DESC").First(&purchaseInventory).Error
2024-03-18 11:53:42 +00:00
if err != nil {
logger.Error("purchase order err:", logger.Field("err", err))
return 0, "", err
}
return purchaseInventory.InventoryId, purchaseInventory.InventoryName, nil
}
2024-02-23 10:06:21 +00:00
// InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息
2024-03-27 10:01:38 +00:00
func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
2024-02-23 10:06:21 +00:00
// 遍历采购入库商品信息
var stockList []ErpStockCommodity
2024-03-27 10:01:38 +00:00
for _, v := range list {
2024-02-23 10:06:21 +00:00
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(
2024-03-27 10:01:38 +00:00
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d",
2024-02-23 10:06:21 +00:00
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: InStock,
StorageType: PurchaseInventory, // 采购入库
2024-02-23 10:06:21 +00:00
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,
2024-03-18 11:53:42 +00:00
OriginalSn: purchaseOrder.SerialNumber,
2024-03-27 10:01:38 +00:00
StockSn: v.SerialNumber,
2024-02-23 10:06:21 +00:00
}
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 采购退货更新库存信息
2024-03-27 10:01:38 +00:00
func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
usedStockCommodityIdList := make(map[uint32]bool)
for i, _ := range list {
if list[i].IMEIType == 2 { // 串码商品
if list[i].IMEI == "" {
2024-02-23 10:06:21 +00:00
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
2024-03-27 10:01:38 +00:00
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI).
2024-02-23 10:06:21 +00:00
Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("Inventory RejectStock query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
2024-03-27 10:01:38 +00:00
return fmt.Errorf("商品[%s]已经销售,不能退货", stockCommodityInfo.ErpCommodityName)
2024-02-23 10:06:21 +00:00
} else if stockCommodityInfo.State == OnSale {
return fmt.Errorf("商品[%s]在销售锁定中,不能退货", stockCommodityInfo.ErpCommodityName)
}
2024-03-27 10:01:38 +00:00
err = gdb.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI).
Updates(&map[string]interface{}{
"state": PurchaseReturn,
"stock_sn": list[i].SerialNumber,
}).Error // 状态更新为采购退货
2024-02-23 10:06:21 +00:00
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 = ?",
2024-03-27 10:01:38 +00:00
purchaseOrder.StoreId, list[i].ErpCommodityId).
2024-02-23 10:06:21 +00:00
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
}
2024-03-27 10:01:38 +00:00
} else {
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, list[i].ErpCommodityId)
if err != nil {
logger.Error("InventoryErpPurchaseUpdateRejectStock GetCommodityStockByPurchaseId err:", logger.Field("err", err))
return err
}
// 如果库存数量不够则报错
if nCount < list[i].Count {
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", list[i].ErpCommodityName)
}
2024-02-23 10:06:21 +00:00
var stockCommodity []ErpStockCommodity
// 通过门店id商品id查找状态为1-在库的非串码商品
2024-03-27 10:01:38 +00:00
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
"and state = ? and imei_type = ?", list[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1).
2024-02-23 10:06:21 +00:00
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")
}
2024-03-27 10:01:38 +00:00
var currentID uint32
// 找一个可用的库存ID
for _, item := range stockCommodity {
_, ok := usedStockCommodityIdList[item.ID]
if !ok {
usedStockCommodityIdList[item.ID] = true
currentID = item.ID
break
} else {
continue
}
}
if currentID == 0 {
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", list[i].ErpCommodityName)
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", currentID).Updates(&map[string]interface{}{
"state": PurchaseReturn,
"stock_sn": list[i].SerialNumber,
}).Error // 状态更新为采购退货
2024-02-23 10:06:21 +00:00
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 = ?",
2024-03-27 10:01:38 +00:00
purchaseOrder.StoreId, list[i].ErpCommodityId).
2024-02-23 10:06:21 +00:00
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 i, inventory := range req.Inventories {
if inventory.ErpCommodityId == 0 {
return fmt.Errorf("商品Id传参错误不能为0")
}
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)
}
}
// 备注:员工成本价在"库存管理-采购单入库"里面的入库操作前端是隐藏不可修改的会默认传0
if inventory.EmployeePrice != 0 && inventory.EmployeePrice < inventory.ImplementationPrice {
return fmt.Errorf("数据错误,员工成本价不能低于采购执行单价")
}
2024-03-27 10:01:38 +00:00
erpCommodity, err := GetCommodity(inventory.ErpCommodityId)
if err != nil {
logger.Error("checkPurchaseInventory GetCommodity err:", logger.Field("err", err))
return fmt.Errorf("查询员工成本价报错")
}
req.Inventories[i].ErpCategoryID = erpCommodity.ErpCategoryId // 分类id入库的时候前端没传后端补充
req.Inventories[i].ErpCategoryName = erpCommodity.ErpCategoryName // 分类名称,入库的时候前端没传,后端补充
2024-03-27 10:01:38 +00:00
if inventory.EmployeePrice == 0 { // 没有传入员工成本价,则默认按照商品资料设置的员工成本价加价金额
req.Inventories[i].EmployeePrice = inventory.ImplementationPrice + float64(erpCommodity.StaffCostPrice)
}
}
// 入库的商品信息有误,不在之前的商品列表中
for commodityID := range countMap {
found := false
for _, commodity := range commodities {
if commodity.ErpCommodityId == commodityID {
found = true
break
}
}
if !found {
return fmt.Errorf("商品编号[%d]不属于该采购订单", commodityID)
}
}
// 本次入库的数量超出该商品未入库数量
for _, commodity := range commodities {
if inventoryCount, ok := countMap[commodity.ErpCommodityId]; ok {
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)
}
2024-03-27 10:01:38 +00:00
// 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
var purchaseOrder ErpPurchaseOrder
err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
if err != nil {
logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err))
return err
}
nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, commodity.ErpCommodityId)
if err != nil {
logger.Error("checkPurchaseInventory GetCommodityStockByPurchaseId err:", logger.Field("err", err))
return err
}
// 如果库存数量不够则报错
if nCount < commodity.RejectedCount {
return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", commodity.ErpCommodityName)
}
}
}
}
return nil
}
// ExecuteErpPurchase 执行(入库/退货)
2024-03-18 11:53:42 +00:00
func ExecuteErpPurchase(req *ErpPurchaseExecuteReq) (*ErpPurchaseExecuteResp, error) {
reqParam := &ErpPurchaseInventoryReq{
ErpPurchaseOrderId: req.ErpPurchaseOrderId,
PurchaseType: req.PurchaseType,
Inventories: req.Inventories,
}
err := checkPurchaseInventory(reqParam)
if err != nil {
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
return nil, err
}
resp := &ErpPurchaseExecuteResp{
List: make([]ExecuteData, 0),
}
for _, inventory := range req.Inventories {
2024-03-27 10:01:38 +00:00
// 获取商品信息
commodityInfo, err := GetCommodity(inventory.ErpCommodityId)
if err != nil {
return nil, err
}
if commodityInfo.IMEIType == 2 || commodityInfo.IMEIType == 3 {
2024-02-23 10:06:21 +00:00
// 如果是串码商品,根据 Count 拆分成对应数量的数据
for i := 0; i < int(inventory.Count); i++ {
2024-03-27 10:01:38 +00:00
imei := "" // 默认退货单执行时不需要串码
if inventory.PurchaseType == ErpProcureOrder && commodityInfo.IMEIType == 2 { // 采购单
2024-02-23 10:06:21 +00:00
// 调用函数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,
})
}
2024-03-27 10:01:38 +00:00
} else if commodityInfo.IMEIType == 1 {
// 如果是非串码商品只需拆分为1条数据
resp.List = append(resp.List, ExecuteData{
ErpPurchaseOrderId: inventory.ErpPurchaseOrderId,
ErpCommodityId: inventory.ErpCommodityId,
ErpCommodityName: inventory.ErpCommodityName,
CommoditySerialNumber: inventory.CommoditySerialNumber,
IMEIType: inventory.IMEIType,
IMEI: "",
Count: inventory.Count,
ImplementationPrice: inventory.ImplementationPrice,
EmployeePrice: inventory.EmployeePrice,
})
}
}
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
2024-03-27 10:01:38 +00:00
var demandRemark ErpPurchaseDemandRemark
2024-02-23 10:06:21 +00:00
var demandList []ErpPurchaseDemand
2024-03-27 10:01:38 +00:00
// 采购需求信息
2024-02-23 10:06:21 +00:00
demandInfo.ErpCommodityId = req.ErpCommodityID
demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber
demandInfo.ErpCommodityName = req.ErpCommodityName
demandInfo.State = ErpDemandStateWait // 待采购
for _, v := range req.List {
demandInfo.StoreId = v.StoreID
demandInfo.StoreName = v.StoreName
demandInfo.Count = v.NeedCount
demandInfo.MakerId = uint32(sysUser.UserId)
demandList = append(demandList, demandInfo)
}
2024-03-27 10:01:38 +00:00
// 采购需求备注信息
demandRemark.ErpCommodityId = req.ErpCommodityID
demandRemark.State = ErpDemandStateWait // 待采购
demandRemark.MakerId = uint32(sysUser.UserId)
demandRemark.Remark = req.Remark
2024-02-23 10:06:21 +00:00
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
}
}
}
2024-03-27 10:01:38 +00:00
// 更新备注,先查询有无记录,有则更新,没有则插入新记录
var demandRemarkInfo ErpPurchaseDemandRemark
err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1",
req.ErpCommodityID).Find(&demandRemarkInfo).Error
2024-03-18 11:53:42 +00:00
if err != nil {
2024-03-27 10:01:38 +00:00
logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err))
2024-03-18 11:53:42 +00:00
return err
}
2024-03-27 10:01:38 +00:00
if demandRemarkInfo.ErpCommodityId != 0 { // 有记录
if demandRemarkInfo.Remark != req.Remark { // 备注有变化才更新
err := begin.Model(&ErpPurchaseDemandRemark{}).Where("erp_commodity_id = ? and state = 1",
req.ErpCommodityID).Updates(demandRemark).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_purchase_demand_remark err:", logger.Field("err", err))
return err
}
}
} else { // 无记录,新建
err = begin.Create(&demandRemark).Error
if err != nil {
logger.Error("create erp_purchase_demand_remark err:", logger.Field("err", err))
return err
}
}
2024-03-18 11:53:42 +00:00
err = begin.Commit().Error
2024-02-23 10:06:21 +00:00
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)
}
// 批量更新状态
2024-03-27 10:01:38 +00:00
err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID).
Updates(map[string]interface{}{
"state": ErpDemandStateFinish,
"finish_time": time.Now(),
"purchaser_id": sysUser.UserId,
}).Error
if err != nil {
logger.Error("update err:", logger.Field("err", err))
return err
}
err = orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID).
2024-02-23 10:06:21 +00:00
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 {
2024-03-27 10:01:38 +00:00
categoryInfo, err := GetErpCategory(req.ErpCategoryId)
if err != nil {
return nil, err
}
qs = qs.Where("serial_number like ?", categoryInfo.Number+"%")
2024-02-23 10:06:21 +00:00
}
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 {
2024-03-27 10:01:38 +00:00
//qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
categoryInfo, err := GetErpCategory(req.ErpCategoryId)
if err != nil {
return nil, err
}
qs = qs.Where("serial_number like ?", categoryInfo.Number+"%")
}
if req.ErpCommoditySerialNumber != "" {
qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber)
}
if req.ErpCommodityName != "" {
qs = qs.Where("name=?", req.ErpCommodityName)
}
var count int64
if err := qs.Count(&count).Error; err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
var commodities []ErpCommodity
if req.IsExport == 1 { // 导出excel
err := qs.Order("id DESC").Find(&commodities).Error
if err != nil && err != RecordNotFound {
return resp, err
}
} else {
err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
if err != nil && err != RecordNotFound {
return resp, err
}
}
// 匹配商品id有则继续查询返回数据没有则不返回
var matchedCommodities []ErpCommodity
for _, c := range commodities {
for _, uniqueID := range uniqueCommodityIds {
if c.ID == uniqueID {
matchedCommodities = append(matchedCommodities, c)
break // 找到匹配的商品后跳出内层循环,继续下一个商品
}
}
}
if len(matchedCommodities) == 0 {
resp.List = nil
} else {
// 批量查询门店信息
stores, err := GetOnlineStores()
if err != nil {
return nil, err
}
// 并行查询需求数据
var wg sync.WaitGroup
demandDataList := make([]DemandData, len(matchedCommodities))
for i, v := range matchedCommodities {
wg.Add(1)
go func(index int, commodity ErpCommodity) {
defer wg.Done()
demandData, err := convertToDemandData(commodity, stores)
if err != nil {
// Handle error
return
}
demandDataList[index] = demandData
}(i, v)
}
wg.Wait()
if req.IsExport == 1 { // 导出excel
if len(demandDataList) == 0 {
return nil, errors.New("未查询到数据")
}
resp.ExportUrl, err = demandDataExport(demandDataList)
if err != nil {
return nil, err
}
} else {
resp.List = demandDataList
resp.Total = int64(len(matchedCommodities))
}
}
2024-02-23 10:06:21 +00:00
return resp, nil
}
// convertToDemandData 将商品转换为采购需求数据
func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
2024-03-27 10:01:38 +00:00
// 查询采购商品的备注信息
var demandRemarkInfo ErpPurchaseDemandRemark
err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1",
commodity.ID).Find(&demandRemarkInfo).Error
if err != nil {
logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err))
return DemandData{}, err
}
2024-02-23 10:06:21 +00:00
demandData := DemandData{
ErpCommodityID: commodity.ID,
ErpCommoditySerialNumber: commodity.SerialNumber,
ErpCommodityName: commodity.Name,
ErpCategoryID: commodity.ErpCategoryId,
ErpCategoryName: commodity.ErpCategoryName,
RetailPrice: commodity.RetailPrice,
2024-03-27 10:01:38 +00:00
Remark: demandRemarkInfo.Remark,
2024-02-23 10:06:21 +00:00
}
// 查询采购需求单
demands, err := GetCommodityPurchaseDemands(commodity.ID, stores)
if err != nil {
// Handle error
return DemandData{}, err
}
2024-03-27 10:01:38 +00:00
//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 {
2024-03-27 10:01:38 +00:00
ErpCommodityID uint32
Price float64
2024-02-23 10:06:21 +00:00
}
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").
2024-03-27 10:01:38 +00:00
//Group("erp_commodity_id").
2024-02-23 10:06:21 +00:00
Order("created_at DESC").
2024-03-27 10:01:38 +00:00
First(&prices).Error
2024-02-23 10:06:21 +00:00
if err != nil {
return nil, err
}
// 构建结果
result := make(map[uint32]float64)
for _, p := range prices {
2024-03-27 10:01:38 +00:00
result[p.ErpCommodityID] = p.Price
2024-02-23 10:06:21 +00:00
}
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
}
2024-03-27 10:01:38 +00:00
// GetCommodityStockByPurchaseId 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量
func GetCommodityStockByPurchaseId(serialNumber string, orderId uint32) (uint32, error) {
var count int64
err := orm.Eloquent.Table("erp_stock_commodity").Where("original_sn = ? and erp_commodity_id = ? and state = ?",
serialNumber, orderId, InStock).Count(&count).Error
if err != nil {
return 0, err
}
return uint32(count), nil
}
2024-02-23 10:06:21 +00:00
// GetCommodityLastMonthSales 批量查询商品的上月销售数量
func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) {
// 获取上个月的时间范围
firstDay, lastDay := GetLastMonthRange()
// 并行查询上月销售数量
var wg sync.WaitGroup
wg.Add(len(stores))
var totalSales uint32
var mu sync.Mutex // 用于保护 totalSales 的并发访问
for _, store := range stores {
go func(storeID uint32) {
defer wg.Done()
// 查询上月销售数量
var sales uint32
err := orm.Eloquent.Table("erp_order_commodity").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
"AND erp_order_commodity.created_at BETWEEN ? AND ?",
HavePaid, commodityID, storeID, firstDay, lastDay).
Select("SUM(erp_order_commodity.count) AS sales").
Scan(&sales).Error
if err != nil {
// Handle error
return
}
// 保护 totalSales 的并发访问
mu.Lock()
defer mu.Unlock()
totalSales += sales
}(store.ID)
}
wg.Wait()
return totalSales, nil
}
// GetLastMonthRange 获取上个月的时间范围
func GetLastMonthRange() (time.Time, time.Time) {
now := time.Now()
year, month, _ := now.Date()
firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
lastDay := firstDay.AddDate(0, 1, -1)
return firstDay, lastDay
}
// GetOnlineStores 查询所有在线门店信息
func GetOnlineStores() ([]Store, error) {
var stores []Store
err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
if err != nil {
return nil, err
}
return stores, nil
}
type Result struct {
TotalCount uint32 `gorm:"column:total_count"`
AvgImplementationPrice float64 `gorm:"column:avg_implementation_price"`
TotalAmount float64 `gorm:"column:total_amount"`
AvgEmployeePrice float64 `gorm:"column:avg_employee_price"`
}
// GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价
func GetTotalsAndAveragesByCommodityID(commodityID, orderID uint32) (Result, error) {
2024-02-23 10:06:21 +00:00
var result Result
err := orm.Eloquent.Table("erp_purchase_inventory").
Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+
"SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price").
Where("erp_commodity_id = ? and erp_purchase_order_id = ?", commodityID, orderID).
2024-02-23 10:06:21 +00:00
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: page + 1,
PageSize: req.PageSize,
}
qs := orm.Eloquent.Table("erp_purchase_inventory")
if req.ErpCommodityName != "" {
qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
}
if req.ErpCategoryID != 0 {
qs = qs.Where("erp_category_id=?", req.ErpCategoryID)
}
2024-03-18 11:53:42 +00:00
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
2024-03-27 10:01:38 +00:00
var nTotalCount int32
// 查询采购订单信息
for _, v := range commodityMap {
var purchaseOrder ErpPurchaseOrder
var commodityList []ErpPurchaseCommodityData
2024-03-18 11:53:42 +00:00
query := orm.Eloquent.Table("erp_purchase_order")
if len(req.ErpSupplierId) > 0 { // 供应商复选
2024-03-27 10:01:38 +00:00
query = query.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId)
2024-03-18 11:53:42 +00:00
}
if len(req.StoreId) > 0 { // 门店复选
2024-03-27 10:01:38 +00:00
query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
2024-03-18 11:53:42 +00:00
}
err = query.Where("id = ?", v).Find(&purchaseOrder).Error
if err != nil {
return nil, err
}
var reportByOrderData ReportByOrderData
2024-03-18 11:53:42 +00:00
reportByOrderData.ErpPurchaseOrderId = purchaseOrder.ID
reportByOrderData.SerialNumber = purchaseOrder.SerialNumber
reportByOrderData.PurchaseType = purchaseOrder.PurchaseType
reportByOrderData.StoreId = purchaseOrder.StoreId
reportByOrderData.StoreName = purchaseOrder.StoreName
reportByOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
reportByOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
reportByOrderData.HandlerId = purchaseOrder.HandlerId
reportByOrderData.HandlerName = purchaseOrder.HandlerName
reportByOrderData.MakerTime = purchaseOrder.MakerTime
reportByOrderData.MakerId = purchaseOrder.MakerId
reportByOrderData.MakerName = purchaseOrder.MakerName
reportByOrderData.AuditorId = purchaseOrder.AuditorId
reportByOrderData.AuditTime = purchaseOrder.AuditTime
reportByOrderData.AuditorName = purchaseOrder.AuditorName
reportByOrderData.State = purchaseOrder.State
reportByOrderData.Remark = purchaseOrder.Remark
2024-03-18 11:53:42 +00:00
if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
reportByOrderData.MakerTime = nil
} else {
reportByOrderData.MakerTime = purchaseOrder.MakerTime
}
if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
reportByOrderData.AuditTime = nil
} else {
reportByOrderData.AuditTime = purchaseOrder.AuditTime
}
var nAmount float64
2024-03-27 10:01:38 +00:00
var nCount int32
// 使用 map 来组合相同 ErpCommodityId 的数据
commodityMapInfo := make(map[uint32]ErpPurchaseCommodityData)
for _, inventory := range inventoryList {
if inventory.ErpPurchaseOrderId == purchaseOrder.ID {
2024-03-27 10:01:38 +00:00
var vCount int32
var vAmount float64
if inventory.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
vAmount = -inventory.Amount
vCount = -int32(inventory.Count)
} else {
vCount = int32(inventory.Count)
vAmount = inventory.Amount
}
if existingData, ok := commodityMapInfo[inventory.ErpCommodityId]; ok {
// 如果已经存在相同 ErpCommodityId 的数据,则累加 Amount 和 Count
existingData.Amount += vAmount
existingData.Count += vCount
existingData.Price = existingData.Amount / float64(existingData.Count)
commodityMapInfo[inventory.ErpCommodityId] = existingData
} else {
// 否则,创建新的数据
commodityMapInfo[inventory.ErpCommodityId] = ErpPurchaseCommodityData{
CommodityData: CommodityData{
ErpCommodityId: inventory.ErpCommodityId,
ErpCommodityName: inventory.ErpCommodityName,
ErpCategoryID: inventory.ErpCategoryID,
ErpCategoryName: inventory.ErpCategoryName,
},
Amount: vAmount,
Price: inventory.ImplementationPrice,
Count: vCount,
}
}
// 累加总金额和总数量
nAmount += vAmount
nCount += vCount
}
}
2024-03-27 10:01:38 +00:00
// 将 map 中的值转换为 slice
for _, data := range commodityMapInfo {
commodityList = append(commodityList, data)
}
reportByOrderData.CommodityData = commodityList
reportByOrderData.Amount = nAmount
reportByOrderData.Count = nCount
if nCount != 0 {
reportByOrderData.Price = nAmount / float64(nCount)
}
reportOrderDataList = append(reportOrderDataList, reportByOrderData)
nTotalAmount += nAmount
nTotalCount += nCount
}
resp.Total = differentCommodityCount
resp.List = reportOrderDataList
resp.Amount = nTotalAmount
resp.Count = nTotalCount
if req.IsExport == 1 {
filePath, err := reportByOrderExport(resp)
if err != nil {
return nil, err
}
resp = &ErpPurchaseReportByOrderResp{}
resp.ExportUrl = filePath
}
return resp, nil
}
// 查询采购报表(按单): 先筛选采购订单表,再补充商品入库信息
func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseReportByOrderResp, error) {
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpPurchaseReportByOrderResp{
PageIndex: page + 1,
PageSize: req.PageSize,
}
2024-03-27 10:01:38 +00:00
qs := orm.Eloquent.Table("erp_purchase_order").Where("state != 1") // 未审核订单不展示
if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber)
} else {
if req.PurchaseType != "" { // 采购类型
qs = qs.Where("purchase_type=?", req.PurchaseType)
}
2024-03-18 11:53:42 +00:00
if len(req.ErpSupplierId) > 0 { // 供应商复选
var supplierIDs []uint32
for _, supplier := range req.ErpSupplierId {
supplierIDs = append(supplierIDs, supplier)
}
qs = qs.Where("erp_supplier_id IN (?)", supplierIDs)
}
2024-03-18 11:53:42 +00:00
if len(req.StoreId) > 0 { // 门店复选
var storeIDs []uint32
for _, store := range req.StoreId {
storeIDs = append(storeIDs, store)
}
qs = qs.Where("store_id IN (?)", storeIDs)
}
if req.HandlerId != 0 { // 经手人id
qs = qs.Where("handler_id=?", req.HandlerId)
}
if req.State != 0 { // 订单状态
qs = qs.Where("state=?", req.State)
}
if req.AuditTimeStart != "" { // 审核开始时间
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
qs = qs.Where("audit_time > ?", parse)
}
if req.AuditTimeEnd != "" { // 审核结束时间
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
2024-03-27 10:01:38 +00:00
//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
2024-03-27 10:01:38 +00:00
var nTotalCount int32
for _, v := range orders {
var reportByOrderData ReportByOrderData
var nAmount float64
2024-03-27 10:01:38 +00:00
var nCount int32
2024-03-18 11:53:42 +00:00
reportByOrderData.ErpPurchaseOrderId = v.ID
reportByOrderData.SerialNumber = v.SerialNumber
reportByOrderData.PurchaseType = v.PurchaseType
reportByOrderData.StoreId = v.StoreId
reportByOrderData.StoreName = v.StoreName
reportByOrderData.ErpSupplierId = v.ErpSupplierId
reportByOrderData.ErpSupplierName = v.ErpSupplierName
reportByOrderData.HandlerId = v.HandlerId
reportByOrderData.HandlerName = v.HandlerName
2024-03-18 11:53:42 +00:00
//reportByOrderData.MakerTime = v.MakerTime
reportByOrderData.MakerId = v.MakerId
reportByOrderData.MakerName = v.MakerName
reportByOrderData.AuditorId = v.AuditorId
2024-03-18 11:53:42 +00:00
//reportByOrderData.AuditTime = v.AuditTime
reportByOrderData.AuditorName = v.AuditorName
reportByOrderData.State = v.State
reportByOrderData.Remark = v.Remark
2024-03-18 11:53:42 +00:00
if v.MakerTime != nil && v.MakerTime.IsZero() {
reportByOrderData.MakerTime = nil
} else {
reportByOrderData.MakerTime = v.MakerTime
}
if v.AuditTime != nil && v.AuditTime.IsZero() {
reportByOrderData.AuditTime = nil
} else {
reportByOrderData.AuditTime = v.AuditTime
}
reportByOrderData.CommodityData, nAmount, nCount, err = getOrderInventoryInfo(v.ID)
if err != nil {
return nil, err
}
2024-03-27 10:01:38 +00:00
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
}
// 查询采购订单的入库信息
2024-03-27 10:01:38 +00:00
func getOrderInventoryInfo(erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, int32, error) {
var inventoryList []ErpPurchaseInventory
2024-03-27 10:01:38 +00:00
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
}
2024-03-27 10:01:38 +00:00
// 使用 map 来组合相同 ErpCommodityId 的数据
commodityMap := make(map[uint32]ErpPurchaseCommodityData)
var nAmount float64
2024-03-27 10:01:38 +00:00
var nCount int32
// 遍历库存列表,组合相同 ErpCommodityId 的数据
for _, v := range inventoryList {
2024-03-27 10:01:38 +00:00
var vCount int32
var vAmount float64
if v.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
vAmount = -v.Amount
vCount = -int32(v.Count)
} else {
vCount = int32(v.Count)
vAmount = v.Amount
}
if existingData, ok := commodityMap[v.ErpCommodityId]; ok {
// 如果已经存在相同 ErpCommodityId 的数据,则累加 Amount 和 Count
existingData.Amount += vAmount
existingData.Count += vCount
existingData.Price = existingData.Amount / float64(existingData.Count)
commodityMap[v.ErpCommodityId] = existingData
} else {
// 否则,创建新的数据
commodityMap[v.ErpCommodityId] = ErpPurchaseCommodityData{
CommodityData: CommodityData{
ErpCommodityId: v.ErpCommodityId,
ErpCommodityName: v.ErpCommodityName,
ErpCategoryID: v.ErpCategoryID,
ErpCategoryName: v.ErpCategoryName,
},
Amount: vAmount,
Price: v.ImplementationPrice,
Count: vCount,
}
}
// 累加总金额和总数量
nAmount += vAmount
nCount += vCount
}
// 将 map 中的值转换为 slice
var resp []ErpPurchaseCommodityData
for _, data := range commodityMap {
resp = append(resp, data)
}
return resp, nAmount, nCount, nil
}
// 导出采购报表按单excel
func reportByOrderExport(req *ErpPurchaseReportByOrderResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "采购报表(按单)" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"单据编号", "类型", "店铺名称", "备注", "供应商", "经手人", "制单人", "审核时间", "订单状态",
"商品名称", "商品分类", "已执行金额", "执行单价", "已执行数量"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row1 []interface{}
var row2 []interface{}
nExcelStartRow := 0
for _, orderData := range req.List {
var orderType string
switch orderData.PurchaseType {
case "procure":
orderType = "采购入库"
case "reject":
orderType = "采购退货"
}
var orderStatus string
switch orderData.State { // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
case ErpPurchaseOrderUnAudit:
orderStatus = "待审核"
case ErpPurchaseOrderWaitInventory:
orderStatus = "待入库"
case ErpPurchaseOrderWaitReject:
orderStatus = "待退货"
case ErpPurchaseOrderFinished:
orderStatus = "已完成"
case ErpPurchaseOrderEnd:
orderStatus = "已终止"
}
2024-03-27 10:01:38 +00:00
var strTime string
if orderData.AuditTime != nil {
strTime = orderData.AuditTime.Format(TimeFormat)
} else {
strTime = "--"
}
row1 = []interface{}{
2024-03-27 10:01:38 +00:00
orderData.SerialNumber, // 单据编号
orderType, // 类型
orderData.StoreName, // 店铺名称
orderData.Remark, // 备注
orderData.ErpSupplierName, // 供应商
orderData.HandlerName, // 经手人
orderData.MakerName, // 制单人
strTime, // 审核时间
orderStatus, // 订单状态
"--", // 商品名称
"--", // 商品分类
orderData.Amount, // 已执行金额
orderData.Price, // 执行单价
orderData.Count, // 已执行数量
}
for j, _ := range row1 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row1[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
for _, commodity := range orderData.CommodityData {
row2 = []interface{}{
"", // 单据编号
"", // 类型
"", // 店铺名称
"", // 备注
"", // 供应商
"", // 经手人
"", // 制单人
"", // 审核时间
"", // 订单状态
commodity.ErpCommodityName, // 商品名称
commodity.ErpCategoryName, // 商品分类
commodity.Amount, // 已执行金额
commodity.Price, // 执行单价
commodity.Count, // 已执行数量
}
for j, _ := range row2 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row2[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
}
totalData := "订单数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", "", "", "", "", "", "", "", req.Amount, "--", req.Count}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 13)
file.SetColWidth("Sheet1", "C", "C", 25)
file.SetColWidth("Sheet1", "H", "H", 20)
file.SetColWidth("Sheet1", "J", "J", 18)
endRow := fmt.Sprintf("N"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// GetReportByCommodity 查询采购报表(按商品)
func GetReportByCommodity(req *ErpPurchaseReportByCommodityReq) (*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: page + 1,
PageSize: req.PageSize,
}
qs := orm.Eloquent.Table("erp_purchase_inventory")
if req.ErpCommodityName != "" {
qs = qs.Where("erp_commodity_name=?", req.ErpCommodityName)
}
if req.ErpCategoryID != 0 {
qs = qs.Where("erp_category_id=?", req.ErpCategoryID)
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("getReportByOrderFromCommodityOrCategory count err:", logger.Field("err", err))
return resp, err
}
var inventoryList []ErpPurchaseInventory
if req.IsExport == 1 { // 导出excel
err = qs.Order("id DESC").Find(&inventoryList).Error
} else {
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&inventoryList).Error
}
if err != nil && err != RecordNotFound {
logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err))
return resp, err
}
commodityIDMap := make(map[uint32]map[uint32]ErpPurchaseInventory)
// 遍历 inventoryList
for _, inventory := range inventoryList {
// 如果该商品id已经在map中则将该订单id加入到对应的set中
if ids, ok := commodityIDMap[inventory.ErpCommodityId]; ok {
ids[inventory.ErpPurchaseOrderId] = inventory
} else {
// 如果该商品id不在map中则创建一个新的map并加入订单id及其对应的 ErpPurchaseInventory
commodityIDMap[inventory.ErpCommodityId] = map[uint32]ErpPurchaseInventory{
inventory.ErpPurchaseOrderId: inventory,
}
}
}
resp.Total = len(commodityIDMap)
var reportByCommodityDataList []ReportByCommodityData
var totalData PurchaseData
// 遍历 map 获取去重的 ErpPurchaseOrderId
for _, orderIdSet := range commodityIDMap {
var reportByCommodityData ReportByCommodityData
if len(orderIdSet) != 0 {
reportByCommodityData.ErpCommodityId = orderIdSet[0].ErpPurchaseCommodityId
reportByCommodityData.ErpCommodityName = orderIdSet[0].ErpCommodityName
reportByCommodityData.ErpCategoryID = orderIdSet[0].ErpCategoryID
reportByCommodityData.ErpCategoryName = orderIdSet[0].ErpCategoryName
}
var totalPurchaseData PurchaseData
var purchaseOrderDataList []ErpCommodityPurchaseOrderData
for orderId := range orderIdSet {
2024-03-18 11:53:42 +00:00
purchaseOrderData, err := getPurchaseOrderData(orderId, req)
if err != nil {
return nil, err
}
purchaseOrderDataList = append(purchaseOrderDataList, purchaseOrderData)
totalPurchaseData.PlanCount += purchaseOrderData.PlanCount
totalPurchaseData.PlanPrice += purchaseOrderData.PlanPrice
totalPurchaseData.PlanAmount += purchaseOrderData.PlanAmount
totalPurchaseData.Amount += purchaseOrderData.Amount
totalPurchaseData.Price += purchaseOrderData.Price
totalPurchaseData.Count += purchaseOrderData.Count
totalPurchaseData.NonExecutionAmount += purchaseOrderData.NonExecutionAmount
totalPurchaseData.NonExecutionCount += purchaseOrderData.NonExecutionCount
}
reportByCommodityData.PlanCount = totalPurchaseData.PlanCount
reportByCommodityData.PlanPrice = totalPurchaseData.PlanPrice
reportByCommodityData.PlanAmount = totalPurchaseData.PlanAmount
reportByCommodityData.Amount = totalPurchaseData.Amount
reportByCommodityData.Price = totalPurchaseData.Price
reportByCommodityData.Count = totalPurchaseData.Count
reportByCommodityData.NonExecutionAmount = totalPurchaseData.NonExecutionAmount
reportByCommodityData.NonExecutionCount = totalPurchaseData.NonExecutionCount
totalData.PlanCount += reportByCommodityData.PlanCount
totalData.PlanAmount += reportByCommodityData.PlanAmount
totalData.Amount += reportByCommodityData.Amount
totalData.Count += reportByCommodityData.Count
totalData.NonExecutionAmount += reportByCommodityData.NonExecutionAmount
totalData.NonExecutionCount += reportByCommodityData.NonExecutionCount
reportByCommodityData.OrderInfo = purchaseOrderDataList
reportByCommodityDataList = append(reportByCommodityDataList, reportByCommodityData)
}
resp.List = reportByCommodityDataList
resp.PlanCount = totalData.PlanCount
resp.PlanAmount = totalData.PlanAmount
resp.Amount = totalData.Amount
resp.Count = totalData.Count
resp.NonExecutionAmount = totalData.NonExecutionAmount
resp.NonExecutionCount = totalData.NonExecutionCount
if req.IsExport == 1 {
filePath, err := reportByCommodityExport(resp)
if err != nil {
return nil, err
}
resp = &ErpPurchaseReportByCommodityResp{}
resp.ExportUrl = filePath
}
return resp, nil
}
// 查询采购订单信息
2024-03-18 11:53:42 +00:00
func getPurchaseOrderData(orderID uint32, req *ErpPurchaseReportByCommodityReq) (ErpCommodityPurchaseOrderData, error) {
var purchaseOrderData ErpCommodityPurchaseOrderData
// 查询采购订单信息
var purchaseOrder ErpPurchaseOrder
2024-03-18 11:53:42 +00:00
qs := orm.Eloquent.Table("erp_purchase_order")
if len(req.ErpSupplierId) > 0 { // 供应商复选
2024-03-27 10:01:38 +00:00
qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId)
2024-03-18 11:53:42 +00:00
}
if len(req.StoreId) > 0 { // 门店复选
2024-03-27 10:01:38 +00:00
qs = qs.Where("store_id IN (?)", req.StoreId)
2024-03-18 11:53:42 +00:00
}
err := qs.Where("id = ?", orderID).Find(&purchaseOrder).Error
if err != nil {
return purchaseOrderData, err
}
// 查询采购订单的计划和执行信息
purchaseData, err := getPurchaseData(purchaseOrder.ID)
if err != nil {
return purchaseOrderData, err
}
// 组合数据
2024-03-18 11:53:42 +00:00
purchaseOrderData.ErpPurchaseOrderId = purchaseOrder.ID
purchaseOrderData.SerialNumber = purchaseOrder.SerialNumber
purchaseOrderData.PurchaseType = purchaseOrder.PurchaseType
purchaseOrderData.StoreId = purchaseOrder.StoreId
purchaseOrderData.StoreName = purchaseOrder.StoreName
purchaseOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
purchaseOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
purchaseOrderData.HandlerId = purchaseOrder.HandlerId
purchaseOrderData.HandlerName = purchaseOrder.HandlerName
2024-03-18 11:53:42 +00:00
//purchaseOrderData.MakerTime = purchaseOrder.MakerTime
purchaseOrderData.MakerId = purchaseOrder.MakerId
purchaseOrderData.MakerName = purchaseOrder.MakerName
purchaseOrderData.AuditorId = purchaseOrder.AuditorId
2024-03-18 11:53:42 +00:00
//purchaseOrderData.AuditTime = purchaseOrder.AuditTime
purchaseOrderData.AuditorName = purchaseOrder.AuditorName
2024-03-18 11:53:42 +00:00
if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
purchaseOrderData.MakerTime = nil
} else {
purchaseOrderData.MakerTime = purchaseOrder.MakerTime
}
if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
purchaseOrderData.AuditTime = nil
} else {
purchaseOrderData.AuditTime = purchaseOrder.AuditTime
}
purchaseOrderData.PlanCount = purchaseData.PlanCount
purchaseOrderData.PlanPrice = purchaseData.PlanPrice
purchaseOrderData.PlanAmount = purchaseData.PlanAmount
purchaseOrderData.Amount = purchaseData.Amount
purchaseOrderData.Price = purchaseData.Price
purchaseOrderData.Count = purchaseData.Count
purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount
purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount
2024-03-27 10:01:38 +00:00
if purchaseOrder.PurchaseType == ErpRejectOrder { // 退货单
purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount
purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount
purchaseOrderData.Amount = -purchaseOrderData.Amount
purchaseOrderData.Count = -purchaseOrderData.Count
purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount
purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount
}
return purchaseOrderData, nil
}
// getPurchaseData 根据 ErpPurchaseCommodity 表查询采购数据
func getPurchaseData(erpPurchaseOrderId uint32) (PurchaseData, error) {
var purchaseData PurchaseData
err := orm.Eloquent.Raw(`
SELECT
SUM(pc.count) AS plan_count,
AVG(pc.price) AS plan_price,
SUM(pc.amount) AS plan_amount,
SUM(pi.count) AS count,
AVG(pi.implementation_price) AS price,
SUM(pi.amount) AS amount
FROM
erp_purchase_commodity pc
JOIN
erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
WHERE
pc.erp_purchase_order_id = ?
GROUP BY
pc.erp_purchase_order_id
`, erpPurchaseOrderId).Scan(&purchaseData).Error
if err != nil {
logger.Error("getPurchaseData err:", logger.Field("err", err))
return purchaseData, err
}
// 计算未执行金额和未执行数量
purchaseData.NonExecutionAmount = purchaseData.PlanAmount - purchaseData.Amount
purchaseData.NonExecutionCount = purchaseData.PlanCount - purchaseData.Count
return purchaseData, nil
}
// 查询采购报表(按商品):先筛选采购订单表,再补充商品入库信息
func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq) (*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,
}
2024-03-27 10:01:38 +00:00
qs := orm.Eloquent.Table("erp_purchase_order").Where("state != 1")
if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber)
} else {
if req.PurchaseType != "" { // 采购类型
qs = qs.Where("purchase_type=?", req.PurchaseType)
}
2024-03-18 11:53:42 +00:00
if len(req.ErpSupplierId) > 0 { // 供应商复选
2024-03-27 10:01:38 +00:00
qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId)
}
2024-03-18 11:53:42 +00:00
if len(req.StoreId) > 0 { // 门店复选
2024-03-27 10:01:38 +00:00
qs = qs.Where("store_id IN (?)", req.StoreId)
}
if req.HandlerId != 0 { // 经手人id
qs = qs.Where("handler_id=?", req.HandlerId)
}
if req.State != 0 { // 订单状态
qs = qs.Where("state=?", req.State)
}
if req.AuditTimeStart != "" { // 审核开始时间
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeStart)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
qs = qs.Where("audit_time > ?", parse)
}
if req.AuditTimeEnd != "" { // 审核结束时间
parse, err := time.Parse(QueryTimeFormat, req.AuditTimeEnd)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
2024-03-27 10:01:38 +00:00
//parse = parse.AddDate(0, 0, 1)
qs = qs.Where("audit_time < ?", parse)
}
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("getReportByOrderFromCommon count err:", logger.Field("err", err))
return resp, err
}
var orders []ErpPurchaseOrder
err = qs.Order("id DESC").Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("getReportByOrderFromCommon erp_purchase_order err:", logger.Field("err", err))
return resp, err
}
// 查询所有商品id及其对应的orderId
commodityAndOrderIdMap, err := getAllOrderCommodity(page, req.PageSize, int(req.IsExport))
if err != nil {
return nil, err
}
tempDataMap := make(map[uint32][]TempData)
//// 补充所有采购订单的商品信息和采购执行数量
//for _, v := range orders {
// commodityIds := findCommodityIDsByOrderID(v.ID, commodityAndOrderIdMap)
// // 获取每个采购订单的每个商品的采购和执行信息
// for _, commodityId := range commodityIds {
// purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(v.ID, commodityId)
// if err != nil {
// return nil, err
// }
//
// tempData := TempData{
// CommodityData: commodityData,
// ErpCommodityPurchaseOrderData: purchaseOrderData,
// }
// tempDataMap[commodityId] = append(tempDataMap[commodityId], tempData)
// }
//}
var wg sync.WaitGroup
ch := make(chan TempData, len(orders)*len(commodityAndOrderIdMap))
// 并发查询每个采购订单的每个商品的采购和执行信息
for _, v := range orders {
commodityIds := findCommodityIDsByOrderID(v.ID, commodityAndOrderIdMap)
for _, commodityID := range commodityIds {
wg.Add(1)
go getPurchaseOrderAndCommodityDataAsync(v.ID, commodityID, ch, &wg)
}
}
wg.Wait()
close(ch)
for data := range ch {
tempDataMap[data.ErpCommodityId] = append(tempDataMap[data.ErpCommodityId], data)
}
var dataList []ReportByCommodityData
var totalData PurchaseData
// tempDataList按照商品id进行归类
for _, tempDataList := range tempDataMap {
var reportData ReportByCommodityData
for _, v := range tempDataList {
reportData.ErpCategoryID = v.ErpCategoryID
reportData.ErpCategoryName = v.ErpCategoryName
reportData.ErpCommodityId = v.ErpCommodityId
reportData.ErpCommodityName = v.ErpCommodityName
reportData.PlanCount += v.PlanCount
reportData.PlanAmount += v.PlanAmount
reportData.Amount += v.Amount
reportData.Count += v.Count
reportData.NonExecutionAmount += v.NonExecutionAmount
reportData.NonExecutionCount += v.NonExecutionCount
2024-03-27 10:01:38 +00:00
if reportData.PlanCount != 0 {
reportData.PlanPrice = reportData.PlanAmount / float64(reportData.PlanCount)
reportData.PlanPrice = math.Round(reportData.PlanPrice*100) / 100
}
if reportData.Count != 0 {
reportData.Price = reportData.Amount / float64(reportData.Count)
reportData.Price = math.Round(reportData.Price*100) / 100
}
purchaseOrderData := ErpCommodityPurchaseOrderData{
CommonData{
2024-03-18 11:53:42 +00:00
ErpPurchaseOrderId: v.ErpPurchaseOrderId,
SerialNumber: v.SerialNumber,
PurchaseType: v.PurchaseType,
StoreId: v.StoreId,
StoreName: v.StoreName,
ErpSupplierId: v.ErpSupplierId,
ErpSupplierName: v.ErpSupplierName,
HandlerId: v.HandlerId,
HandlerName: v.HandlerName,
//MakerTime: v.MakerTime,
MakerId: v.MakerId,
MakerName: v.MakerName,
AuditorId: v.AuditorId,
//AuditTime: v.AuditTime,
AuditorName: v.AuditorName,
},
PurchaseData{
PlanCount: v.PlanCount,
PlanPrice: v.PlanPrice,
PlanAmount: v.PlanAmount,
Amount: v.Amount,
Price: v.Price,
Count: v.Count,
NonExecutionAmount: v.NonExecutionAmount,
NonExecutionCount: v.NonExecutionCount,
},
}
2024-03-18 11:53:42 +00:00
2024-03-27 10:01:38 +00:00
if v.PurchaseType == ErpRejectOrder { // 退货单
reportData.PlanCount = -reportData.PlanCount
reportData.PlanAmount = -reportData.PlanAmount
reportData.Amount = -reportData.Amount
reportData.Count = -reportData.Count
reportData.NonExecutionAmount = -reportData.NonExecutionAmount
reportData.NonExecutionCount = -reportData.NonExecutionCount
purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount
purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount
purchaseOrderData.Amount = -purchaseOrderData.Amount
purchaseOrderData.Count = -purchaseOrderData.Count
purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount
purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount
}
2024-03-18 11:53:42 +00:00
if v.MakerTime != nil && v.MakerTime.IsZero() {
purchaseOrderData.MakerTime = nil
} else {
purchaseOrderData.MakerTime = v.MakerTime
}
if v.AuditTime != nil && v.AuditTime.IsZero() {
purchaseOrderData.AuditTime = nil
} else {
purchaseOrderData.AuditTime = v.AuditTime
}
reportData.OrderInfo = append(reportData.OrderInfo, purchaseOrderData)
}
dataList = append(dataList, reportData)
totalData.PlanCount += reportData.PlanCount
totalData.PlanAmount += reportData.PlanAmount
totalData.Amount += reportData.Amount
totalData.Count += reportData.Count
totalData.NonExecutionAmount += reportData.NonExecutionAmount
totalData.NonExecutionCount += reportData.NonExecutionCount
}
sortByCommodityIDDesc(dataList)
resp.Total = len(dataList)
resp.List = dataList
resp.PlanCount = totalData.PlanCount
resp.PlanAmount = totalData.PlanAmount
resp.Amount = totalData.Amount
resp.Count = totalData.Count
resp.NonExecutionAmount = totalData.NonExecutionAmount
resp.NonExecutionCount = totalData.NonExecutionCount
if req.IsExport == 1 {
filePath, err := reportByCommodityExport(resp)
if err != nil {
return nil, err
}
resp = &ErpPurchaseReportByCommodityResp{}
resp.ExportUrl = filePath
}
return resp, nil
}
func getPurchaseOrderAndCommodityDataAsync(orderID, commodityID uint32, ch chan<- TempData, wg *sync.WaitGroup) {
defer wg.Done()
purchaseOrderData, commodityData, err := getPurchaseOrderAndCommodityData(orderID, commodityID)
if err != nil {
logger.Errorf("getPurchaseOrderAndCommodityDataAsync err:", err)
return
}
tempData := TempData{
CommodityData: commodityData,
ErpCommodityPurchaseOrderData: purchaseOrderData,
}
ch <- tempData
}
// 按照商品ID进行倒序排序的 less 函数
func sortByCommodityIDDesc(dataList []ReportByCommodityData) {
sort.Slice(dataList, func(i, j int) bool {
return dataList[i].ErpCommodityId > dataList[j].ErpCommodityId
})
}
// 查询采购订单信息
func getPurchaseOrderAndCommodityData(orderID, commodityId uint32) (ErpCommodityPurchaseOrderData, CommodityData, error) {
var purchaseOrderData ErpCommodityPurchaseOrderData
// 查询采购订单信息
var purchaseOrder ErpPurchaseOrder
err := orm.Eloquent.Table("erp_purchase_order").Where("id = ?", orderID).Find(&purchaseOrder).Error
if err != nil {
return ErpCommodityPurchaseOrderData{}, CommodityData{}, err
}
// 查询采购订单的计划和执行信息
purchaseData, commodityData, err := getSignalPurchaseData(purchaseOrder.ID, commodityId)
if err != nil {
return ErpCommodityPurchaseOrderData{}, CommodityData{}, err
}
// 组合数据
2024-03-18 11:53:42 +00:00
purchaseOrderData.ErpPurchaseOrderId = purchaseOrder.ID
purchaseOrderData.SerialNumber = purchaseOrder.SerialNumber
purchaseOrderData.PurchaseType = purchaseOrder.PurchaseType
purchaseOrderData.StoreId = purchaseOrder.StoreId
purchaseOrderData.StoreName = purchaseOrder.StoreName
purchaseOrderData.ErpSupplierId = purchaseOrder.ErpSupplierId
purchaseOrderData.ErpSupplierName = purchaseOrder.ErpSupplierName
purchaseOrderData.HandlerId = purchaseOrder.HandlerId
purchaseOrderData.HandlerName = purchaseOrder.HandlerName
purchaseOrderData.MakerId = purchaseOrder.MakerId
purchaseOrderData.MakerName = purchaseOrder.MakerName
purchaseOrderData.AuditorId = purchaseOrder.AuditorId
purchaseOrderData.AuditTime = purchaseOrder.AuditTime
purchaseOrderData.AuditorName = purchaseOrder.AuditorName
2024-03-18 11:53:42 +00:00
if purchaseOrder.MakerTime != nil && purchaseOrder.MakerTime.IsZero() {
purchaseOrderData.MakerTime = nil
} else {
purchaseOrderData.MakerTime = purchaseOrder.MakerTime
}
if purchaseOrder.AuditTime != nil && purchaseOrder.AuditTime.IsZero() {
purchaseOrderData.AuditTime = nil
} else {
purchaseOrderData.AuditTime = purchaseOrder.AuditTime
}
purchaseOrderData.PlanCount = purchaseData.PlanCount
purchaseOrderData.PlanPrice = purchaseData.PlanPrice
purchaseOrderData.PlanAmount = purchaseData.PlanAmount
purchaseOrderData.Amount = purchaseData.Amount
purchaseOrderData.Price = purchaseData.Price
purchaseOrderData.Count = purchaseData.Count
purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount
purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount
return purchaseOrderData, commodityData, nil
}
// getSignalPurchaseData 根据 ErpPurchaseCommodity 表查询采购数据
func getSignalPurchaseData(erpPurchaseOrderId, commodityId uint32) (PurchaseData, CommodityData, error) {
var purchaseData PurchaseData
var commodityData CommodityData
err := orm.Eloquent.Raw(`
SELECT
SUM(pc.count) AS plan_count,
AVG(pc.price) AS plan_price,
SUM(pc.amount) AS plan_amount,
SUM(pi.count) AS count,
AVG(pi.implementation_price) AS price,
SUM(pi.amount) AS amount
FROM
erp_purchase_commodity pc
JOIN
erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
WHERE
pc.erp_purchase_order_id = ? and pc.erp_commodity_id = ?
GROUP BY
pc.erp_purchase_order_id
`, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
if err != nil {
logger.Error("getPurchaseData err:", logger.Field("err", err))
return PurchaseData{}, CommodityData{}, err
}
// 计算未执行金额和未执行数量
purchaseData.NonExecutionAmount = purchaseData.PlanAmount - purchaseData.Amount
purchaseData.NonExecutionCount = purchaseData.PlanCount - purchaseData.Count
// 查询订单对应的商品信息
commodityInfo, err := GetCommodity(commodityId)
if err != nil {
return PurchaseData{}, CommodityData{}, err
}
commodityData.ErpCommodityId = commodityInfo.ID
commodityData.ErpCommodityName = commodityInfo.Name
commodityData.ErpCategoryID = commodityInfo.ErpCategoryId
commodityData.ErpCategoryName = commodityInfo.ErpCategoryName
return purchaseData, commodityData, nil
}
//// 查询所有商品信息
//func getAllOrderCommodity(pageIndex, pageSize int) (map[uint32][]uint32, error) {
// qs := orm.Eloquent.Table("erp_purchase_commodity")
//
// var count int64
// err := qs.Count(&count).Error
// if err != nil {
// logger.Error("getAllOrderCommodity count err:", logger.Field("err", err))
// return nil, err
// }
//
// var commodityList []ErpPurchaseCommodity
// err = qs.Order("id DESC").Offset(pageIndex * pageSize).Limit(pageSize).Find(&commodityList).Error
// if err != nil && err != RecordNotFound {
// logger.Error("getAllOrderCommodity erp_purchase_commodity err:", logger.Field("err", err))
// return nil, err
// }
//
// commodityMap := make(map[uint32][]uint32)
// for _, v := range commodityList {
// if !contains(commodityMap[v.ErpCommodityId], v.ErpPurchaseOrderId) {
// commodityMap[v.ErpCommodityId] = append(commodityMap[v.ErpCommodityId], v.ErpPurchaseOrderId)
// }
// }
//
// return commodityMap, nil
//}
//
//func contains(slice []uint32, item uint32) bool {
// for _, value := range slice {
// if value == item {
// return true
// }
// }
// return false
//}
// 查询所有商品信息每页展示不同商品ID及其对应的订单ID
func getAllOrderCommodity(pageIndex, pageSize, 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 = "采购退货"
}
2024-03-27 10:01:38 +00:00
var strTime string
if orderData.AuditTime != nil {
strTime = orderData.AuditTime.Format(TimeFormat)
} else {
strTime = "--"
}
row2 = []interface{}{
2024-03-27 10:01:38 +00:00
"", // 商品名称
"", // 商品分类
orderData.SerialNumber, // 单据编号
orderType, // 类型
orderData.StoreName, // 店铺名称
orderData.ErpSupplierName, // 供应商
orderData.HandlerName, // 经手人
orderData.MakerName, // 制单人
strTime, // 审核时间
orderData.PlanAmount, // 计划采购金额
orderData.PlanPrice, // 计划采购单价
orderData.PlanCount, // 计划采购数量
orderData.Amount, // 已执行金额
orderData.Price, // 已执行单价
orderData.Count, // 已执行数量
orderData.NonExecutionAmount, // 未执行金额
orderData.NonExecutionCount, // 未执行数量
}
for j, _ := range row2 {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+3)
err := file.SetCellValue(fSheet, cell, row2[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
}
totalData := "订单数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{totalData, "", "", "", "", "", "", "", "",
req.PlanAmount, // 计划采购金额
"--", // 计划采购单价
req.PlanCount, // 计划采购数量
req.Amount, // 已执行金额
"--", // 已执行单价
req.Count, // 已执行数量
req.NonExecutionAmount, // 未执行金额
req.NonExecutionCount, // 未执行数量
}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
// 合并单元格
_ = file.MergeCell(fSheet, "A1", "A2")
_ = file.MergeCell(fSheet, "B1", "B2")
_ = file.MergeCell(fSheet, "C1", "C2")
_ = file.MergeCell(fSheet, "D1", "D2")
_ = file.MergeCell(fSheet, "E1", "E2")
_ = file.MergeCell(fSheet, "F1", "F2")
_ = file.MergeCell(fSheet, "G1", "G2")
_ = file.MergeCell(fSheet, "H1", "H2")
_ = file.MergeCell(fSheet, "I1", "I2")
_ = file.MergeCell(fSheet, "J1", "L1")
_ = file.MergeCell(fSheet, "M1", "O1")
_ = file.MergeCell(fSheet, "P1", "Q1")
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
file.SetRowHeight("Sheet1", 2, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 15)
file.SetColWidth("Sheet1", "B", "B", 10)
file.SetColWidth("Sheet1", "C", "C", 13)
file.SetColWidth("Sheet1", "E", "E", 25)
endRow := fmt.Sprintf("Q"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// GetReportBySupplier 查询供应商采购汇总
func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*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)
}
2024-03-18 11:53:42 +00:00
if len(req.ErpCommodityName) > 0 {
2024-03-27 10:01:38 +00:00
query = query.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName)
}
2024-03-18 11:53:42 +00:00
if len(req.ErpCategoryID) > 0 {
2024-03-27 10:01:38 +00:00
query = query.Where("erp_purchase_inventory.erp_category_id IN (?)", req.ErpCategoryID)
}
if req.StartTime != "" { // 入/出库开始时间
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Errorf("GetReportDetail err:", err)
return nil, err
}
query = query.Where("erp_purchase_inventory.created_at >= ?", parse)
}
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 {
2024-03-27 10:01:38 +00:00
query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreList)
}
// 获取总数
var total int64
query.Count(&total)
resp.Total = int(total)
// 分页查询
2024-03-18 11:53:42 +00:00
var err error
if req.IsExport == 1 { // 导出excel
2024-03-18 11:53:42 +00:00
err = query.Find(&resp.List).Error
} else {
2024-03-27 10:01:38 +00:00
//err = query.Offset((req.PageIndex - 1) * req.PageSize).Limit(req.PageSize).Find(&resp.List).Error
err = query.Find(&resp.List).Error
2024-03-18 11:53:42 +00:00
}
if err != nil {
return nil, err
}
2024-03-27 10:01:38 +00:00
var esData []PurchaseReportData
2024-03-27 10:01:38 +00:00
if len(req.ErpSupplierId) > 0 {
var purchaseOrder []ErpPurchaseOrder
err = orm.Eloquent.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId).Find(&purchaseOrder).Error
if err != nil {
return nil, err
}
// 循环遍历采购订单
for _, po := range purchaseOrder {
// 在resp.List中查找匹配的订单
for _, respItem := range resp.List {
if po.ID == respItem.ErpPurchaseOrderId {
// 如果找到匹配的订单将其添加到esData中
data := PurchaseReportData{
ErpPurchaseOrderId: po.ID,
StoreId: po.StoreId,
StoreName: po.StoreName,
PurchaseType: respItem.PurchaseType,
ErpSupplierId: po.ErpSupplierId,
ErpSupplierName: po.ErpSupplierName,
ErpCommodityId: respItem.ErpCommodityId,
ErpCommodityName: respItem.ErpCommodityName,
ErpCategoryID: respItem.ErpCategoryID,
ErpCategoryName: respItem.ErpCategoryName,
Count: respItem.Count,
Amount: respItem.Amount,
RejectAmount: respItem.RejectAmount,
Difference: respItem.Difference,
}
if data.PurchaseType == "reject" {
data.Amount = -data.Amount
data.RejectAmount = -data.RejectAmount
data.Difference = data.Amount + data.RejectAmount
}
esData = append(esData, data)
}
}
}
resp.List = esData
} else {
// 补充关联的供应商和店铺信息
for i := range resp.List {
var purchaseOrderInfo ErpPurchaseOrder
orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrderInfo)
resp.List[i].StoreId = purchaseOrderInfo.StoreId
resp.List[i].StoreName = purchaseOrderInfo.StoreName
resp.List[i].ErpSupplierId = purchaseOrderInfo.ErpSupplierId
resp.List[i].ErpSupplierName = purchaseOrderInfo.ErpSupplierName
if resp.List[i].PurchaseType == "reject" {
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
}
}
}
2024-03-27 10:01:38 +00:00
mergedData := mergeData(resp.List)
// 统计总计数量和金额
var totalAmount float64
var totalCount uint32
2024-03-27 10:01:38 +00:00
var totalRejectAmount float64
var totalDifference float64
for _, item := range mergedData {
totalAmount += item.Amount
totalCount += item.Count
2024-03-27 10:01:38 +00:00
totalRejectAmount += item.RejectAmount
totalDifference += item.Difference
}
resp.Amount = totalAmount
resp.Count = totalCount
2024-03-27 10:01:38 +00:00
resp.RejectAmount = totalRejectAmount
resp.Difference = totalDifference
resp.Total = len(mergedData)
// 分页处理
startIdx := (resp.PageIndex - 1) * resp.PageSize
endIdx := resp.PageIndex * resp.PageSize
// 确保不超出索引范围
if startIdx >= len(mergedData) {
resp.List = []PurchaseReportData{}
} else if endIdx > len(mergedData) {
resp.List = mergedData[startIdx:]
} else {
resp.List = mergedData[startIdx:endIdx]
}
if req.IsExport == 1 {
filePath, err := reportBySupplierExport(resp)
if err != nil {
return nil, err
}
resp = &ErpPurchaseReportBySupplierResp{}
resp.ExportUrl = filePath
}
return resp, nil
}
2024-03-27 10:01:38 +00:00
//func mergeData(esData []PurchaseReportData) []PurchaseReportData {
// mergedMap := make(map[string]*PurchaseReportData)
//
// // 遍历 esData 数据
// for _, data := range esData {
// key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType)
// if _, ok := mergedMap[key]; !ok {
// // 如果键不存在,创建新条目
// mergedMap[key] = &PurchaseReportData{
// StoreId: data.StoreId,
// ErpSupplierId: data.ErpSupplierId,
// ErpCommodityId: data.ErpCommodityId,
// StoreName: data.StoreName,
// PurchaseType: data.PurchaseType,
// ErpSupplierName: data.ErpSupplierName,
// ErpCommodityName: data.ErpCommodityName,
// ErpCategoryID: data.ErpCategoryID,
// ErpCategoryName: data.ErpCategoryName,
// Count: data.Count,
// Amount: data.Amount,
// RejectAmount: data.RejectAmount,
// Difference: data.Difference,
// }
// } else {
// // 如果键已存在,进行累加操作
// mergedMap[key].Count += data.Count
// mergedMap[key].Amount += data.Amount
// mergedMap[key].RejectAmount += data.RejectAmount
// mergedMap[key].Difference += data.Difference
// }
// }
//
// // 将合并后的数据转换为数组返回
// var mergedData []PurchaseReportData
// for _, v := range mergedMap {
// mergedData = append(mergedData, *v)
// }
//
// return mergedData
//}
func mergeData(esData []PurchaseReportData) []PurchaseReportData {
mergedMap := make(map[string]*PurchaseReportData)
var keys []string // 用于记录键的顺序
// 遍历 esData 数据
for _, data := range esData {
key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType)
if _, ok := mergedMap[key]; !ok {
// 如果键不存在,创建新条目
mergedMap[key] = &PurchaseReportData{
StoreId: data.StoreId,
ErpSupplierId: data.ErpSupplierId,
ErpCommodityId: data.ErpCommodityId,
StoreName: data.StoreName,
PurchaseType: data.PurchaseType,
ErpSupplierName: data.ErpSupplierName,
ErpCommodityName: data.ErpCommodityName,
ErpCategoryID: data.ErpCategoryID,
ErpCategoryName: data.ErpCategoryName,
Count: data.Count,
Amount: data.Amount,
RejectAmount: data.RejectAmount,
Difference: data.Difference,
}
if data.PurchaseType == ErpRejectOrder {
mergedMap[key].RejectAmount = mergedMap[key].Amount
mergedMap[key].Amount = 0
}
keys = append(keys, key) // 将键添加到有序的键列表中
} else {
// 如果键已存在,进行累加操作
mergedMap[key].Count += data.Count
mergedMap[key].Amount += data.Amount
mergedMap[key].RejectAmount += data.RejectAmount
mergedMap[key].Difference += data.Difference
if data.PurchaseType == ErpRejectOrder {
mergedMap[key].RejectAmount = mergedMap[key].Amount
mergedMap[key].Amount = 0
}
}
}
// 根据有序的键列表顺序构建返回的数组
var mergedData []PurchaseReportData
for _, key := range keys {
mergedData = append(mergedData, *mergedMap[key])
}
return mergedData
}
// 导出供应商采购汇总excel
func reportBySupplierExport(req *ErpPurchaseReportBySupplierResp) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "供应商采购汇总" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
// 组合标题栏数据
title := []interface{}{"店铺名称", "采购类型", "供应商", "商品名称", "商品分类", "采购数量", "采购金额", "退货金额", "差额"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Errorf("file set value err:", err)
}
}
var row []interface{}
nExcelStartRow := 0
for _, supplierData := range req.List {
var orderType string
switch supplierData.PurchaseType {
case "procure":
orderType = "采购入库"
case "reject":
orderType = "采购退货"
}
row = []interface{}{
supplierData.StoreName, // 店铺名称
orderType, // 采购类型
supplierData.ErpSupplierName, // 供应商
supplierData.ErpCommodityName, // 商品名称
supplierData.ErpCategoryName, // 商品分类
supplierData.Count, // 采购数量
supplierData.Amount, // 采购金额
supplierData.RejectAmount, // 退货金额
supplierData.Difference, // 差额
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
totalData := "记录数:" + strconv.FormatInt(int64(req.Total), 10)
end := []interface{}{"汇总", totalData, "", "", "",
req.Count, // 采购数量
req.Amount, // 采购金额
req.RejectAmount, // 退货金额
req.Difference, // 差额
}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 25)
file.SetColWidth("Sheet1", "D", "D", 15)
endRow := fmt.Sprintf("I"+"%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// GetReportDetail 查询采购明细
func GetReportDetail(req *ErpPurchaseReportDetailReq) (*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 {
2024-03-18 11:53:42 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
OrderSerialNumber string `json:"order_serial_number"`
2024-03-27 10:01:38 +00:00
SerialNumber string `json:"serial_number"`
2024-03-18 11:53:42 +00:00
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").
2024-03-18 11:53:42 +00:00
Select("erp_purchase_order.id as erp_purchase_order_id, "+
"erp_purchase_order.serial_number as order_serial_number, "+
2024-03-27 10:01:38 +00:00
"erp_purchase_inventory.serial_number, "+
"erp_purchase_order.purchase_type, "+
"erp_purchase_inventory.created_at as execute_time, "+
"erp_purchase_order.store_id, "+
"erp_purchase_order.store_name, "+
"erp_purchase_order.erp_supplier_id, "+
"erp_purchase_order.erp_supplier_name, "+
"erp_purchase_inventory.erp_commodity_id, "+
"erp_purchase_inventory.erp_commodity_name, "+
"erp_purchase_inventory.erp_category_id, "+
"erp_purchase_inventory.erp_category_name, "+
"erp_purchase_inventory.imei_type, "+
"erp_purchase_inventory.imei, "+
"CASE "+
"WHEN erp_purchase_order.purchase_type = 'procure' THEN erp_purchase_inventory.implementation_price "+
"WHEN erp_purchase_order.purchase_type = 'reject' THEN erp_purchase_inventory.implementation_price "+
"ELSE 0 END AS price, "+
"CASE "+
"WHEN erp_purchase_order.purchase_type = 'procure' THEN 0 "+
"WHEN erp_purchase_order.purchase_type = 'reject' THEN erp_purchase_inventory.implementation_price "+
"ELSE 0 END AS reject_price, "+
"erp_purchase_inventory.employee_price, "+
"(erp_purchase_inventory.implementation_price - erp_purchase_inventory.employee_price) as difference_price").
Joins("JOIN erp_purchase_inventory ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
Where("erp_purchase_order.state <> ?", 5) // 排除已终止的订单
2024-03-18 11:53:42 +00:00
// 创建一个新的查询对象,用于 count 查询
countQuery := orm.Eloquent.Debug().Table("erp_purchase_order").
Joins("JOIN erp_purchase_inventory ON erp_purchase_order.id = erp_purchase_inventory.erp_purchase_order_id").
Where("erp_purchase_order.state <> ?", 5) // 排除已终止的订单
if req.SerialNumber != "" {
qs = qs.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_order.serial_number = ?", req.SerialNumber)
}
if req.PurchaseType != "" {
qs = qs.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_order.purchase_type = ?", req.PurchaseType)
}
if req.ErpCommodityName != "" {
qs = qs.Where("erp_purchase_inventory.erp_commodity_name LIKE ?", "%"+req.ErpCommodityName+"%")
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_inventory.erp_commodity_name LIKE ?", "%"+req.ErpCommodityName+"%")
}
if req.ErpCategoryID != 0 {
qs = qs.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_inventory.erp_category_id = ?", req.ErpCategoryID)
}
if req.ErpSupplierId != 0 {
qs = qs.Where("erp_purchase_order.erp_supplier_id = ?", req.ErpSupplierId)
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_order.erp_supplier_id = ?", req.ErpSupplierId)
}
if req.StartTime != "" { // 入/出库开始时间
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Errorf("GetReportDetail err:", err)
return nil, err
}
qs = qs.Where("erp_purchase_inventory.created_at >= ?", parse)
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_inventory.created_at >= ?", parse)
}
if req.EndTime != "" { // 入/出库结束时间
parse, err := time.Parse(QueryTimeFormat, req.EndTime)
if err != nil {
logger.Errorf("GetReportDetail err:", err)
return nil, err
}
qs = qs.Where("erp_purchase_inventory.created_at <= ?", parse)
2024-03-18 11:53:42 +00:00
countQuery = countQuery.Where("erp_purchase_inventory.created_at <= ?", parse)
}
2024-03-18 11:53:42 +00:00
if len(req.StoreId) > 0 {
2024-03-27 10:01:38 +00:00
qs = qs.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreId)
2024-03-18 11:53:42 +00:00
}
var count int64
err := countQuery.Count(&count).Error
if err != nil {
logger.Errorf("GetReportDetail count err:", err)
return nil, err
}
offset := (req.PageIndex - 1) * req.PageSize
2024-03-18 11:53:42 +00:00
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 {
2024-03-27 10:01:38 +00:00
resp.List[i].DifferencePrice = 0
if resp.List[i].PurchaseType == "reject" {
2024-03-27 10:01:38 +00:00
// 采购退货单查询采购价:根据采购入库编号
price, err := getPrice(resp.List[i].SerialNumber)
if err != nil {
return nil, err
}
resp.List[i].Price = -float64(price)
resp.List[i].DifferencePrice = -resp.List[i].DifferencePrice
resp.List[i].RejectPrice = -resp.List[i].RejectPrice
2024-03-27 10:01:38 +00:00
resp.List[i].DifferencePrice = resp.List[i].Price - resp.List[i].RejectPrice
}
}
resp.Total = int(count)
resp.Price, resp.EmployeePrice, resp.RejectPrice, resp.DifferencePrice = calculatePrices(resp.List)
if req.IsExport == 1 {
filePath, err := reportDetailExport(resp)
if err != nil {
return nil, err
}
resp = &ErpPurchaseReportDetailResp{}
resp.ExportUrl = filePath
}
return resp, nil
}
2024-03-27 10:01:38 +00:00
// 根据采购单据号查询入库采购价
func getPrice(serialNumber string) (uint32, error) {
var stockCommodity ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("stock_sn = ?", serialNumber).
Find(&stockCommodity).Error
if err != nil {
return 0, err
}
return stockCommodity.WholesalePrice, nil
}
// 计算价格信息
func calculatePrices(list []struct {
2024-03-18 11:53:42 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id
OrderSerialNumber string `json:"order_serial_number"`
2024-03-27 10:01:38 +00:00
SerialNumber string `json:"serial_number"`
2024-03-18 11:53:42 +00:00
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
}
2024-03-27 10:01:38 +00:00
// CancelAuditUpdateStock 反审核后更新库存信息
// 查询订单有无入库信息
// 采购单,有入库信息,则退库;如果有已审核的退货单则不能反审核,报错提示
// 退货单,有入库信息,则入库
func CancelAuditUpdateStock(begin *gorm.DB, req ErpPurchaseOrder) error {
var purchaseOrder ErpPurchaseOrder
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ID).Find(&purchaseOrder).Error
if err != nil {
logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err))
return err
}
var inventoryList []ErpPurchaseInventory
err = orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", req.ID).
Find(&inventoryList).Error
if err != nil {
logger.Error("purchase commodities err:", logger.Field("err", err))
return err
}
if len(inventoryList) == 0 { // 还没有入库记录,直接取消审核
return nil
}
if req.PurchaseType == ErpProcureOrder { // 采购单反审核
// 查询有无退货订单
var count int64
stateList := []int{ErpPurchaseOrderUnAudit, ErpPurchaseOrderEnd}
err = orm.Eloquent.Table("erp_purchase_order").Where("rejected_serial_number = ? and state NOT IN (?)",
req.SerialNumber, stateList).Count(&count).Error
if err != nil {
return err
}
if count > 0 { // 有已审核的退货单
return errors.New("取消审核失败:已存在采购退库订单,请先将其取消")
}
//// 更新入库的商品为"采购退库"
//reqParam := &ErpPurchaseInventoryReq{
// ErpPurchaseOrderId: req.ID,
// PurchaseType: ErpRejectOrder,
// Inventories: inventoryList,
//}
// 按照采购退货更新库存
err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder)
if err != nil {
return fmt.Errorf("取消审核失败:%s", err.Error())
}
// 更新采购商品表的入库数量
for _, v := range inventoryList {
err = begin.Model(&ErpPurchaseCommodity{}).
Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
UpdateColumn("inventory_count", gorm.Expr("inventory_count - ?", v.Count)).Error
if err != nil {
logger.Error("update inventory count err:", logger.Field("err", err))
return err
}
}
} else if req.PurchaseType == ErpRejectOrder { // 退货单反审核
// 更新入库的商品为"采购退库"
reqParam := &ErpPurchaseInventoryReq{
ErpPurchaseOrderId: req.ID,
PurchaseType: ErpProcureOrder,
Inventories: inventoryList,
}
// 采购退货单反审核更新库存
err = ErpRejectOrderCancelAuditUpdateStock(begin, reqParam, purchaseOrder)
if err != nil {
return fmt.Errorf("取消审核失败:%s", err.Error())
}
// 更新采购商品表的入库数量
for _, v := range inventoryList {
err = begin.Model(&ErpPurchaseCommodity{}).
Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId).
UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error
if err != nil {
logger.Error("update inventory count err:", logger.Field("err", err))
return err
}
}
} else {
return errors.New("取消审核失败:采购类型有误")
}
// 删除采购入库的记录
err = begin.Table("erp_purchase_inventory").Where("erp_purchase_order_id = ? and purchase_type = ?",
req.ID, req.PurchaseType).Delete(&ErpPurchaseInventory{}).Error
if err != nil {
return err
}
return nil
}
// ErpRejectOrderCancelAuditUpdateStock 采购退货单反审核更新库存
func ErpRejectOrderCancelAuditUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error {
// 遍历采购入库商品信息
var stockList []ErpStockCommodity
for _, v := range req.Inventories {
commodityInfo, err := GetCommodity(v.ErpCommodityId)
if err != nil {
logger.Errorf("GetCommodity err:", err)
return err
}
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
purchaseOrder.StoreId, v.ErpCommodityId))
if err != nil {
logger.Errorf("exist err:", err)
return err
}
if exist {
err = gdb.Exec(fmt.Sprintf(
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;",
v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error
if err != nil {
logger.Errorf("update stock err:", err)
return err
}
} else {
return errors.New("未查询到商品库存信息")
}
// 更新商品库存信息
// 串码商品直接更新状态为:在库
if v.IMEIType == 2 || v.IMEIType == 3 { // 串码商品
if v.IMEI == "" {
return fmt.Errorf("商品[%s]串码为空", v.ErpCommodityName)
}
err = gdb.Table("erp_stock_commodity").Where("imei = ?", v.IMEI).
Update("state", InStock).Error // 状态更新为采购退货
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
}
// 非串码商品则新建
nowTime := time.Now()
stockCommodity := ErpStockCommodity{
StoreId: purchaseOrder.StoreId,
StoreName: purchaseOrder.StoreName,
ErpCommodityId: v.ErpCommodityId,
ErpCommodityName: v.ErpCommodityName,
CommoditySerialNumber: v.CommoditySerialNumber,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: purchaseOrder.ErpSupplierId,
ErpSupplierName: purchaseOrder.ErpSupplierName,
StaffCostPrice: uint32(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: uint32(v.ImplementationPrice),
State: InStock,
StorageType: PurchaseInventory, // 采购入库
FirstStockTime: nowTime,
StockTime: nowTime,
Count: v.Count,
ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码
IMEIType: v.IMEIType,
IMEI: v.IMEI,
Remark: "",
MemberDiscount: commodityInfo.MemberDiscount,
MinRetailPrice: commodityInfo.MinRetailPrice,
RetailPrice: commodityInfo.RetailPrice,
OriginalSn: purchaseOrder.SerialNumber,
}
stockList = append(stockList, stockCommodity)
}
err := gdb.Debug().Create(&stockList).Error
if err != nil {
logger.Errorf("create stock commodity err:", err)
return err
}
return nil
}