mh_goadmin_server/app/admin/models/purchase.go

1998 lines
69 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

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

package models
import (
"errors"
"fmt"
orm "go-admin/common/global"
"go-admin/logger"
"gorm.io/gorm"
"math/rand"
"sync"
"time"
)
const (
ErpPurchaseOrderUnAudit = 1 // 待审核
ErpPurchaseOrderWaitInventory = 2 // 待入库
ErpPurchaseOrderWaitReject = 3 // 待退货
ErpPurchaseOrderFinished = 4 // 已完成
ErpPurchaseOrderEnd = 5 // 已终止
ErpPurchaseOrderInInventory = 6 // 入库中,部分入库
ErpPurchaseOrderInReject = 7 // 退货中,部分退货
ErpProcureOrder = "procure" // 采购入库订单
ErpRejectOrder = "reject" // 采购退货订单
ErpDemandStateWait = 1 // 待采购
ErpDemandStateFinish = 2 // 完成采购
)
// ErpPurchaseOrder 采购订单表
type ErpPurchaseOrder struct {
Model
SerialNumber string `json:"serial_number" gorm:"index"` // 单据编号
PurchaseType string `json:"purchase_type"` // 类型:procure-采购 reject-退货
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
MakerTime time.Time `json:"maker_time"` // 制单时间
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
MakerName string `json:"maker_name"` // 制单人名称
AuditTime time.Time `json:"audit_time"` // 审核时间
AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id
AuditorName string `json:"auditor_name"` // 审核人名称
State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止
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"` // 银行卡号
DeliveryTime string `json:"delivery_time"` // 交货日期2024-02-23
Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"`
}
// ErpPurchaseCommodity 采购订单商品表
type ErpPurchaseCommodity struct {
Model
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 采购订单id
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
RetailPrice 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
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"` // 采购退货订单号
StoreId uint32 `json:"store_id"` // 门店id
DeliveryAddress string `json:"delivery_address"` // 交货地址
HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id
HandlerName string `json:"handler_name"` // 经手人名称
ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id
ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式
AccountHolder string `json:"account_holder"` // 收款人
OpeningBank string `json:"opening_bank" ` // 开户行
BankAccount string `json:"bank_account" ` // 银行卡号
DeliveryTime string `json:"delivery_time" ` // 交货日期
Remark string `json:"remark"` // 备注
ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_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"` // 交货地址
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
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 {
List []ExecuteData `json:"list"`
Total int `json:"total"` // 总条数
}
type ExecuteData struct {
ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei"` // 商品串码
Count uint32 `json:"count"` // 数量
ImplementationPrice float64 `json:"implementation_price"` // 执行单价
EmployeePrice float64 `json:"employee_price"` // 员工成本价
}
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 {
purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price
}
if purchaseCommodities[i].RejectedCount != 0 {
purchaseCommodities[i].RejectedAmount = float64(purchaseCommodities[i].RejectedCount) * purchaseCommodities[i].RejectedPrice
}
}
}
return nil
}
// IdInit 添加商户和供应商信息
func (m *ErpPurchaseOrder) IdInit() error {
if m.StoreId != 0 {
store, err := GetStore(m.StoreId)
if err != nil {
logger.Error("get store err:", logger.Field("err", err))
return err
}
m.StoreName = store.Name
}
if m.ErpSupplierId != 0 {
supplier, err := GetErpSupplier(m.ErpSupplierId)
if err != nil {
logger.Error("get supplier err:", logger.Field("err", err))
return err
}
m.ErpSupplierName = supplier.Name
}
if m.ErpCashierId != 0 {
cashier, err := GetAccountDetail(int(m.ErpCashierId))
if err != nil {
logger.Error("get cashier err:", logger.Field("err", err))
return err
}
m.ErpCashierName = cashier.Name
}
return nil
}
// GetPurchaseInventorySn 生成入库编号
func GetPurchaseInventorySn() string {
count := 0
for {
if count > 5 {
return ""
}
nowTime := time.Now()
sn := nowTime.Format("060102")
sn += fmt.Sprintf("%d", nowTime.Unix()%100)
rand.Seed(nowTime.UnixNano())
sn += fmt.Sprintf("%d", rand.Int31n(100))
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_inventory WHERE serial_number='%s'", sn))
if err != nil {
logger.Error("sn err:", logger.Field("err", err))
count++
continue
}
if err == nil && !exist {
return sn
}
return ""
}
}
// CreateErpPurchaseOrder 新增采购订单
func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) {
var err error
nowTime := time.Now()
purchaseOrder := &ErpPurchaseOrder{}
if req.PurchaseType == ErpProcureOrder { // 采购入库订单
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "cgr" + NewErpPurchaseSn(),
PurchaseType: req.PurchaseType,
StoreId: req.StoreId,
ErpSupplierId: req.ErpSupplierId,
MakerTime: nowTime,
HandlerId: req.HandlerId,
HandlerName: req.HandlerName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
State: ErpPurchaseOrderUnAudit, // 1-待审核
ErpCashierId: req.ErpCashierId,
AccountHolder: req.AccountHolder,
OpeningBank: req.OpeningBank,
BankAccount: req.BankAccount,
DeliveryTime: req.DeliveryTime,
}
err = purchaseOrder.IdInit()
} else if req.PurchaseType == ErpRejectOrder { // 采购退货订单
if req.PurchaseOrderSn == "" {
return nil, errors.New("新建失败:采购退货订单号为空")
}
var erpPurchaseOrder ErpPurchaseOrder
err = orm.Eloquent.Table("erp_purchase_order").Where("serial_number=?", req.PurchaseOrderSn).Find(&erpPurchaseOrder).Error
if err != nil {
logger.Error("purchase order err:", logger.Field("err", err))
return nil, err
}
purchaseOrder = &ErpPurchaseOrder{
SerialNumber: "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,
}
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
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 {
v.SerialNumber = GetPurchaseInventorySn()
// 更新采购商品表的执行数量
// todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息可能采购价不同需要区分入库的是哪一条(已修改)
err = begin.Model(&ErpPurchaseCommodity{}).
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
}
}
// 查询采购订单信息
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
}
// 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
}
countMap := make(map[uint32]uint32)
for _, inventory := range req.Inventories {
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 {
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 {
// 如果是串码商品,根据 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,
})
}
}
resp.Total = len(resp.List)
return resp, nil
}
// 生成串码
func generateIMEI(commodityId uint32) (string, error) {
commodity, err := GetCommodity(commodityId)
if err != nil {
return "", err
}
return GenerateSerialCode(commodity.ErpCategoryId)
}
// CreateErpPurchaseDemand 创建采购需求单
func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error {
var demandInfo ErpPurchaseDemand
var 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
}