mh_goadmin_server/app/admin/models/purchase.go

1998 lines
69 KiB
Go
Raw Normal View History

package models
import (
"errors"
"fmt"
orm "go-admin/common/global"
"go-admin/logger"
"gorm.io/gorm"
"math/rand"
2024-02-23 10:06:21 +00:00
"sync"
"time"
)
const (
ErpPurchaseOrderUnAudit = 1 // 待审核
ErpPurchaseOrderWaitInventory = 2 // 待入库
ErpPurchaseOrderWaitReject = 3 // 待退货
ErpPurchaseOrderFinished = 4 // 已完成
ErpPurchaseOrderEnd = 5 // 已终止
ErpPurchaseOrderInInventory = 6 // 入库中,部分入库
ErpPurchaseOrderInReject = 7 // 退货中,部分退货
ErpProcureOrder = "procure" // 采购入库订单
ErpRejectOrder = "reject" // 采购退货订单
2024-02-23 10:06:21 +00:00
ErpDemandStateWait = 1 // 待采购
ErpDemandStateFinish = 2 // 完成采购
)
// ErpPurchaseOrder 采购订单表
type ErpPurchaseOrder struct {
Model
SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号
PurchaseType string `json:"purchase_type"` // 类型:procure-采购 reject-退货
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
2024-02-23 10:06:21 +00:00
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
MakerTime time.Time `json:"maker_time"` // 制单时间
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
MakerName string `json:"maker_name"` // 制单人名称
AuditTime time.Time `json:"audit_time"` // 审核时间
AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id
AuditorName string `json:"auditor_name"` // 审核人名称
State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
RejectedPurchaseOrderId uint32 `json:"rejected_purchase_order_id"` // 退货采购订单id
ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式/收款方式id
ErpCashierName string `json:"erp_cashier_name"` // 付款方式/收款方式名称
AccountHolder string `json:"account_holder"` // 收款人
OpeningBank string `json:"opening_bank"` // 开户行
BankAccount string `json:"bank_account"` // 银行卡号
2024-02-23 10:06:21 +00:00
DeliveryTime string `json:"delivery_time"` // 交货日期2024-02-23
Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"`
}
// ErpPurchaseCommodity 采购订单商品表
type ErpPurchaseCommodity struct {
Model
2024-02-23 10:06:21 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 采购订单id
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
RetailPrice uint32 `json:"retail_price"` // 指导零售价
Count uint32 `json:"count"` // 计划采购数量
Price float64 `json:"price"` // 计划采购单价
Amount float64 `json:"amount"` // 计划采购金额
Remark string `json:"remark"` // 备注
RejectedPrice float64 `json:"rejected_price"` // 计划退货单价
RejectedCount uint32 `json:"rejected_count"` // 计划退货数量
RejectedAmount float64 `json:"rejected_amount"` // 计划退货金额
InventoryCount int32 `json:"inventory_count"` // 入库数量(=执行数量)
ExecutionCount uint32 `json:"execute_count" gorm:"-"` // 执行数量
ExecutionPrice float64 `json:"execute_price" gorm:"-"` // 平均采购单价
ExecutionEmployeePrice float64 `json:"execute_employee_price" gorm:"-"` // 平均员工成本价
ExecutionAmount float64 `json:"execute_amount" gorm:"-"` // 执行金额
}
// ErpPurchaseInventory 采购入库执行信息
type ErpPurchaseInventory struct {
Model
2024-02-23 10:06:21 +00:00
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id
ErpPurchaseCommodityId uint32 `json:"erp_purchase_commodity_id" gorm:"index"` // 采购订单商品表id
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
Count uint32 `json:"count"` // 执行数量
ImplementationPrice float64 `json:"implementation_price"` // 执行单价
Amount float64 `json:"amount"` // 执行金额
EmployeePrice float64 `json:"employee_price"` // 员工成本价
}
type ErpPurchaseCreateReq struct {
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型procure-采购 reject-退货
PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号
2024-02-23 10:06:21 +00:00
StoreId uint32 `json:"store_id"` // 门店id
DeliveryAddress string `json:"delivery_address"` // 交货地址
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式
AccountHolder string `json:"account_holder"` // 收款人
2024-02-23 10:06:21 +00:00
OpeningBank string `json:"opening_bank" ` // 开户行
BankAccount string `json:"bank_account" ` // 银行卡号
DeliveryTime string `json:"delivery_time" ` // 交货日期
Remark string `json:"remark"` // 备注
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodities" binding:"required"` // 采购商品信息
}
type ErpPurchaseEditReq struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型procure-采购 reject-退货
PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号
StoreId uint32 `json:"store_id" binding:"required"` // 门店id
DeliveryAddress string `json:"delivery_address" binding:"required"` // 交货地址
2024-02-23 10:06:21 +00:00
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 供应商id
ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式
AccountHolder string `json:"account_holder"` // 收款人
OpeningBank string `json:"opening_bank" validate:"required"` // 开户行
BankAccount string `json:"bank_account" validate:"required"` // 银行卡号
DeliveryTime string `json:"delivery_time" binding:"required"` // 交货日期
Remark string `json:"remark"` // 备注
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodities" binding:"required"` // 采购商品信息
}
type ErpPurchaseOrderListReq struct {
SerialNumber string `json:"serial_number"` // 单据编号
PurchaseType string `json:"purchase_type"` // 采购类型procure-采购 reject-退货
StoreId uint32 `json:"store_id"` // 门店id
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
State uint32 `json:"state"` // 状态1-待审核 2-待入库 3-待退货 4-已完成
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
type ErpPurchaseOrderListResp struct {
List []ErpPurchaseOrder `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
type ErpPurchaseDetailReq struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
}
// ErpPurchaseInventoryReq 入库(退货)入参;执行(入库/退货)入参
type ErpPurchaseInventoryReq struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id
2024-02-23 10:06:21 +00:00
PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货
Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息
}
// ErpPurchaseAuditReq 审核采购订单入参
type ErpPurchaseAuditReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核
}
// ErpPurchaseTerminateReq 终止采购入参
type ErpPurchaseTerminateReq struct {
SerialNumber string `json:"serial_number" binding:"required"` // 单据编号
}
// ErpPurchaseExecuteResp 执行(入库/退货)出参
type ErpPurchaseExecuteResp struct {
2024-02-23 10:06:21 +00:00
List []ExecuteData `json:"list"`
Total int `json:"total"` // 总条数
}
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"` // 员工成本价
}
type ErpPurchaseDemand struct {
Model
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号
ErpCommodityName string `json:"erp_commodity_name" gorm:"index"` // 商品名称
StoreId uint32 `json:"store_id"` // 门店id
StoreName string `json:"store_name"` // 门店名称
Count uint32 `json:"count"` // 需采购数量
State uint32 `json:"state"` // 1-待采购 2-已采购
MakerId uint32 `json:"maker_id"` // 制单人id
PurchaserId uint32 `json:"purchaser_id"` // 采购人id
FinishTime *time.Time `json:"finish_time"` // 完成采购时间
Remark string `json:"remark"` // 备注
}
type ErpPurchaseDemandRecord struct {
Model
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
StoreId uint32 `json:"store_id" binding:"required"` // 门店id
StoreName string `json:"store_name" binding:"required"` // 门店名称
Count uint32 `json:"count"` // 数量
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
State uint32 `json:"state"` // 1-待采购 2-已采购
}
type GetErpPurchaseDemandReq struct {
ErpCategoryId uint32 `json:"erp_category_id" binding:"required"` // 商品分类id
HideFlag string `json:"hide_flag"` // 隐藏标记默认关闭ON-开启隐藏无采购需求的商品OFF-关闭,展示所有
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示数据条数
IsExport uint32 `json:"is_export"` // 1-导出
}
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"` // 需采购总金额
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"`
}
type GetErpPurchaseDemandResp struct {
List []DemandData `json:"list"`
Total int64 `json:"total"` // 数据总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ExportUrl string `json:"export_url"` // 文件路径
}
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"`
}
type FinishErpPurchaseDemandReq struct {
ErpCommodityID uint32 `json:"erp_commodity_id" binding:"required"` // 商品id
}
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")
if m.SerialNumber != "" {
qs = qs.Where("serial_number=?", m.SerialNumber)
} else {
if m.PurchaseType != "" {
qs = qs.Where("purchase_type=?", m.PurchaseType)
}
if m.StoreId != 0 {
qs = qs.Where("store_id=?", m.StoreId)
}
if m.ErpSupplierId != 0 {
qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId)
}
if m.State != 0 {
qs = qs.Where("state=?", m.State)
}
if m.AuditTimeStart != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
qs = qs.Where("audit_time > ?", parse)
}
if m.AuditTimeEnd != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("erpPurchaseOrderList err:", err)
return nil, err
}
parse = parse.AddDate(0, 0, 1)
qs = qs.Where("audit_time < ?", parse)
}
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
resp.Total = int(count)
var orders []ErpPurchaseOrder
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
resp.List = orders
return resp, nil
}
// NewErpPurchaseSn 生成采购订单号
func NewErpPurchaseSn() string {
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create sn err")
return ""
}
random := rand.Int31n(9999) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE serial_number='%s'", sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
}
max++
}
}
func ErpPurchaseCommodityListPerfectInfo(purchaseCommodities []ErpPurchaseCommodity) error {
commodityIds := make([]uint32, 0, len(purchaseCommodities))
for i, _ := range purchaseCommodities {
commodityIds = append(commodityIds, purchaseCommodities[i].ID)
}
commodityMap, err := GetErpCommodityMap(commodityIds)
if err != nil {
logger.Error("purchase commodities err:", logger.Field("err", err))
return err
}
for i, _ := range purchaseCommodities {
v, ok := commodityMap[purchaseCommodities[i].ErpCommodityId]
if ok {
purchaseCommodities[i].CommoditySerialNumber = v.SerialNumber
purchaseCommodities[i].IMEIType = v.IMEIType
//purchaseCommodities[i].IMEI = v.IMEI
purchaseCommodities[i].ErpCommodityName = v.Name
if purchaseCommodities[i].Count != 0 {
2024-02-23 10:06:21 +00:00
purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price
}
if purchaseCommodities[i].RejectedCount != 0 {
2024-02-23 10:06:21 +00:00
purchaseCommodities[i].RejectedAmount = float64(purchaseCommodities[i].RejectedCount) * purchaseCommodities[i].RejectedPrice
}
}
}
return nil
}
// IdInit 添加商户和供应商信息
func (m *ErpPurchaseOrder) IdInit() error {
if m.StoreId != 0 {
store, err := GetStore(m.StoreId)
if err != nil {
logger.Error("get store err:", logger.Field("err", err))
return err
}
m.StoreName = store.Name
}
if m.ErpSupplierId != 0 {
supplier, err := GetErpSupplier(m.ErpSupplierId)
if err != nil {
logger.Error("get supplier err:", logger.Field("err", err))
return err
}
m.ErpSupplierName = supplier.Name
}
if m.ErpCashierId != 0 {
cashier, err := GetAccountDetail(int(m.ErpCashierId))
if err != nil {
logger.Error("get cashier err:", logger.Field("err", err))
return err
}
m.ErpCashierName = cashier.Name
}
return nil
}
// GetPurchaseInventorySn 生成入库编号
func GetPurchaseInventorySn() string {
count := 0
for {
if count > 5 {
return ""
}
nowTime := time.Now()
sn := nowTime.Format("060102")
sn += fmt.Sprintf("%d", nowTime.Unix()%100)
rand.Seed(nowTime.UnixNano())
sn += fmt.Sprintf("%d", rand.Int31n(100))
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_inventory WHERE serial_number='%s'", sn))
if err != nil {
logger.Error("sn err:", logger.Field("err", err))
count++
continue
}
if err == nil && !exist {
return sn
}
return ""
}
}
// CreateErpPurchaseOrder 新增采购订单
func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
var err error
nowTime := time.Now()
purchaseOrder := &ErpPurchaseOrder{}
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgr" + NewErpPurchaseSn(),
PurchaseType: req.PurchaseType,
StoreId: req.StoreId,
ErpSupplierId: req.ErpSupplierId,
MakerTime: nowTime,
2024-02-23 10:06:21 +00:00
HandlerId: req.HandlerId,
HandlerName: req.HandlerName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpPurchaseOrderUnAudit, // 1-待审核
ErpCashierId: req.ErpCashierId,
AccountHolder: req.AccountHolder,
OpeningBank: req.OpeningBank,
BankAccount: req.BankAccount,
DeliveryTime: req.DeliveryTime,
}
err = purchaseOrder.IdInit()
} else if req.PurchaseType == ErpRejectOrder { // 采购退货订单
2024-02-23 10:06:21 +00:00
if req.PurchaseOrderSn == "" {
return nil, errors.New("新建失败:采购退货订单号为空")
}
var erpPurchaseOrder ErpPurchaseOrder
err = orm.Eloquent.Table("erp_purchase_order").Where("serial_number=?", req.PurchaseOrderSn).Find(&erpPurchaseOrder).Error
if err != nil {
logger.Error("purchase order err:", logger.Field("err", err))
return nil, err
}
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgt" + NewErpPurchaseSn(),
PurchaseType: req.PurchaseType,
StoreId: erpPurchaseOrder.StoreId,
ErpSupplierId: erpPurchaseOrder.ErpSupplierId,
MakerTime: nowTime,
2024-02-23 10:06:21 +00:00
HandlerId: req.HandlerId,
HandlerName: req.HandlerName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpPurchaseOrderUnAudit, // 1-待审核
ErpCashierId: req.ErpCashierId,
}
err = purchaseOrder.IdInit()
} else {
logger.Errorf("purchase_type err:", req.PurchaseType)
return nil, errors.New("操作失败:采购类型有误")
}
if err != nil {
logger.Error("info err:", logger.Field("err", err))
return nil, err
}
err = ErpPurchaseCommodityListPerfectInfo(req.ErpPurchaseCommodities)
if err != nil {
logger.Error("info err:", logger.Field("err", err))
return nil, err
}
begin := orm.Eloquent.Begin()
err = begin.Create(purchaseOrder).Error
if err != nil {
begin.Rollback()
logger.Error("create purchase order err:", logger.Field("err", err))
return nil, err
}
for i, _ := range req.ErpPurchaseCommodities {
req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = purchaseOrder.ID
req.ErpPurchaseCommodities[i].InventoryCount = 0 // todo 数量待核实
err = begin.Create(&req.ErpPurchaseCommodities[i]).Error
if err != nil {
begin.Rollback()
logger.Error("create purchase commodity err:", logger.Field("err", err))
return nil, err
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit purchase commodity err:", logger.Field("err", err))
return nil, err
}
return purchaseOrder, nil
}
// EditErpPurchaseOrder 编辑采购订单
func EditErpPurchaseOrder(req *ErpPurchaseEditReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
// 查询订单信息
var purchaseOrder ErpPurchaseOrder
err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
if err != nil {
logger.Error("purchase order err:", logger.Field("err", err))
return nil, err
}
if purchaseOrder.State != ErpPurchaseOrderUnAudit { // 只有待审核的订单才能编辑
return nil, errors.New("订单不是待审核状态")
}
begin := orm.Eloquent.Begin()
// 1-更新采购订单信息
purchaseOrder.StoreId = req.StoreId
purchaseOrder.ErpSupplierId = req.ErpSupplierId
2024-02-23 10:06:21 +00:00
purchaseOrder.HandlerId = req.HandlerId
purchaseOrder.HandlerName = req.HandlerName
purchaseOrder.MakerId = uint32(sysUser.UserId)
purchaseOrder.MakerName = sysUser.NickName
purchaseOrder.ErpCashierId = req.ErpCashierId
purchaseOrder.AccountHolder = req.AccountHolder
purchaseOrder.OpeningBank = req.OpeningBank
purchaseOrder.BankAccount = req.BankAccount
purchaseOrder.DeliveryTime = req.DeliveryTime
err = purchaseOrder.IdInit()
if err != nil {
logger.Error("purchase IdInit err:", logger.Field("err", err))
return nil, err
}
err = begin.Model(&ErpPurchaseOrder{}).Where("id = ?", req.ErpPurchaseOrderId).Updates(purchaseOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order err:", logger.Field("err", err))
return nil, err
}
// 2-更新采购订单商品表
err = updatePurchaseCommodityData(begin, req.ErpPurchaseOrderId, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_purchase_commodity err:", logger.Field("err", err))
return nil, err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return nil, err
}
return &purchaseOrder, nil
}
// updatePurchaseCommodityData 更新采购订单商品信息
func updatePurchaseCommodityData(gdb *gorm.DB, orderId uint32, req *ErpPurchaseEditReq) error {
// 查询现有的零售订单信息
var commodities []ErpPurchaseCommodity
err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error
if err != nil {
logger.Error("query erp_purchase_commodity err:", logger.Field("err", err))
return err
}
var newCommodities []ErpPurchaseCommodity
var deletedCommodities []ErpPurchaseCommodity
var matchingCommodities []ErpPurchaseCommodity
// 找到新增的商品
for i, reqCommodity := range req.ErpPurchaseCommodities {
// 订单商品表信息添加零售订单id
req.ErpPurchaseCommodities[i].ErpPurchaseOrderId = orderId
var found bool
for _, dbCommodity := range commodities {
if reqCommodity.ErpCommodityId == dbCommodity.ErpCommodityId {
found = true
break
}
}
if !found {
newCommodities = append(newCommodities, reqCommodity)
}
}
// 找到删除的商品
for _, dbCommodity := range commodities {
var found bool
for _, reqCommodity := range req.ErpPurchaseCommodities {
if reqCommodity.ID == dbCommodity.ID {
found = true
// 找到匹配的商品,加入匹配列表
matchingCommodities = append(matchingCommodities, reqCommodity)
break
}
}
if !found {
deletedCommodities = append(deletedCommodities, dbCommodity)
}
}
// 2-更新商品订单信息-更新
for _, commodity := range matchingCommodities {
if err := gdb.Model(&ErpPurchaseCommodity{}).Where("id = ?", commodity.ID).Updates(commodity).Error; err != nil {
logger.Error("更新商品订单信息-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 2-更新商品订单信息-新增
if len(newCommodities) != 0 {
err = gdb.Create(&newCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
//2-更新商品订单信息-删除
if len(deletedCommodities) != 0 {
err = gdb.Delete(&deletedCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}
// InventoryErpPurchase 采购订单入库
func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error {
err := checkPurchaseInventory(req)
if err != nil {
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
return err
}
begin := orm.Eloquent.Begin()
for _, v := range req.Inventories {
2024-02-23 10:06:21 +00:00
v.SerialNumber = GetPurchaseInventorySn()
// 更新采购商品表的执行数量
2024-02-23 10:06:21 +00:00
// todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息可能采购价不同需要区分入库的是哪一条(已修改)
err = begin.Model(&ErpPurchaseCommodity{}).
2024-02-23 10:06:21 +00:00
Where("id = ?", v.ErpPurchaseCommodityId).
UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error
if err != nil {
begin.Rollback()
logger.Error("update inventory count err:", logger.Field("err", err))
return err
}
// 新建采购入库记录
err = begin.Create(&v).Error
if err != nil {
begin.Rollback()
logger.Error("create erp inventory commodity err:", logger.Field("err", err))
return err
}
2024-02-23 10:06:21 +00:00
}
// 查询采购订单信息
var purchaseOrder ErpPurchaseOrder
err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error
if err != nil {
logger.Error("purchase order err:", logger.Field("err", err))
return err
}
// 更新库存信息表
if purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单
err = InventoryErpPurchaseUpdateStock(begin, req, purchaseOrder)
} else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单
err = InventoryErpPurchaseUpdateRejectStock(begin, req, purchaseOrder)
} else {
return errors.New("订单类型有误")
}
if err != nil {
begin.Rollback()
logger.Error("update stock err:", logger.Field("err", err))
return err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return err
}
return nil
}
2024-02-23 10:06:21 +00:00
// InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息
func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error {
// 遍历采购入库商品信息
var stockList []ErpStockCommodity
for _, v := range req.Inventories {
commodityInfo, err := GetCommodity(v.ErpCommodityId)
if err != nil {
logger.Errorf("GetCommodity err:", err)
return err
}
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d",
purchaseOrder.StoreId, v.ErpCommodityId))
if err != nil {
logger.Errorf("exist err:", err)
return err
}
if exist {
err = gdb.Exec(fmt.Sprintf(
"UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;",
v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error
if err != nil {
logger.Errorf("update stock err:", err)
return err
}
} else {
stock := &ErpStock{
StoreId: purchaseOrder.StoreId,
StoreName: purchaseOrder.StoreName,
ErpCommodityId: v.ErpCommodityId,
ErpCommodityName: v.ErpCommodityName,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
CommoditySerialNumber: v.CommoditySerialNumber,
IMEIType: v.IMEIType,
RetailPrice: commodityInfo.RetailPrice,
MinRetailPrice: commodityInfo.MinRetailPrice,
Count: v.Count,
DispatchCount: 0,
}
err = gdb.Create(stock).Error
if err != nil {
logger.Errorf("create stock err:", err)
return err
}
}
nowTime := time.Now()
stockCommodity := ErpStockCommodity{
StoreId: purchaseOrder.StoreId,
StoreName: purchaseOrder.StoreName,
ErpCommodityId: v.ErpCommodityId,
ErpCommodityName: v.ErpCommodityName,
CommoditySerialNumber: v.CommoditySerialNumber,
ErpCategoryId: commodityInfo.ErpCategoryId,
ErpCategoryName: commodityInfo.ErpCategoryName,
ErpSupplierId: purchaseOrder.ErpSupplierId,
ErpSupplierName: purchaseOrder.ErpSupplierName,
StaffCostPrice: uint32(v.EmployeePrice - v.ImplementationPrice),
WholesalePrice: uint32(v.ImplementationPrice),
State: 1,
StorageType: 1,
FirstStockTime: nowTime,
StockTime: nowTime,
Count: v.Count,
ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码
IMEIType: v.IMEIType,
IMEI: v.IMEI,
Remark: "",
MemberDiscount: commodityInfo.MemberDiscount,
MinRetailPrice: commodityInfo.MinRetailPrice,
RetailPrice: commodityInfo.RetailPrice,
}
stockList = append(stockList, stockCommodity)
}
err := gdb.Debug().Create(&stockList).Error
if err != nil {
logger.Errorf("create stock commodity err:", err)
return err
}
return nil
}
// InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息
func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error {
for i, _ := range req.Inventories {
if req.Inventories[i].IMEIType == 2 { // 串码商品
if req.Inventories[i].IMEI == "" {
return errors.New("串码为空")
}
// 判断该串码商品是否已经销售
var stockCommodityInfo ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[i].IMEI).
Find(&stockCommodityInfo).Error
if err != nil {
logger.Error("Inventory RejectStock query commodities err:", logger.Field("err", err))
return err
}
if stockCommodityInfo.State == SoldOut {
return fmt.Errorf("商品[%s]已经消息,不能退货", stockCommodityInfo.ErpCommodityName)
} else if stockCommodityInfo.State == OnSale {
return fmt.Errorf("商品[%s]在销售锁定中,不能退货", stockCommodityInfo.ErpCommodityName)
}
err = gdb.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[i].IMEI).
Update("state", PurchaseReturn).Error // 状态更新为采购退货
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
purchaseOrder.StoreId, req.Inventories[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
} else { // 非串码商品
var stockCommodity []ErpStockCommodity
// 通过门店id商品id查找状态为1-在库的非串码商品
err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
"and state = ? and imei_type = ?", req.Inventories[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1).
Order("id DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil {
return errors.New("RetailTypeRejected find no stock commodity")
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID).
Update("state", PurchaseReturn).Error // 状态更新为采购退货
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
purchaseOrder.StoreId, req.Inventories[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
}
}
return nil
}
// 校验入参数据,执行数量是否超过总数;串码商品的串码是否重复
func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error {
// 查询现有的零售订单信息
var commodities []ErpPurchaseCommodity
err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id = ?", req.ErpPurchaseOrderId).Find(&commodities).Error
if err != nil {
logger.Error("query erp_purchase_commodity err:", logger.Field("err", err))
return err
}
2024-02-23 10:06:21 +00:00
countMap := make(map[uint32]uint32)
for _, inventory := range req.Inventories {
2024-02-23 10:06:21 +00:00
countMap[inventory.ErpCommodityId] += inventory.Count
// 如果该商品是串码商品,判断其串码是否会重复
if inventory.IMEI != "" {
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET(%s, imei) > 0", inventory.IMEI))
if err != nil {
logger.Error("exist sn err")
}
if exist {
return fmt.Errorf("串码重复[%s]", inventory.IMEI)
}
}
}
// 入库的商品信息有误,不在之前的商品列表中
for commodityID := range countMap {
found := false
for _, commodity := range commodities {
if commodity.ErpCommodityId == commodityID {
found = true
break
}
}
if !found {
return fmt.Errorf("商品编号[%d]不属于该采购订单", commodityID)
}
}
// 本次入库的数量超出该商品未入库数量
for _, commodity := range commodities {
if inventoryCount, ok := countMap[commodity.ErpCommodityId]; ok {
2024-02-23 10:06:21 +00:00
if req.PurchaseType == ErpProcureOrder {
if commodity.Count-uint32(commodity.InventoryCount) < inventoryCount {
return fmt.Errorf("本次入库商品[%s]数量[%d]超出该商品未入库数量[%d]", commodity.ErpCommodityName,
inventoryCount, int32(commodity.Count)-commodity.InventoryCount)
}
} else if req.PurchaseType == ErpRejectOrder {
if commodity.RejectedCount-uint32(commodity.InventoryCount) < inventoryCount {
return fmt.Errorf("本次退货商品[%s]数量[%d]超出该商品未退货数量[%d]", commodity.ErpCommodityName,
inventoryCount, int32(commodity.Count)-commodity.InventoryCount)
}
}
}
}
return nil
}
// ExecuteErpPurchase 执行(入库/退货)
func ExecuteErpPurchase(req *ErpPurchaseInventoryReq) (*ErpPurchaseExecuteResp, error) {
err := checkPurchaseInventory(req)
if err != nil {
logger.Error("checkPurchaseInventoryReq err:", logger.Field("err", err))
return nil, err
}
resp := &ErpPurchaseExecuteResp{
List: make([]ExecuteData, 0),
}
for _, inventory := range req.Inventories {
if inventory.IMEIType == 2 {
2024-02-23 10:06:21 +00:00
// 如果是串码商品,根据 Count 拆分成对应数量的数据
for i := 0; i < int(inventory.Count); i++ {
imei := "" // 默认退货单执行时不需要串码
if inventory.PurchaseType == ErpProcureOrder { // 采购单
// 调用函数B生成商品串码
imei, err = generateIMEI(inventory.ErpCommodityId)
if err != nil {
return nil, err
}
}
// 将拆分后的商品信息添加到执行响应中
resp.List = append(resp.List, ExecuteData{
ErpPurchaseOrderId: inventory.ErpPurchaseOrderId,
ErpCommodityId: inventory.ErpCommodityId,
ErpCommodityName: inventory.ErpCommodityName,
CommoditySerialNumber: inventory.CommoditySerialNumber,
IMEIType: inventory.IMEIType,
IMEI: imei,
Count: 1,
ImplementationPrice: inventory.ImplementationPrice,
EmployeePrice: inventory.EmployeePrice,
})
}
} else if inventory.IMEIType == 1 {
// 如果是非串码商品只需拆分为1条数据
resp.List = append(resp.List, ExecuteData{
ErpPurchaseOrderId: inventory.ErpPurchaseOrderId,
ErpCommodityId: inventory.ErpCommodityId,
ErpCommodityName: inventory.ErpCommodityName,
CommoditySerialNumber: inventory.CommoditySerialNumber,
IMEIType: inventory.IMEIType,
IMEI: "",
Count: inventory.Count,
ImplementationPrice: inventory.ImplementationPrice,
EmployeePrice: inventory.EmployeePrice,
})
}
}
2024-02-23 10:06:21 +00:00
resp.Total = len(resp.List)
return resp, nil
}
2024-02-23 10:06:21 +00:00
// 生成串码
func generateIMEI(commodityId uint32) (string, error) {
commodity, err := GetCommodity(commodityId)
if err != nil {
return "", err
}
return GenerateSerialCode(commodity.ErpCategoryId)
}
2024-02-23 10:06:21 +00:00
// CreateErpPurchaseDemand 创建采购需求单
func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error {
var demandInfo ErpPurchaseDemand
var demandList []ErpPurchaseDemand
demandInfo.ErpCommodityId = req.ErpCommodityID
demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber
demandInfo.ErpCommodityName = req.ErpCommodityName
demandInfo.Remark = req.Remark
demandInfo.State = ErpDemandStateWait // 待采购
for _, v := range req.List {
demandInfo.StoreId = v.StoreID
demandInfo.StoreName = v.StoreName
demandInfo.Count = v.NeedCount
demandInfo.MakerId = uint32(sysUser.UserId)
demandList = append(demandList, demandInfo)
}
begin := orm.Eloquent.Begin()
// 查询当前表格,有记录则更新,没有则插入新记录
for _, v := range demandList {
var demand ErpPurchaseDemand
err := orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? and store_id = ? and state = 1",
v.ErpCommodityId, v.StoreId).Find(&demand).Error
if err != nil {
logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
return err
}
if demand.StoreId != 0 { // 有记录
if demand.Count == v.Count { // 值没变则不更新
continue
} else {
err = begin.Model(&ErpPurchaseDemand{}).Where("erp_commodity_id = ? and store_id = ? and state = 1",
v.ErpCommodityId, v.StoreId).Updates(v).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order err:", logger.Field("err", err))
return err
}
}
} else { // 无记录,新建
err = begin.Create(&v).Error
if err != nil {
logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
return err
}
}
}
err := begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return err
}
return nil
}
// FinishErpPurchaseDemand 完成采购需求
func FinishErpPurchaseDemand(req *FinishErpPurchaseDemandReq, sysUser *SysUser) error {
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_demand WHERE erp_commodity_id='%d'",
req.ErpCommodityID))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return fmt.Errorf("商品编号[%d]的商品不在采购需求单中", req.ErpCommodityID)
}
// 批量更新状态
err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=?", req.ErpCommodityID).
Updates(map[string]interface{}{
"state": ErpDemandStateFinish,
"finish_time": time.Now(),
"purchaser_id": sysUser.UserId,
}).Error
if err != nil {
logger.Error("update err:", logger.Field("err", err))
return err
}
return nil
}
//// GetErpPurchaseDemand 获取采购需求
//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
// resp := &GetErpPurchaseDemandResp{
// PageIndex: req.PageIndex,
// PageSize: req.PageSize,
// }
// page := req.PageIndex - 1
// if page < 0 {
// page = 0
// }
// if req.PageSize == 0 {
// req.PageSize = 10
// }
//
// qs := orm.Eloquent.Debug().Table("erp_commodity")
// if req.ErpCategoryId != 0 {
// qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
// }
//
// var commodities []ErpCommodity
// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
// if err != nil && err != RecordNotFound {
// //logger.Error("erp commodity list err:", err)
// return resp, err
// }
//
// // 组合数据
// resp, err = convertToDemandResp(commodities)
//
// return resp, nil
//}
//
//func convertToDemandResp(commodities []ErpCommodity) (*GetErpPurchaseDemandResp, error) {
// resp := new(GetErpPurchaseDemandResp)
// var demandData DemandData
// var demandList []DemandData
//
// // 查询所有在线门店信息
// var stores []Store
// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
// if err != nil {
// logger.Error("stores err:", logger.Field("err", err))
// return nil, err
// }
//
// demandData.List = make([]struct {
// StoreID uint32 `json:"store_id"`
// StoreName string `json:"store_name"`
// LastMonthSales uint32 `json:"last_month_sales"`
// StockCount uint32 `json:"stock_count"`
// NeedCount uint32 `json:"need_count"`
// }, len(stores))
//
// var totalCount uint32 // 总需采购数量
//
// // 遍历所有商品
// for _, v := range commodities {
// // 初始化 NeedCount 为 0
// var totalNeedCount uint32
//
// for i, store := range stores {
// demandData.List[i].StoreID = store.ID
// demandData.List[i].StoreName = store.Name
//
// // 初始化 NeedCount 为 0
// demandData.List[i].NeedCount = 0
//
// // 设置商品相关信息
// demandData.ErpCommodityID = v.ID
// demandData.ErpCommoditySerialNumber = v.SerialNumber
// demandData.ErpCommodityName = v.Name
// demandData.ErpCategoryID = v.ErpCategoryId
// demandData.ErpCategoryName = v.ErpCategoryName
// demandData.RetailPrice = v.RetailPrice
// // 最近采购价
// demandData.LastWholesalePrice, _ = GetCommodityLastWholesalePrice(v.ID)
//
// // 查询采购需求单
// var demand []ErpPurchaseDemand
// err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? AND state = 1 AND store_id = ?",
// v.ID, store.ID).Find(&demand).Error
// if err != nil {
// logger.Error("query erp_purchase_demand err:", logger.Field("err", err))
// return nil, err
// }
//
// if len(demand) > 0 {
// totalNeedCount += demand[0].Count
// demandData.List[i].NeedCount = demand[0].Count
// }
//
// // 查询某个门店某个商品的库存情况
// demandData.List[i].StockCount, _ = GetCommodityStockByStoreId(v.ID, store.ID)
// // 查询某个门店某件商品的上月销售数量
// demandData.List[i].LastMonthSales, _ = GetCommodityLastMonthSalesByStoreId(v.ID, store.ID)
// }
// totalCount += totalNeedCount
// demandData.TotalCount = totalCount
// demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice
// demandList = append(demandList, demandData)
// }
// resp.List = demandList
//
// return resp, nil
//}
//
//// GetCommodityStockByStoreId 查询某个门店某个商品的库存情况
//func GetCommodityStockByStoreId(commodityId, storeId uint32) (uint32, error) {
// var count int64
// err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? and state = 1",
// commodityId, storeId).Count(&count).Error
// if err != nil {
// logger.Error("GetCommodityStockByStoreId count err:", logger.Field("err", err))
// return 0, err
// }
//
// return uint32(count), nil
//}
//
//// GetCommodityLastMonthSalesByStoreId 查询某个门店某件商品的上月销售数量
//func GetCommodityLastMonthSalesByStoreId(commodityId, storeId uint32) (uint32, error) {
// var lastMonthSales uint32
//
// // 获取当前时间
// now := time.Now()
// year, month, _ := now.Date()
// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
// lastDay := firstDay.AddDate(0, 1, -1)
//
// // 执行查询
// err := orm.Eloquent.Model(&ErpOrderCommodity{}).
// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
// Select("SUM(erp_order_commodity.count) AS last_month_sales").
// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
// "AND erp_order_commodity.created_at BETWEEN ? AND ?",
// HavePaid, commodityId, storeId, firstDay, lastDay).
// Scan(&lastMonthSales).Error
// if err != nil {
// logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err))
// return 0, err
// }
//
// return lastMonthSales, nil
//}
//
//// GetCommodityLastWholesalePrice 查询某个商品的最近采购价
//func GetCommodityLastWholesalePrice(commodityId uint32) (float64, error) {
// var implementationPrice float64
//
// // 执行查询
// err := orm.Eloquent.Table("erp_purchase_inventory").
// Select("implementation_price").
// Where("erp_commodity_id = ? AND purchase_type = ?", 167, "procure").
// Order("created_at DESC").
// Limit(1).
// Scan(&implementationPrice).Error
// if err != nil {
// logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err))
// return 0, err
// }
//
// return implementationPrice, nil
//}
// 222222222
//// GetErpPurchaseDemand 获取采购需求
//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
// resp := &GetErpPurchaseDemandResp{
// PageIndex: req.PageIndex,
// PageSize: req.PageSize,
// }
// page := req.PageIndex - 1
// if page < 0 {
// page = 0
// }
// if req.PageSize == 0 {
// req.PageSize = 10
// }
//
// qs := orm.Eloquent.Debug().Table("erp_commodity")
// if req.ErpCategoryId != 0 {
// qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
// }
//
// var commodities []ErpCommodity
// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
// if err != nil && err != RecordNotFound {
// return resp, err
// }
//
// // 批量查询门店信息
// stores, err := GetOnlineStores()
// if err != nil {
// return nil, err
// }
//
// // 批量查询商品信息
// demandDataList := make([]DemandData, 0, len(commodities))
// for _, v := range commodities {
// demandData, err := convertToDemandData(v, stores)
// if err != nil {
// return nil, err
// }
// demandDataList = append(demandDataList, demandData)
// }
//
// resp.List = demandDataList
//
// return resp, nil
//}
//
//// convertToDemandData 将商品转换为采购需求数据
//func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
// demandData := DemandData{
// ErpCommodityID: commodity.ID,
// ErpCommoditySerialNumber: commodity.SerialNumber,
// ErpCommodityName: commodity.Name,
// ErpCategoryID: commodity.ErpCategoryId,
// ErpCategoryName: commodity.ErpCategoryName,
// RetailPrice: commodity.RetailPrice,
// }
//
// // 批量查询最近采购价
// lastWholesalePrices, err := GetCommodityLastWholesalePrices(commodity.ID)
// if err != nil {
// return DemandData{}, err
// }
//
// for i, store := range stores {
// demandData.List = append(demandData.List, struct {
// StoreID uint32 `json:"store_id"`
// StoreName string `json:"store_name"`
// LastMonthSales uint32 `json:"last_month_sales"`
// StockCount uint32 `json:"stock_count"`
// NeedCount uint32 `json:"need_count"`
// }{
// StoreID: store.ID,
// StoreName: store.Name,
// })
//
// // 批量查询库存情况
// stockCounts, err := GetCommodityStocksByStoreID(commodity.ID, store.ID)
// if err != nil {
// return DemandData{}, err
// }
// demandData.List[i].StockCount = stockCounts[store.ID]
//
// // 批量查询上月销售数量
// lastMonthSales, err := GetCommodityLastMonthSales(commodity.ID, store.ID)
// if err != nil {
// return DemandData{}, err
// }
// demandData.List[i].LastMonthSales = lastMonthSales
//
// // 设置最近采购价
// demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]
// }
//
// return demandData, nil
//}
//
//// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
//func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
// // 查询最近采购价
// var prices []struct {
// CommodityID uint32
// Price float64
// }
// err := orm.Eloquent.Table("erp_purchase_inventory").
// Select("erp_commodity_id, implementation_price AS price").
// Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
// Group("erp_commodity_id").
// Order("created_at DESC").
// Find(&prices).Error
// if err != nil {
// return nil, err
// }
//
// // 构建结果
// result := make(map[uint32]float64)
// for _, p := range prices {
// result[p.CommodityID] = p.Price
// }
// return result, nil
//}
//
//// GetCommodityStocksByStoreID 批量查询商品的库存情况
//func GetCommodityStocksByStoreID(commodityID, storeID uint32) (map[uint32]uint32, error) {
// // 查询库存情况
// var stocks []struct {
// StoreID uint32
// CommodityID uint32
// StockCount uint32
// }
// err := orm.Eloquent.Table("erp_stock_commodity").
// Select("store_id, erp_commodity_id, COUNT(*) AS stock_count").
// Where("erp_commodity_id IN (?) AND store_id = ? AND state = 1", commodityID, storeID).
// Group("store_id, erp_commodity_id").
// Find(&stocks).Error
// if err != nil {
// return nil, err
// }
//
// // 构建结果
// result := make(map[uint32]uint32)
// for _, s := range stocks {
// result[s.StoreID] = s.StockCount
// }
// return result, nil
//}
//
//// GetCommodityLastMonthSales 批量查询商品的上月销售数量
//func GetCommodityLastMonthSales(commodityID, storeID uint32) (uint32, error) {
// // 获取上个月的时间范围
// firstDay, lastDay := GetLastMonthRange()
//
// // 查询上月销售数量
// var lastMonthSales struct {
// Sales uint32
// }
// err := orm.Eloquent.Table("erp_order_commodity").
// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
// "AND erp_order_commodity.created_at BETWEEN ? AND ?",
// HavePaid, commodityID, storeID, firstDay, lastDay).
// Select("SUM(erp_order_commodity.count) AS sales").
// Scan(&lastMonthSales).Error
// if err != nil {
// return 0, err
// }
//
// return lastMonthSales.Sales, nil
//}
//
//// GetLastMonthRange 获取上个月的时间范围
//func GetLastMonthRange() (time.Time, time.Time) {
// now := time.Now()
// year, month, _ := now.Date()
// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
// lastDay := firstDay.AddDate(0, 1, -1)
// return firstDay, lastDay
//}
//
//// GetOnlineStores 查询所有在线门店信息
//func GetOnlineStores() ([]Store, error) {
// var stores []Store
// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
// if err != nil {
// return nil, err
// }
// return stores, nil
//}
// 3333
//// GetErpPurchaseDemand 获取采购需求
//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
// resp := &GetErpPurchaseDemandResp{
// PageIndex: req.PageIndex,
// PageSize: req.PageSize,
// }
// page := req.PageIndex - 1
// if page < 0 {
// page = 0
// }
// if req.PageSize == 0 {
// req.PageSize = 10
// }
//
// qs := orm.Eloquent.Debug().Table("erp_commodity")
// if req.ErpCategoryId != 0 {
// qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
// }
//
// var commodities []ErpCommodity
// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error
// if err != nil && err != RecordNotFound {
// return resp, err
// }
//
// // 批量查询门店信息
// stores, err := GetOnlineStores()
// if err != nil {
// return nil, err
// }
//
// // 并行查询需求数据
// var wg sync.WaitGroup
// demandDataList := make([]DemandData, len(commodities))
//
// for i, v := range commodities {
// wg.Add(1)
// go func(index int, commodity ErpCommodity) {
// defer wg.Done()
// demandData, err := convertToDemandData(commodity, stores)
// if err != nil {
// // Handle error
// return
// }
// demandDataList[index] = demandData
// }(i, v)
// }
//
// wg.Wait()
//
// resp.List = demandDataList
//
// return resp, nil
//}
//
//// convertToDemandData 将商品转换为采购需求数据
//func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
// demandData := DemandData{
// ErpCommodityID: commodity.ID,
// ErpCommoditySerialNumber: commodity.SerialNumber,
// ErpCommodityName: commodity.Name,
// ErpCategoryID: commodity.ErpCategoryId,
// ErpCategoryName: commodity.ErpCategoryName,
// RetailPrice: commodity.RetailPrice,
// }
//
// // 并行查询最近采购价、库存情况、上月销售数量
// var wg sync.WaitGroup
// wg.Add(3)
//
// var lastWholesalePrices map[uint32]float64
// var stockCounts map[uint32]uint32
// var lastMonthSales uint32
// var err1, err2, err3 error
//
// go func() {
// defer wg.Done()
// lastWholesalePrices, err1 = GetCommodityLastWholesalePrices(commodity.ID)
// }()
//
// go func() {
// defer wg.Done()
// stockCounts, err2 = GetCommodityStocksByStoreID(commodity.ID, stores)
// }()
//
// go func() {
// defer wg.Done()
// lastMonthSales, err3 = GetCommodityLastMonthSales(commodity.ID, stores)
// }()
//
// wg.Wait()
//
// if err1 != nil || err2 != nil || err3 != nil {
// // Handle error
// return DemandData{}, err1
// }
//
// // 构建需求数据
// demandData.List = make([]struct {
// StoreID uint32 `json:"store_id"`
// StoreName string `json:"store_name"`
// LastMonthSales uint32 `json:"last_month_sales"`
// StockCount uint32 `json:"stock_count"`
// NeedCount uint32 `json:"need_count"`
// }, len(stores))
//
// for i, store := range stores {
// demandData.List[i].StoreID = store.ID
// demandData.List[i].StoreName = store.Name
//
// demandData.List[i].StockCount = stockCounts[store.ID]
// demandData.List[i].LastMonthSales = lastMonthSales
//
// // 设置最近采购价
// demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]
// }
//
// return demandData, nil
//}
//
//// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
//func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
// // 查询最近采购价
// var prices []struct {
// CommodityID uint32
// Price float64
// }
// err := orm.Eloquent.Table("erp_purchase_inventory").
// Select("erp_commodity_id, implementation_price AS price").
// Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
// Group("erp_commodity_id").
// Order("created_at DESC").
// Find(&prices).Error
// if err != nil {
// return nil, err
// }
//
// // 构建结果
// result := make(map[uint32]float64)
// for _, p := range prices {
// result[p.CommodityID] = p.Price
// }
// return result, nil
//}
//
//// GetCommodityStocksByStoreID 批量查询商品的库存情况
//func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) {
// // 并行查询库存情况
// var wg sync.WaitGroup
// wg.Add(len(stores))
//
// result := make(map[uint32]uint32)
//
// for _, store := range stores {
// go func(storeID uint32) {
// defer wg.Done()
// // 查询库存情况
// var stockCount int64
// err := orm.Eloquent.Table("erp_stock_commodity").
// Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID).
// Count(&stockCount).Error
// if err != nil {
// // Handle error
// return
// }
// result[storeID] = uint32(stockCount)
// }(store.ID)
// }
//
// wg.Wait()
//
// return result, nil
//}
//
//// GetCommodityLastMonthSales 批量查询商品的上月销售数量
//func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) {
// // 获取上个月的时间范围
// firstDay, lastDay := GetLastMonthRange()
//
// // 并行查询上月销售数量
// var wg sync.WaitGroup
// wg.Add(len(stores))
//
// var totalSales uint32
// var mu sync.Mutex // 用于保护 totalSales 的并发访问
//
// for _, store := range stores {
// go func(storeID uint32) {
// defer wg.Done()
// // 查询上月销售数量
// var sales uint32
// err := orm.Eloquent.Table("erp_order_commodity").
// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
// "AND erp_order_commodity.created_at BETWEEN ? AND ?",
// HavePaid, commodityID, storeID, firstDay, lastDay).
// Select("SUM(erp_order_commodity.count) AS sales").
// Scan(&sales).Error
// if err != nil {
// // Handle error
// return
// }
//
// // 累加销售数量
// mu.Lock()
// totalSales += sales
// mu.Unlock()
// }(store.ID)
// }
//
// wg.Wait()
//
// return totalSales, nil
//}
//
//// GetLastMonthRange 获取上个月的时间范围
//func GetLastMonthRange() (time.Time, time.Time) {
// now := time.Now()
// year, month, _ := now.Date()
// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
// lastDay := firstDay.AddDate(0, 1, -1)
// return firstDay, lastDay
//}
//
//// GetOnlineStores 查询所有在线门店信息
//func GetOnlineStores() ([]Store, error) {
// var stores []Store
// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
// if err != nil {
// return nil, err
// }
// return stores, nil
//}
// GetErpPurchaseDemand 获取采购需求
func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) {
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &GetErpPurchaseDemandResp{
PageIndex: page + 1,
PageSize: req.PageSize,
}
qs := orm.Eloquent.Debug().Table("erp_commodity")
if req.ErpCategoryId != 0 {
qs = qs.Where("erp_category_id=?", req.ErpCategoryId)
}
var count int64
if err := qs.Count(&count).Error; err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
var commodities []ErpCommodity
err := qs.Order("id DESC").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
resp.Total = count
return resp, nil
}
// convertToDemandData 将商品转换为采购需求数据
func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) {
demandData := DemandData{
ErpCommodityID: commodity.ID,
ErpCommoditySerialNumber: commodity.SerialNumber,
ErpCommodityName: commodity.Name,
ErpCategoryID: commodity.ErpCategoryId,
ErpCategoryName: commodity.ErpCategoryName,
RetailPrice: commodity.RetailPrice,
}
// 查询采购需求单
demands, err := GetCommodityPurchaseDemands(commodity.ID, stores)
if err != nil {
// Handle error
return DemandData{}, err
}
// 使用 WaitGroup 进行并行查询
var wg sync.WaitGroup
wg.Add(3)
var lastWholesalePrices map[uint32]float64
var stockCounts map[uint32]uint32
var lastMonthSales uint32
go func() {
defer wg.Done()
lastWholesalePrices, err = GetCommodityLastWholesalePrices(commodity.ID)
}()
go func() {
defer wg.Done()
stockCounts, err = GetCommodityStocksByStoreID(commodity.ID, stores)
}()
go func() {
defer wg.Done()
lastMonthSales, err = GetCommodityLastMonthSales(commodity.ID, stores)
}()
wg.Wait()
if err != nil {
// Handle error
return DemandData{}, err
}
var totalCount uint32 // 总需采购数量
// 构建需求数据
demandData.StoreList = make([]struct {
StoreID uint32 `json:"store_id"`
StoreName string `json:"store_name"`
LastMonthSales uint32 `json:"last_month_sales"`
StockCount uint32 `json:"stock_count"`
NeedCount uint32 `json:"need_count"`
}, len(stores))
for i, store := range stores {
demandData.StoreList[i].StoreID = store.ID
demandData.StoreList[i].StoreName = store.Name
demandData.StoreList[i].StockCount = stockCounts[store.ID]
demandData.StoreList[i].LastMonthSales = lastMonthSales
// 设置最近采购价
demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID]
// 设置采购需求量
for _, demand := range demands {
if demand.StoreId == store.ID {
demandData.StoreList[i].NeedCount = demand.Count
totalCount += demand.Count
break
}
}
}
demandData.TotalCount = totalCount
demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice
return demandData, nil
}
// GetCommodityPurchaseDemands 查询商品的采购需求单
func GetCommodityPurchaseDemands(commodityID uint32, stores []Store) ([]ErpPurchaseDemand, error) {
var wg sync.WaitGroup
var mu sync.Mutex
var demands []ErpPurchaseDemand
wg.Add(len(stores))
for _, store := range stores {
go func(storeID uint32) {
defer wg.Done()
var demand ErpPurchaseDemand
err := orm.Eloquent.Table("erp_purchase_demand").
Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", commodityID, storeID).
First(&demand).Error
if err != nil {
// Handle error
return
}
mu.Lock()
defer mu.Unlock()
demands = append(demands, demand)
}(store.ID)
}
wg.Wait()
return demands, nil
}
// GetCommodityLastWholesalePrices 批量查询商品的最近采购价
func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) {
// 查询最近采购价
var prices []struct {
CommodityID uint32
Price float64
}
err := orm.Eloquent.Table("erp_purchase_inventory").
Select("erp_commodity_id, implementation_price AS price").
Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure").
Group("erp_commodity_id").
Order("created_at DESC").
Find(&prices).Error
if err != nil {
return nil, err
}
// 构建结果
result := make(map[uint32]float64)
for _, p := range prices {
result[p.CommodityID] = p.Price
}
return result, nil
}
// GetCommodityStocksByStoreID 批量查询商品的库存情况
func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) {
// 并行查询库存情况
var wg sync.WaitGroup
wg.Add(len(stores))
result := make(map[uint32]uint32)
for _, store := range stores {
go func(storeID uint32) {
defer wg.Done()
// 查询库存情况
var stockCount int64
err := orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID).
Count(&stockCount).Error
if err != nil {
// Handle error
return
}
result[storeID] = uint32(stockCount)
}(store.ID)
}
wg.Wait()
return result, nil
}
// GetCommodityLastMonthSales 批量查询商品的上月销售数量
func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) {
// 获取上个月的时间范围
firstDay, lastDay := GetLastMonthRange()
// 并行查询上月销售数量
var wg sync.WaitGroup
wg.Add(len(stores))
var totalSales uint32
var mu sync.Mutex // 用于保护 totalSales 的并发访问
for _, store := range stores {
go func(storeID uint32) {
defer wg.Done()
// 查询上月销售数量
var sales uint32
err := orm.Eloquent.Table("erp_order_commodity").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id").
Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+
"AND erp_order_commodity.created_at BETWEEN ? AND ?",
HavePaid, commodityID, storeID, firstDay, lastDay).
Select("SUM(erp_order_commodity.count) AS sales").
Scan(&sales).Error
if err != nil {
// Handle error
return
}
// 保护 totalSales 的并发访问
mu.Lock()
defer mu.Unlock()
totalSales += sales
}(store.ID)
}
wg.Wait()
return totalSales, nil
}
// GetLastMonthRange 获取上个月的时间范围
func GetLastMonthRange() (time.Time, time.Time) {
now := time.Now()
year, month, _ := now.Date()
firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location())
lastDay := firstDay.AddDate(0, 1, -1)
return firstDay, lastDay
}
// GetOnlineStores 查询所有在线门店信息
func GetOnlineStores() ([]Store, error) {
var stores []Store
err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error
if err != nil {
return nil, err
}
return stores, nil
}
type Result struct {
TotalCount uint32 `gorm:"column:total_count"`
AvgImplementationPrice float64 `gorm:"column:avg_implementation_price"`
TotalAmount float64 `gorm:"column:total_amount"`
AvgEmployeePrice float64 `gorm:"column:avg_employee_price"`
}
// GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价
func GetTotalsAndAveragesByCommodityID(commodityID uint32) (Result, error) {
var result Result
err := orm.Eloquent.Table("erp_purchase_inventory").
Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+
"SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price").
Where("erp_commodity_id = ?", commodityID).
Scan(&result).Error
if err != nil {
return Result{}, err
}
return result, nil
}