1.修复缺陷:

(1)采购执行入库时入库编号规则调整,采购为入库编号,退货为采购单单据号;
(2)采购入库更新库存信息时,遍历库存信息,合并重复数据,避免插入多条相同数据;
(3)采购报表(按单)调整筛选条件查询,支持组合查询,改为1个函数;
(4)采购报表(按商品)调整筛选条件查询,支持组合查询,改为1个函数;
This commit is contained in:
chenlin 2024-05-11 10:03:52 +08:00
parent 6f91388f05
commit 4696c63778
2 changed files with 269 additions and 127 deletions

View File

@ -250,7 +250,7 @@ func ErpPurchaseDetail(c *gin.Context) {
v.ExecutionPrice = math.Round(v.ExecutionPrice*100) / 100 v.ExecutionPrice = math.Round(v.ExecutionPrice*100) / 100
serialNumber := purchaseOrder.SerialNumber serialNumber := purchaseOrder.SerialNumber
if purchaseOrder.PurchaseType == model.ErpRejectOrder { // 采购退货订单 if purchaseOrder.PurchaseType == model.ErpRejectOrder && purchaseOrder.State == model.ErpPurchaseOrderUnAudit { // 采购退货订单
serialNumber = purchaseOrder.RejectedSerialNumber serialNumber = purchaseOrder.RejectedSerialNumber
// 查询原始采购订单的信息 // 查询原始采购订单的信息

View File

@ -1137,7 +1137,12 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq, c *gin.Context) error {
nCount := v.Count nCount := v.Count
nAmount := v.Amount nAmount := v.Amount
for j := 0; j < int(nCount); j++ { // 采购入库记录表都是单笔数据 for j := 0; j < int(nCount); j++ { // 采购入库记录表都是单笔数据
if v.PurchaseType == ErpProcureOrder {
v.SerialNumber = GetPurchaseInventorySn() v.SerialNumber = GetPurchaseInventorySn()
} else {
v.SerialNumber = purchaseOrder.SerialNumber
}
v.ID = 0 v.ID = 0
v.Count = 1 v.Count = 1
v.Amount = nAmount / float64(nCount) // 前端传的执行金额是总金额 v.Amount = nAmount / float64(nCount) // 前端传的执行金额是总金额
@ -1231,6 +1236,7 @@ func GetInventoryIdAndName(orderId uint32) (uint32, string, error) {
func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error { func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
// 遍历采购入库商品信息 // 遍历采购入库商品信息
var stockList []ErpStockCommodity var stockList []ErpStockCommodity
var waitCreateStockList []ErpStock
for _, v := range list { for _, v := range list {
commodityInfo, err := GetCommodity(v.ErpCommodityId) commodityInfo, err := GetCommodity(v.ErpCommodityId)
if err != nil { if err != nil {
@ -1252,7 +1258,8 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory,
return err return err
} }
} else { } else {
stock := &ErpStock{ // 如果同时入库多个商品,刚好之前又没有记录,则可能生成多条记录
stock := ErpStock{
StoreId: purchaseOrder.StoreId, StoreId: purchaseOrder.StoreId,
StoreName: purchaseOrder.StoreName, StoreName: purchaseOrder.StoreName,
ErpCommodityId: v.ErpCommodityId, ErpCommodityId: v.ErpCommodityId,
@ -1266,11 +1273,13 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory,
Count: v.Count, Count: v.Count,
DispatchCount: 0, DispatchCount: 0,
} }
err = gdb.Create(stock).Error
if err != nil { waitCreateStockList = append(waitCreateStockList, stock)
logger.Errorf("create stock err:", err) //err = gdb.Create(stock).Error
return err //if err != nil {
} // logger.Errorf("create stock err:", err)
// return err
//}
} }
nowTime := time.Now() nowTime := time.Now()
@ -1304,15 +1313,63 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory,
stockList = append(stockList, stockCommodity) stockList = append(stockList, stockCommodity)
} }
err := gdb.Debug().Create(&stockList).Error // 遍历库存信息,合并重复数据
newStockList := combineStocks(waitCreateStockList)
err := gdb.Debug().Create(&newStockList).Error
if err != nil { if err != nil {
logger.Errorf("create stock commodity err:", err) logger.Errorf("create erp_stock err:", err)
return err
}
err = gdb.Debug().Create(&stockList).Error
if err != nil {
logger.Errorf("create erp_stock_commodity err:", err)
return err return err
} }
return nil return nil
} }
func combineStocks(waitCreateStockList []ErpStock) []ErpStock {
// 创建一个map用于存储相同 StoreId 和 ErpCommodityId 的库存信息
stockMap := make(map[string]*ErpStock)
// 遍历待处理的库存列表
for _, stock := range waitCreateStockList {
// 构建库存信息的唯一标识
key := fmt.Sprintf("%d_%d", stock.StoreId, stock.ErpCommodityId)
// 如果该库存信息已经存在于 map 中,则累加数量
if existingStock, found := stockMap[key]; found {
existingStock.Count += stock.Count
} else {
// 否则,将该库存信息添加到 map 中
stockMap[key] = &ErpStock{
StoreId: stock.StoreId,
StoreName: stock.StoreName,
ErpCommodityId: stock.ErpCommodityId,
ErpCommodityName: stock.ErpCommodityName,
ErpCategoryId: stock.ErpCategoryId,
ErpCategoryName: stock.ErpCategoryName,
CommoditySerialNumber: stock.CommoditySerialNumber,
IMEIType: stock.IMEIType,
RetailPrice: stock.RetailPrice,
MinRetailPrice: stock.MinRetailPrice,
Count: stock.Count,
DispatchCount: stock.DispatchCount,
}
}
}
// 将 map 中的库存信息转换为列表
var combinedStocks []ErpStock
for _, stock := range stockMap {
combinedStocks = append(combinedStocks, *stock)
}
return combinedStocks
}
// InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息 // InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息
func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error { func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error {
usedStockCommodityIdList := make(map[uint32]bool) usedStockCommodityIdList := make(map[uint32]bool)
@ -3075,13 +3132,15 @@ func convertLettersToColumn(letters string) int {
func GetReportByOrder(req *ErpPurchaseReportByOrderReq, c *gin.Context) (*ErpPurchaseReportByOrderResp, error) { func GetReportByOrder(req *ErpPurchaseReportByOrderReq, c *gin.Context) (*ErpPurchaseReportByOrderResp, error) {
var err error var err error
resp := new(ErpPurchaseReportByOrderResp) resp := new(ErpPurchaseReportByOrderResp)
if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空 //if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
// 先筛选商品入库信息表,然后再补充采购订单信息 // // 先筛选商品入库信息表,然后再补充采购订单信息
resp, err = getReportByOrderFromCommodityOrCategory(req, c) // resp, err = getReportByOrderFromCommodityOrCategory(req, c)
} else { //} else {
// 先筛选采购订单表,再补充商品入库信息 // // 先筛选采购订单表,再补充商品入库信息
// resp, err = getReportByOrderFromCommon(req, c)
//}
resp, err = getReportByOrderFromCommon(req, c) resp, err = getReportByOrderFromCommon(req, c)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -3316,10 +3375,10 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
PageIndex: page + 1, PageIndex: page + 1,
PageSize: req.PageSize, PageSize: req.PageSize,
} }
qs := orm.Eloquent.Table("erp_purchase_order").Where("state != 1") // 未审核订单不展示 qs := orm.Eloquent.Table("erp_purchase_order").Where("state != ?", ErpPurchaseOrderUnAudit) // 未审核订单不展示
if req.SerialNumber != "" { // 单据编号 if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber) qs = qs.Where("serial_number=?", req.SerialNumber)
} else { }
if req.PurchaseType != "" { // 采购类型 if req.PurchaseType != "" { // 采购类型
qs = qs.Where("purchase_type=?", req.PurchaseType) qs = qs.Where("purchase_type=?", req.PurchaseType)
} }
@ -3360,7 +3419,6 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
//parse = parse.AddDate(0, 0, 1) //parse = parse.AddDate(0, 0, 1)
qs = qs.Where("audit_time < ?", parse) qs = qs.Where("audit_time < ?", parse)
} }
}
var count int64 var count int64
err := qs.Count(&count).Error err := qs.Count(&count).Error
@ -3370,8 +3428,7 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
} }
resp.Total = int(count) resp.Total = int(count)
var orders []ErpPurchaseOrder var orders []ErpPurchaseOrder
if req.ErpCategoryID != 0 || req.ErpCommodityName != "" || req.IsExport == 1 {
if req.IsExport == 1 { // 导出excel
err = qs.Order("id DESC").Find(&orders).Error err = qs.Order("id DESC").Find(&orders).Error
} else { } else {
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
@ -3388,6 +3445,7 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
var reportByOrderData ReportByOrderData var reportByOrderData ReportByOrderData
var nAmount float64 var nAmount float64
var nCount int32 var nCount int32
reportByOrderData.ErpPurchaseOrderId = v.ID reportByOrderData.ErpPurchaseOrderId = v.ID
reportByOrderData.SerialNumber = v.SerialNumber reportByOrderData.SerialNumber = v.SerialNumber
reportByOrderData.PurchaseType = v.PurchaseType reportByOrderData.PurchaseType = v.PurchaseType
@ -3418,11 +3476,15 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
reportByOrderData.AuditTime = v.AuditTime reportByOrderData.AuditTime = v.AuditTime
} }
reportByOrderData.CommodityData, nAmount, nCount, err = getOrderInventoryInfo(v.ID) reportByOrderData.CommodityData, nAmount, nCount, err = getOrderInventoryInfo(req, v.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if reportByOrderData.CommodityData == nil {
continue
}
reportByOrderData.Amount = nAmount reportByOrderData.Amount = nAmount
reportByOrderData.Count = nCount reportByOrderData.Count = nCount
if nCount != 0 { if nCount != 0 {
@ -3432,10 +3494,25 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
nTotalAmount += nAmount nTotalAmount += nAmount
nTotalCount += nCount nTotalCount += nCount
} }
resp.Total = len(reportByOrderDataList)
if req.ErpCategoryID != 0 || req.ErpCommodityName != "" {
// 计算分页所需的切片索引
startIndex := page * req.PageSize
endIndex := (page + 1) * req.PageSize
if endIndex > len(reportByOrderDataList) {
endIndex = len(reportByOrderDataList)
}
resp.List = reportByOrderDataList[startIndex:endIndex]
} else {
resp.List = reportByOrderDataList resp.List = reportByOrderDataList
}
resp.Amount = nTotalAmount resp.Amount = nTotalAmount
resp.Count = nTotalCount resp.Count = nTotalCount
resp.Total = int(count) //resp.Total = int(count)
if req.IsExport == 1 { if req.IsExport == 1 {
filePath, err := reportByOrderExport(resp) filePath, err := reportByOrderExport(resp)
@ -3450,7 +3527,7 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq, c *gin.Context
} }
// 查询采购订单的入库信息 // 查询采购订单的入库信息
func getOrderInventoryInfo(erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, int32, error) { func getOrderInventoryInfo(req *ErpPurchaseReportByOrderReq, erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, int32, error) {
var inventoryList []ErpPurchaseInventory var inventoryList []ErpPurchaseInventory
err := orm.Eloquent.Table("erp_purchase_inventory"). err := orm.Eloquent.Table("erp_purchase_inventory").
Where("erp_purchase_order_id = ?", erpPurchaseOrderId). Where("erp_purchase_order_id = ?", erpPurchaseOrderId).
@ -3474,6 +3551,15 @@ func getOrderInventoryInfo(erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityDat
for _, v := range inventoryList { for _, v := range inventoryList {
var vCount int32 var vCount int32
var vAmount float64 var vAmount float64
// 商品名称和分类筛选
if req.ErpCommodityName != "" && v.ErpCommodityName != req.ErpCommodityName {
continue
}
if req.ErpCategoryID != 0 && v.ErpCategoryID != req.ErpCategoryID {
continue
}
if v.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值 if v.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值
vAmount = -v.Amount vAmount = -v.Amount
vCount = -int32(v.Count) vCount = -int32(v.Count)
@ -3665,13 +3751,15 @@ func reportByOrderExport(req *ErpPurchaseReportByOrderResp) (string, error) {
func GetReportByCommodity(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (*ErpPurchaseReportByCommodityResp, error) { func GetReportByCommodity(req *ErpPurchaseReportByCommodityReq, c *gin.Context) (*ErpPurchaseReportByCommodityResp, error) {
var err error var err error
resp := new(ErpPurchaseReportByCommodityResp) resp := new(ErpPurchaseReportByCommodityResp)
if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空 //if req.ErpCommodityName != "" || req.ErpCategoryID != 0 { // 商品名称、商品分类不为空
// 先筛选商品入库信息表,然后再补充采购订单信息 // // 先筛选商品入库信息表,然后再补充采购订单信息
resp, err = getReportByCommodityFromCommodityOrCategory(req, c) // resp, err = getReportByCommodityFromCommodityOrCategory(req, c)
} else { //} else {
// 先筛选采购订单表,再补充商品入库信息 // // 先筛选采购订单表,再补充商品入库信息
// resp, err = getReportByCommodityFromCommon(req, c)
//}
resp, err = getReportByCommodityFromCommon(req, c) resp, err = getReportByCommodityFromCommon(req, c)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -3729,11 +3817,7 @@ func getReportByCommodityFromCommodityOrCategory(req *ErpPurchaseReportByCommodi
} }
var inventoryList []ErpPurchaseInventory var inventoryList []ErpPurchaseInventory
if req.IsExport == 1 { // 导出excel
err = qs.Order("id DESC").Find(&inventoryList).Error err = qs.Order("id DESC").Find(&inventoryList).Error
} else {
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&inventoryList).Error
}
if err != nil && err != RecordNotFound { if err != nil && err != RecordNotFound {
logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err)) logger.Error("getReportByOrderFromCommodityOrCategory erp_purchase_inventory err:", logger.Field("err", err))
return resp, err return resp, err
@ -3761,10 +3845,13 @@ func getReportByCommodityFromCommodityOrCategory(req *ErpPurchaseReportByCommodi
for _, orderIdSet := range commodityIDMap { for _, orderIdSet := range commodityIDMap {
var reportByCommodityData ReportByCommodityData var reportByCommodityData ReportByCommodityData
if len(orderIdSet) != 0 { if len(orderIdSet) != 0 {
reportByCommodityData.ErpCommodityId = orderIdSet[0].ErpPurchaseCommodityId for _, item := range orderIdSet {
reportByCommodityData.ErpCommodityName = orderIdSet[0].ErpCommodityName reportByCommodityData.ErpCommodityId = item.ErpCommodityId
reportByCommodityData.ErpCategoryID = orderIdSet[0].ErpCategoryID reportByCommodityData.ErpCommodityName = item.ErpCommodityName
reportByCommodityData.ErpCategoryName = orderIdSet[0].ErpCategoryName reportByCommodityData.ErpCategoryID = item.ErpCategoryID
reportByCommodityData.ErpCategoryName = item.ErpCategoryName
break
}
} }
var totalPurchaseData PurchaseData var totalPurchaseData PurchaseData
@ -3807,7 +3894,17 @@ func getReportByCommodityFromCommodityOrCategory(req *ErpPurchaseReportByCommodi
reportByCommodityDataList = append(reportByCommodityDataList, reportByCommodityData) reportByCommodityDataList = append(reportByCommodityDataList, reportByCommodityData)
} }
resp.List = reportByCommodityDataList sortByCommodityIDDesc(reportByCommodityDataList)
resp.Total = len(reportByCommodityDataList)
// 计算分页所需的切片索引
startIndex := page * req.PageSize
endIndex := (page + 1) * req.PageSize
if endIndex > len(reportByCommodityDataList) {
endIndex = len(reportByCommodityDataList)
}
resp.List = reportByCommodityDataList[startIndex:endIndex]
resp.PlanCount = totalData.PlanCount resp.PlanCount = totalData.PlanCount
resp.PlanAmount = totalData.PlanAmount resp.PlanAmount = totalData.PlanAmount
resp.Amount = totalData.Amount resp.Amount = totalData.Amount
@ -3966,10 +4063,10 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin
PageIndex: page + 1, PageIndex: page + 1,
PageSize: req.PageSize, PageSize: req.PageSize,
} }
qs := orm.Eloquent.Table("erp_purchase_order").Where("state != 1") qs := orm.Eloquent.Table("erp_purchase_order").Where("state != ?", ErpPurchaseOrderUnAudit)
if req.SerialNumber != "" { // 单据编号 if req.SerialNumber != "" { // 单据编号
qs = qs.Where("serial_number=?", req.SerialNumber) qs = qs.Where("serial_number=?", req.SerialNumber)
} else { }
if req.PurchaseType != "" { // 采购类型 if req.PurchaseType != "" { // 采购类型
qs = qs.Where("purchase_type=?", req.PurchaseType) qs = qs.Where("purchase_type=?", req.PurchaseType)
} }
@ -4002,7 +4099,6 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin
//parse = parse.AddDate(0, 0, 1) //parse = parse.AddDate(0, 0, 1)
qs = qs.Where("audit_time < ?", parse) qs = qs.Where("audit_time < ?", parse)
} }
}
var count int64 var count int64
err := qs.Count(&count).Error err := qs.Count(&count).Error
@ -4069,6 +4165,13 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin
for _, tempDataList := range tempDataMap { for _, tempDataList := range tempDataMap {
var reportData ReportByCommodityData var reportData ReportByCommodityData
for _, v := range tempDataList { for _, v := range tempDataList {
// 商品名称和分类筛选
if req.ErpCommodityName != "" && v.ErpCommodityName != req.ErpCommodityName {
continue
}
if req.ErpCategoryID != 0 && v.ErpCategoryID != req.ErpCategoryID {
continue
}
reportData.ErpCategoryID = v.ErpCategoryID reportData.ErpCategoryID = v.ErpCategoryID
reportData.ErpCategoryName = v.ErpCategoryName reportData.ErpCategoryName = v.ErpCategoryName
reportData.ErpCommodityId = v.ErpCommodityId reportData.ErpCommodityId = v.ErpCommodityId
@ -4149,6 +4252,9 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin
reportData.OrderInfo = append(reportData.OrderInfo, purchaseOrderData) reportData.OrderInfo = append(reportData.OrderInfo, purchaseOrderData)
} }
if reportData.ErpCategoryID == 0 || len(reportData.OrderInfo) == 0 {
continue
}
dataList = append(dataList, reportData) dataList = append(dataList, reportData)
@ -4274,23 +4380,59 @@ func getSignalPurchaseData(erpPurchaseOrderId, commodityId uint32) (PurchaseData
var purchaseData PurchaseData var purchaseData PurchaseData
var commodityData CommodityData var commodityData CommodityData
//err := orm.Eloquent.Raw(`
// SELECT
// SUM(pc.count) AS plan_count,
// AVG(pc.price) AS plan_price,
// SUM(pc.amount) AS plan_amount,
// SUM(pi.count) AS count,
// AVG(pi.implementation_price) AS price,
// SUM(pi.amount) AS amount
// FROM
// erp_purchase_commodity pc
// JOIN
// erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
// WHERE
// pc.erp_purchase_order_id = ? and pc.erp_commodity_id = ?
// GROUP BY
// pc.erp_purchase_order_id
//`, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
err := orm.Eloquent.Raw(` err := orm.Eloquent.Raw(`
SELECT SELECT
plan.plan_count AS plan_count,
plan.plan_price AS plan_price,
plan.plan_amount AS plan_amount,
inventory.count AS count,
inventory.price AS price,
inventory.amount AS amount
FROM
(
SELECT
SUM(pc.count) AS plan_count, SUM(pc.count) AS plan_count,
AVG(pc.price) AS plan_price, AVG(pc.price) AS plan_price,
SUM(pc.amount) AS plan_amount, SUM(pc.amount) AS plan_amount
FROM
erp_purchase_commodity pc
WHERE
pc.erp_purchase_order_id = ? AND pc.erp_commodity_id = ?
GROUP BY
pc.erp_purchase_order_id
) AS plan
JOIN
(
SELECT
SUM(pi.count) AS count, SUM(pi.count) AS count,
AVG(pi.implementation_price) AS price, AVG(pi.implementation_price) AS price,
SUM(pi.amount) AS amount SUM(pi.amount) AS amount
FROM FROM
erp_purchase_commodity pc erp_purchase_inventory pi
JOIN
erp_purchase_inventory pi ON pc.erp_purchase_order_id = pi.erp_purchase_order_id
WHERE WHERE
pc.erp_purchase_order_id = ? and pc.erp_commodity_id = ? pi.erp_purchase_order_id = ? AND pi.erp_commodity_id = ?
GROUP BY GROUP BY
pc.erp_purchase_order_id pi.erp_purchase_order_id
`, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error ) AS inventory ON 1 = 1
`, erpPurchaseOrderId, commodityId, erpPurchaseOrderId, commodityId).Scan(&purchaseData).Error
if err != nil { if err != nil {
logger.Error("getPurchaseData err:", logger.Field("err", err)) logger.Error("getPurchaseData err:", logger.Field("err", err))
return PurchaseData{}, CommodityData{}, err return PurchaseData{}, CommodityData{}, err