mh_goadmin_server/app/admin/models/erp_order.go
chenlin 0a5fe58bbe 优化生产反馈缺陷:
1.小程序调用erp登录接口不判断验证码;
2.修改原接口的翻页相关字段;
3.修复float64转int32精度丢失的缺陷;
4.注释库存导入时采购价需大于0的校验;
5.相关域名改成生产环境域名;
2024-07-03 18:56:33 +08:00

5203 lines
186 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 (
"encoding/json"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2"
"go-admin/app/admin/apis/pay"
orm "go-admin/common/global"
"go-admin/logger"
"go-admin/tools"
"go-admin/tools/config"
"gorm.io/gorm"
"math"
"math/rand"
"sort"
"strconv"
"strings"
"time"
)
const (
ErpOrderStateUnAudit = "un_audit" // 未审核
ErpOrderStateAudited = "audited" // 已审核
ErpOrderMemberTypeGeneral = "general" // 普通
ErpOrderMemberTypeMember = "member" // 会员
RetailTypeSale = "sale" // 零售订单
RetailTypeRejected = "rejected" // 零售退货订单
NoCreatePayOrder = 0 // 未创建
WaitForPaying = 1 // 待支付
HavePaid = 2 // 已支付
NoPrint = 1 // 未打印
HavePrinted = 2 // 已打印
OnlinePay = 1 // 线上支付(微信/支付宝/云闪付扫码)
NoPayOrder = "no_pay_order"
PayInit = "pay_init"
Paying = "paying"
PayOk = "pay_ok"
PayFailed = "pay_failed"
PayUnknown = "pay_unknown"
)
// ErpOrder 零售订单表
type ErpOrder struct {
Model
BillSn string `json:"bill_sn" gorm:"index"` // 单据编号
RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货
Uid int `json:"uid"` // 用户id
Tel string `json:"tel" gorm:"index"` // 客户手机号
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id
MakerName string `json:"maker_name"` // 制单人名称
MakerTime time.Time `json:"maker_time"` // 制单时间
AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id
AuditorName string `json:"auditor_name"` // 审核人姓名
AuditTime *time.Time `json:"audit_time"` // 审核时间
CashierList string `json:"cashier_list" gorm:"type:text"` // 付款方式存储json数据
SalesmanList string `json:"salesman_list" gorm:"type:text"` // 销售员信息存储json数据
MemberType string `json:"member_type"` // 会员类型:general 普通; member 会员
State string `json:"state" gorm:"index"` // 订单状态:un_audit 待审核; audited 已审核
TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价
TotalAmount float64 `json:"total_amount"` // 订单实收金额
TotalCount int32 `json:"total_count"` // 订单商品数量
TotalSalesProfit float64 `json:"total_sales_profit"` // 订单总销售毛利
TotalStaffProfit float64 `json:"total_staff_profit"` // 订单总员工毛利
VmCount uint32 `json:"vm_count"` // 使用会员积分
SaleOrderId uint32 `json:"sale_order_id"` // 销售订单id
PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 1-待支付; 2-已支付
IsPrint uint32 `json:"is_print"` // 是否打印小票 1-未打印 2-已打印
PrintCount uint32 `json:"print_count"` // 小票打印次数
InvoiceCode string `json:"invoice_code"` // 发票代码
InvoiceNumber string `json:"invoice_number"` // 发票编码
RejectedTotalAmount float64 `json:"rejected_total_amount" gorm:"-"` // 订单总退货金额
RejectedTotalCount uint32 `json:"rejected_total_count" gorm:"-"` // 订单总退货数量
StorePer float64 `json:"store_per"` // 门店提成订单总员工毛利X该门店设置好的提成比例保留到小数后两位多余舍去
TotalDiscount float64 `json:"total_discount"` // 订单总优惠:订单所有商品零售优惠+会员优惠+会员积分抵扣之和
Commodities []ErpOrderCommodity `json:"commodities" gorm:"-"` // 零售订单商品信息
Cashiers []ErpOrderCashier `json:"cashiers" gorm:"-"` // 收付款方式
Salesman []ErpOrderSales `json:"salesman" gorm:"-"` // 销售员信息
}
// ErpOrderCommodity 零售订单商品表
type ErpOrderCommodity struct {
Model
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id后端生成
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id
ErpCategoryName string `json:"erp_category_name"` // 分类名称
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 主供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 主供应商名称
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei" gorm:"index"` // 串码
PresentType uint32 `json:"present_type"` // 赠送类型:1-非赠送 2-赠送
RetailPrice float64 `json:"retail_price"` // 指导零售价
SalePrice float64 `json:"sale_price"` // 零售价
Count int32 `json:"count"` // 销售数量
SaleDiscount float64 `json:"sale_discount"` // 零售优惠
MemberDiscount float64 `json:"member_discount"` // 会员优惠
VmDiscount float64 `json:"vm_discount"` // 会员积分抵扣
Amount float64 `json:"amount"` // 实际零售价
ReceivedAmount float64 `json:"received_amount"` // 商品实收金额
Remark string `json:"remark"` // 销售备注
RejectedRemark string `json:"rejected_remark"` // 退货备注
RejectedPrice float64 `json:"rejected_price"` // 退货单价
RejectedCount uint32 `json:"rejected_count"` // 退货数量
RejectedAmount float64 `json:"rejected_amount"` // 退货金额
RejectedOrderCommodityId uint32 `json:"rejected_order_commodity_id"` // 退货订单商品id
StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价加价50不是加价后的价格
WholesalePrice float64 `json:"wholesale_price"` // 指导采购价
SalesProfit float64 `json:"sales_profit"` // 销售毛利:实际零售价-采购单价;如果为退货订单,则为实际退货价-采购单价
StaffProfit float64 `json:"staff_profit"` // 员工毛利:实际零售价-员工成本价;如果为退货订单,则为实际退货价-员工成本价
ErpStockCommodityID string `json:"erp_stock_commodity_id"` // 库存商品表主键id
StaffPrice float64 `json:"staff_price" gorm:"-"` // 员工成本价
}
// ErpOrderCashier 订单收款方式
type ErpOrderCashier struct {
CashierId uint32 `json:"cashier_id"` // 收付款方式id
Name string `json:"name"` // 收付款方式名称
Amount float64 `json:"amount"` // 金额
}
// ErpOrderPayWay 订单支付方式记录
type ErpOrderPayWay struct {
Model
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id后端生成
CashierId uint32 `json:"cashier_id"` // 收付款方式id
Name string `json:"name"` // 收付款方式名称
Amount float64 `json:"amount"` // 金额
}
// ErpOrderSales 销售员信息
type ErpOrderSales struct {
Model
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id后端生成
Uid uint32 `json:"userId" binding:"required"` // 销售员用户ID20240322更换为系统用户表主键id
Name string `json:"name"` // 销售员用户姓名
SalesProfitPer float64 `json:"sales_profit_per"` // 销售毛利提成每个商品销售毛利X其对应的提成比例后求和如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去
StaffProfitPer float64 `json:"staff_profit_per"` // 员工毛利提成每个商品员工毛利X其对应的提成比例后求和如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去
SalesmanPer float64 `json:"salesman_per"` // 销售员提成订单总员工毛利X该销售员设置好的提成比例如果是两个销售员参与那么两个人算出的提成均除以2保留到小数后两位多余舍去
}
// ErpOrderRecord 订单支付记录表
type ErpOrderRecord struct {
Model
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id
BillSn string `json:"bill_sn" gorm:"index"` // 单据编号
OutOrderNo string `json:"out_order_no"` // 商户订单号
PlatTrxNo string `json:"plat_trx_no"` // 平台交易流水号
BankOrderNo string `json:"bank_order_no"` // 银行订单号
TotalAmount float64 `json:"total_amount"` // 订单总金额
PayWay string `json:"pay_way"` // 支付方式
Status string `json:"status"` // 支付状态
}
// ErpOrderCreateReq 订单创建入参
type ErpOrderCreateReq struct {
BillSn string `json:"bill_sn"` // 单据编号
StoreId uint32 `json:"store_id" binding:"required"` // 门店id
StoreName string `json:"store_name" binding:"required"` // 门店名称
RetailType string `json:"retail_type" binding:"required"` // 销售类型sale 零售销售; rejected 零售退货
Tel string `json:"tel" binding:"required"` // 会员手机号
MemberType string `json:"member_type" binding:"required"` // 会员类型general 普通; member 会员
TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价如果是赠送商品金额可以为0
TotalAmount float64 `json:"total_amount"` // 订单实收金额如果只有1个赠送商品金额可以为0
TotalCount uint32 `json:"total_count" binding:"required"` // 订单商品数量
VmAmount uint32 `json:"vm_count"` // 使用会员积分
Cashiers []ErpOrderCashier `json:"cashiers" binding:"required"` // 收付款方式
ErpOrderCommodities []ErpOrderCommodity `json:"erp_order_commodities" binding:"required"` // 零售订单商品信息
Salesman []ErpOrderSales `json:"salesman" binding:"required"` // 销售员信息
}
// ErpOrderListReq 查询零售订单列表入参
type ErpOrderListReq struct {
ScanCode string `json:"scan_code"` // 扫码枪扫码数据:串码
BillSn string `json:"bill_sn"` // 单据编号
RetailType string `json:"retail_type"` // 销售类型sale 零售销售; rejected 零售退货
CommodityName string `json:"commodity_name"` // 商品名称
Uid int `json:"uid"` // 用户ID
Tel string `json:"tel"` // 客户手机号
Salesman uint32 `json:"salesman"` // 销售人员ID
StoreId uint32 `json:"store_id"` // 门店ID
State string `json:"state"` // 订单状态
PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 1-待支付; 2-已支付
MakeTimeStart string `json:"make_time_start"` // 制单开始时间
MakeTimeEnd string `json:"make_time_end"` // 制单结束时间
AuditTimeStart string `json:"audit_time_start"` // 审核开始时间
AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
}
// ErpOrderListResp 查询零售订单列表出参
type ErpOrderListResp struct {
List []ErpOrder `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ShowAll string `json:"show_all" binding:"required"` // 展示所有订单配置ON-打开OFF-关闭
ExportUrl string `json:"export_url"`
}
// ErpOrderDeleteReq 删除零售订单入参
type ErpOrderDeleteReq struct {
BillSn string `json:"bill_sn" binding:"required"` // 单据编号
}
// ErpOrderPayReq 收款入参
type ErpOrderPayReq struct {
BillSn string `json:"bill_sn" binding:"required"` // 单据编号
AuthCode string `json:"auth_code" binding:"required"` // 用户付款码
}
// ErpOrderPayResp 收款出参
type ErpOrderPayResp struct {
Status string `json:"status"` // 支付成功pay_ok支付失败pay_failed 等待支付paying; 未知状态pay_unknown; 未创建支付订单no_pay_order
}
// ErpOrderAuditReq 审核零售订单入参
type ErpOrderAuditReq struct {
BillSn string `json:"bill_sn" binding:"required"` // 单据编号
State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核
}
// ErpOrderAddInvoiceReq 开发票入参
type ErpOrderAddInvoiceReq struct {
BillSn string `json:"bill_sn" binding:"required"` // 单据编号
InvoiceCode string `json:"invoice_code" binding:"required"` // 发票代码
InvoiceNumber string `json:"invoice_number" binding:"required"` // 发票编码
}
// ErpOrderStoreManageDataReq 查询门店经营入参
type ErpOrderStoreManageDataReq struct {
StoreId uint32 `json:"store_id"` // 门店ID
StartTime string `json:"start_time"` // 开始时间
EndTime string `json:"end_time"` // 结束时间
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
IsExport uint32 `json:"is_export"` // 1-导出
SortType string `json:"sort_type"` // 排序类型desc 降序、asc 升序
}
// ErpOrderStoreManageDataResp 查询门店经营出参
type ErpOrderStoreManageDataResp struct {
List []StoreManageData `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ExportUrl string `json:"export_url"`
}
// StoreManageData 门店经营数据
type StoreManageData struct {
Date string `json:"date"` // 时间,如:"2023-12-25"
TotalSalesAmount float64 `json:"total_sales_amount"` // 销售额
PromotionFee float64 `json:"promotion_fee"` // 推广费
SalesProfit float64 `json:"sales_profit"` // 销售毛利
StaffProfit float64 `json:"staff_profit"` // 员工毛利
Count int64 `json:"count"` // 销售数量
}
// ErpOrderRetailMarginReq 查询商品零售毛利汇总入参
type ErpOrderRetailMarginReq struct {
StoreId []uint32 `json:"store_id"` // 门店ID
RetailType []string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货
ErpCommodityName []string `json:"erp_commodity_name"` // 商品名称
ErpCategoryId []uint32 `json:"erp_category_id" gorm:"index"` // 分类id
StartTime string `json:"start_time"` // 开始时间
EndTime string `json:"end_time"` // 结束时间
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
IsExport uint32 `json:"is_export"` // 1-导出
}
// ErpOrderRetailMarginResp 查询商品零售毛利汇总出参
type ErpOrderRetailMarginResp struct {
List []RetailMarginData `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
TotalCount int32 `json:"total_count"` // 总销售数量
TotalSalesAmount float64 `json:"total_sales_amount"` // 总销售/退货金额
TotalSalesCost float64 `json:"total_sales_cost"` // 总销售成本:销售采购价之和
TotalEmployeeCost float64 `json:"total_employee_cost"` // 总员工成本:商品员工成本价之和
TotalSalesMargin float64 `json:"total_sales_margin"` // 总销售毛利:销售/退货金额-销售成本
TotalGrossMargins string `json:"total_gross_margins"` // 销售毛利率:销售毛利/销售/退货金额
ExportUrl string `json:"export_url"`
}
// RetailMarginData 商品零售毛利数据
type RetailMarginData struct {
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id
ErpCategoryName string `json:"erp_category_name"` // 分类名称
Count int32 `json:"count"` // 销售数量
SalesAmount float64 `json:"sales_amount"` // 销售/退货金额
SalesCost float64 `json:"sales_cost"` // 销售成本:销售采购价之和
EmployeeCost float64 `json:"employee_cost"` // 员工成本:商品员工成本价之和
SalesMargin float64 `json:"sales_margin"` // 销售毛利:销售/退货金额-销售成本
GrossMargins string `json:"gross_margins"` // 销售毛利率:销售毛利/销售/退货金额
}
// ErpOrderRetailDetailReq 零售明细汇总入参
type ErpOrderRetailDetailReq struct {
BillSn string `json:"bill_sn"` // 单据编号
RetailType string `json:"retail_type"` // 销售类型sale 零售销售; rejected 零售退货
Uid int `json:"uid"` // 用户ID
Tel string `json:"tel"` // 客户手机号
StoreId uint32 `json:"store_id"` // 门店ID
ErpCategoryId uint32 `json:"erp_category_id"` // 分类id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
Salesman uint32 `json:"salesman"` // 销售人员ID
IMEI string `json:"imei"` // 串码
StartTime string `json:"start_time"` // 开始时间
EndTime string `json:"end_time"` // 结束时间
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
IsExport uint32 `json:"is_export"` // 1-导出
}
// ErpOrderRetailDetailResp 零售明细汇总出参
type ErpOrderRetailDetailResp struct {
Total int `json:"total"` // 总条数(总订单数)
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ExportUrl string `json:"export_url"` // 导出excel地址
List []ErpOrder `json:"list"` // 零售明细
SumData RetailDetailTotalData `json:"sumData"` // 汇总数据
}
// RetailDetailTotalData 零售明细相关金额汇总
type RetailDetailTotalData struct {
Count int32 `json:"count"` // 销售数量
RetailPrice float64 `json:"retail_price"` // 指导零售价
SalePrice float64 `json:"sale_price"` // 零售价
SaleDiscount float64 `json:"sale_discount"` // 零售优惠
MemberDiscount float64 `json:"member_discount"` // 会员优惠
VmDiscount float64 `json:"vm_discount"` // 会员积分抵扣
Amount float64 `json:"amount"` // 实际零售价
WholesalePrice float64 `json:"wholesale_price"` // 采购单价
StaffPrice float64 `json:"staff_price"` // 员工成本价
SalesProfit float64 `json:"sales_profit"` // 销售毛利
StaffProfit float64 `json:"staff_profit"` // 员工毛利
TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价
TotalDiscount float64 `json:"total_discount"` // 订单总优惠:订单所有商品零售优惠+会员优惠+会员积分抵扣之和
TotalAmount float64 `json:"total_amount"` // 订单实收金额
TotalCashierData
TotalSalesProfit float64 `json:"total_sales_profit"` // 订单总销售毛利
TotalStaffProfit float64 `json:"total_staff_profit"` // 订单总员工毛利
TotalPerData
StorePer float64 `json:"store_per"` // 门店提成
}
// TotalPerData 员工提成
type TotalPerData struct {
TotalSalesProfitPer float64 `json:"total_sales_profit_per"` // 销售毛利提成
TotalStaffProfitPer float64 `json:"total_staff_profit_per"` // 员工毛利提成
SalesmanPer float64 `json:"salesman_per"` // 销售员提成
}
// TotalCashierData 支付方式金额汇总
type TotalCashierData struct {
ScanAmount float64 `json:"scan_amount"` // 扫码付
CashAmount float64 `json:"cash_amount"` // 现金收款
PosAmount float64 `json:"pos_amount"` // pos机收款
StoreVmAmount float64 `json:"store_vm_amount"` // 商场积分抵扣
OtherAmount float64 `json:"other_amount"` // 其他付款方式
}
// ErpOrderReceiptDataResp 查询小票数据出参
type ErpOrderReceiptDataResp struct {
StoreName string `json:"storeName"` // 门店名称
Barcode string `json:"barcode"` // 单据编号:条码
OddNum string `json:"oddNum" ` // 单据编号
Time time.Time `json:"time"` // 审核时间
CollectS string `json:"collectS"` // 收银人员:制单人
ChandiseObj map[string]TableData `json:"chandiseObj"` // 商品信息
TotalRetailP float64 `json:"totalRetailP"` // 零售价合计
TotalNum uint32 `json:"totalNum"` // 数量合计
TotalAmount float64 `json:"totalAmount"` // 零售优惠总金额
MembersAmount float64 `json:"membersAmount"` // 会员优惠总金额
IntegrationAmount float64 `json:"integrationAmount"` // 积分抵扣总金额
ToDealWith float64 `json:"toDealWith"` // 零售价合计 - 零售优惠总额 - 会员优惠总和 - 积分抵扣总额
ModeOfPayment map[string]ErpOrderCashier `json:"modeOfPayment"` // 支付信息
ActualPayment float64 `json:"actualPayment"` // 所有支付方式金额总和
Tel string `json:"tel"` // 买家电话
StoreTel string `json:"storeTel"` // 卖家电话
StoreAddress string `json:"storeAddress"` // 店铺地址
Uid int `json:"uid"` // 用户id
}
type TableData struct {
Name string `json:"name"`
SL uint32 `json:"SL"` // 销售数量
DJ float64 `json:"DJ"` // 商品指导零售价
JE float64 `json:"JE"` // 商品指导零售价乘以销售数量
}
// Contains 判断id是否在list中
func Contains(list []uint32, id uint32) bool {
for _, item := range list {
if item == id {
return true
}
}
return false
}
// CompareLists 返回共有的数据
func CompareLists(list1 []uint32, list2 []uint32) []uint32 {
if len(list2) == 0 { // 如果list2为空则直接使用list1的数据
return list1
}
// 创建一个 map 用于存储 list1 中的数据
list1Map := make(map[uint32]bool)
for _, id := range list1 {
list1Map[id] = true
}
var commonIds []uint32
// 遍历 list2如果在 list1Map 中找到相同的元素,则加入到 commonIds 中
for _, id := range list2 {
if list1Map[id] {
commonIds = append(commonIds, id)
}
}
return commonIds
}
// GetValidStoreIDs 返回未过期门店的ID列表
func GetValidStoreIDs(storeData string) []uint32 {
// 解析门店数据
var stores []StoreInfo
if err := json.Unmarshal([]byte(storeData), &stores); err != nil {
return nil
}
var validStoreIDs []uint32
// 遍历每个门店,检查是否过期
for _, store := range stores {
expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
if err != nil {
continue
}
expireTime = expireTime.Add(24*time.Hour - time.Second)
// 如果过期时间在当前时间之后则未过期将门店ID添加到列表中
if expireTime.After(time.Now()) {
validStoreIDs = append(validStoreIDs, uint32(store.StoreID))
}
}
return validStoreIDs
}
// List 查询零售订单列表
func (m *ErpOrderListReq) List(c *gin.Context) (*ErpOrderListResp, error) {
showConfig, err := GetErpOrderShowConfig()
if err != nil {
logger.Errorf("List err:", err)
showConfig.ShowAll = "ON"
}
resp := &ErpOrderListResp{
PageIndex: m.PageIndex,
PageSize: m.PageSize,
}
page := m.PageIndex - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
if m.ScanCode != "" { // 扫描了串码,需要查询已售的商品数据
return QueryListByScanCode(m.StoreId, m.ScanCode, showConfig.ShowAll, c)
}
if m.CommodityName != "" { // 输入了商品名称进行查询
return QueryListByCommodityName(m, showConfig.ShowAll, c)
}
qs := orm.Eloquent.Table("erp_order")
if showConfig.ShowAll == "OFF" { // 关闭后未开小票的零售销售订单隐藏
qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
}
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
if len(storeList) == 1 {
qs = qs.Where("store_id = ?", storeList[0])
} else {
qs = qs.Where("store_id IN (?)", storeList)
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
if m.BillSn != "" {
qs = qs.Where("bill_sn=?", m.BillSn)
} else {
if m.RetailType != "" {
qs = qs.Where("retail_type=?", m.RetailType)
}
if m.Uid != 0 {
qs = qs.Where("uid=?", m.Uid)
}
if m.Tel != "" {
qs = qs.Where("tel=?", m.Tel)
}
if m.StoreId != 0 {
qs = qs.Where("store_id=?", m.StoreId)
}
if m.Salesman != 0 {
qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, m.Salesman))
}
if m.PayStatus != 0 {
qs = qs.Where("pay_status=?", m.PayStatus)
}
if m.State != "" {
qs = qs.Where("state=?", m.State)
}
if m.MakeTimeStart != "" {
parse, err := time.Parse(QueryTimeFormat, m.MakeTimeStart)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("maker_time > ?", parse)
}
if m.MakeTimeEnd != "" {
parse, err := time.Parse(QueryTimeFormat, m.MakeTimeEnd)
if err != nil {
logger.Errorf("err:", err)
}
//parse = parse.AddDate(0, 0, 1)
qs = qs.Where("maker_time < ?", parse)
}
if m.AuditTimeStart != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("audit_time > ?", parse)
}
if m.AuditTimeEnd != "" {
parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd)
if err != nil {
logger.Errorf("err:", 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
}
var orders []ErpOrder
err = qs.Debug().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
}
// 添加付款、销售员、商品信息
erpOrderListSetCommodity(orders)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
resp.List = orders
//跟之前保持一致
resp.Total = int(count)
resp.PageIndex = page + 1
resp.PageSize = m.PageSize
resp.ShowAll = showConfig.ShowAll
return resp, nil
}
// QueryListByScanCode 通过扫描串码查询列表
func QueryListByScanCode(storeId uint32, scanCode, showConfig string, c *gin.Context) (*ErpOrderListResp, error) {
resp := &ErpOrderListResp{}
// 查询扫码串码的零售销售订单的商品信息
var commodity []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").Where("imei = ? and rejected_count = 0", scanCode).Find(&commodity).Error
if err != nil && err != RecordNotFound {
logger.Error("get erp_order_commodity err:", logger.Field("err", err))
return resp, err
}
if len(commodity) == 0 {
return &ErpOrderListResp{}, nil
}
// 判断该串码商品是否已经退货退回库存列表
var stockCount int64
err = orm.Eloquent.Table("erp_stock_commodity").
Where("state = 1 AND imei = ?", scanCode).Count(&stockCount).Error
if err != nil {
return nil, err
}
if stockCount > 0 {
return nil, errors.New("库存已有该串码商品")
}
var orders []ErpOrder
for _, item := range commodity {
if showConfig == "OFF" {
err = orm.Eloquent.Table("erp_order").
Where("id = ? and pay_status = ? and is_print != ?", item.ErpOrderId, HavePaid, NoPrint).
Order("audit_time DESC").Find(&orders).Error
} else {
err = orm.Eloquent.Table("erp_order").
Where("id = ? and pay_status = ?", item.ErpOrderId, HavePaid).
Order("audit_time DESC").Find(&orders).Error
}
if err != nil && err != RecordNotFound {
logger.Error("get erp_order err:", logger.Field("err", err))
return resp, err
}
if len(orders) == 0 {
continue
} else {
break
}
}
if len(orders) != 0 {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("查询失败:" + err.Error())
}
if !CheckUserStore(orders[0].StoreId, sysUser) {
return &ErpOrderListResp{}, errors.New("您没有该门店权限")
}
}
if orders[0].StoreId != storeId && storeId != 0 {
return &ErpOrderListResp{}, errors.New("非当前门店所售商品,需前往对应门店退货")
}
}
// 添加付款、销售员、商品信息
erpOrderListSetCommodity(orders)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
orders[0].Commodities = commodity
if len(orders) != 0 {
// 查询该串码商品是否已经退过货
resp.List = append(resp.List, orders[0])
} else {
resp.List = orders
}
//跟之前保持一致
resp.Total = len(resp.List)
resp.PageIndex = 1
resp.PageSize = 10
return resp, nil
}
// QueryListByCommodityName 通过商品名称查询列表
func QueryListByCommodityName(req *ErpOrderListReq, showConfig string, c *gin.Context) (*ErpOrderListResp, error) {
resp := &ErpOrderListResp{
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_order_commodity").
Select("erp_order_commodity.*, erp_order.*").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")
if req.CommodityName != "" { // 商品名称
qs = qs.Where("erp_order_commodity.erp_commodity_name like ?", "%"+req.CommodityName+"%")
}
if showConfig == "OFF" {
qs = qs.Where("invoice_code != ?", 0)
}
if req.Tel != "" { // 用户手机号
qs = qs.Where("erp_order.tel=?", req.Tel)
}
if req.StoreId != 0 { // 门店ID
qs = qs.Where("erp_order.store_id=?", req.StoreId)
}
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
if len(storeList) == 1 {
qs = qs.Where("erp_order.store_id = ?", storeList[0])
} else {
qs = qs.Where("erp_order.store_id IN (?)", storeList)
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
qs.Where("erp_order.pay_status = ?", HavePaid)
es := qs
var result []RetailDetailByJoin
err := qs.Order("erp_order.audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&result).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Errorf("QueryRetailMargin count err:", err.Error())
return nil, err
}
orders := packData(result)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
resp.List = orders
//跟之前保持一致
resp.Total = int(count)
resp.PageIndex = page + 1
resp.PageSize = req.PageSize
return resp, nil
}
// 数组转字符串
func intArrayToString(arr []uint32) string {
var strArr []string
for _, num := range arr {
strArr = append(strArr, fmt.Sprintf("%d", num))
}
return strings.Join(strArr, ",")
}
// 字符串转数组
func stringToIntArray(str string) ([]uint32, error) {
var arr []uint32
strArr := strings.Split(str, ",")
for _, s := range strArr {
num, err := strconv.Atoi(s)
if err != nil {
return nil, err
}
arr = append(arr, uint32(num))
}
return arr, nil
}
// 更新零售订单商品表的库存商品表主键id字段
func updateErpStockCommodityID(gdb *gorm.DB, id uint32, nIdList []uint32) error {
strId := intArrayToString(nIdList)
// 查找在库的非串码商品
var stockCommodity ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("id = ?", strId).First(&stockCommodity).Error
if err != nil {
logger.Error("get erp_stock_commodity err:", logger.Field("err", err))
return err
}
err = gdb.Table("erp_order_commodity").Where("id = ?", id).
Updates(map[string]interface{}{
"erp_stock_commodity_id": strId,
"retail_price": stockCommodity.RetailPrice,
"wholesale_price": stockCommodity.WholesalePrice,
"staff_cost_price": stockCommodity.StaffCostPrice,
}).Error
//Update("erp_stock_commodity_id", strId).Error
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
return nil
}
// 找一个可用的库存商品表主键ID
func findRightErpStockCommodityId(idList map[uint32][]uint32, commodityId uint32, stockCommodity []ErpStockCommodity) (uint32, error) {
// 获取给定商品ID对应的ID列表
existingIds, ok := idList[commodityId]
if !ok || len(existingIds) == 0 {
// 如果对应的ID列表不存在或为空直接返回第一个库存商品的ID
if len(stockCommodity) > 0 {
return stockCommodity[0].ID, nil
}
return 0, fmt.Errorf("empty stock commodity list")
}
// 创建一个 map 用于快速查找已有的 ID
existingIdMap := make(map[uint32]bool)
for _, id := range existingIds {
existingIdMap[id] = true
}
// 遍历库存商品找到第一个不在已有ID列表中的ID并返回
for _, item := range stockCommodity {
if _, found := existingIdMap[item.ID]; !found {
return item.ID, nil
}
}
// 如果所有库存商品的ID都在已有的ID列表中则返回错误
return 0, fmt.Errorf("no available ID found for commodity ID: %d", commodityId)
}
// UpdateStock 扣减or添加库存
// 零售订单:
// 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"已售"
// 非串码通过门店id、商品id、商品名称查找库存详情表找到库存时间最长的然后更改其状态为"已售"。
// 同时扣减库存表对应的数量,-1
// 零售退货:
// 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"在库"
// 非串码通过门店id、商品id、商品名称查找库存详情表找到状态为"已售"且时间最近的单,将其状态改为"在库"
// 同时扣减库存表对应的数量,+1
func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state, auditState int) error {
var commodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", erpOrder.ID).
Find(&commodities).Error
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id
if erpOrder.RetailType == RetailTypeSale { // 零售订单
for i, _ := range commodities {
if commodities[i].IMEIType == 2 || commodities[i].IMEIType == 3 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Updates(map[string]interface{}{"state": state}).Error // 状态更新为已销售;反审核则更新为在库
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
if state == SoldOut { // 已售的订单才更新库存数量
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
} else { // 反审核时则库存数量+1
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
}
} else { // 非串码商品
if state == InStock { // 零售订单反审核
err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID).
Updates(map[string]interface{}{"state": state}).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 = ?",
erpOrder.StoreId, commodities[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
}
err = gdb.Table("erp_order_commodity").Where("id = ?", commodities[i].ID).
Updates(map[string]interface{}{
"erp_stock_commodity_id": "",
}).Error
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
} else { // 正常销售
if commodities[i].ErpStockCommodityID != "" { // 零售退货单反审核,默认当作销售单
err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID).
Updates(map[string]interface{}{"state": SoldOut}).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 = ?",
erpOrder.StoreId, commodities[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
// 添加的一条零售商品包含的非串码商品可能不止1个
var stockCommodityIdList []uint32
// 通过门店id商品id查找状态为1-在库的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, InStock, 1).
Order("first_stock_time ASC").Find(&stockCommodity).Error
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil || len(stockCommodity) == 0 {
return errors.New("find commodity no stock ")
}
// 找一个可用的库存商品表主键ID使用零售商品表的主键ID作为key
rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList,
commodities[i].ErpCommodityId, stockCommodity)
if err != nil {
return err
}
// 优先出库库存时间最长的数据
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Updates(map[string]interface{}{"state": state}).Error // 状态更新为销售锁定中;反审核则更新为在库
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
if state == SoldOut { // 已售的订单才更新库存数量
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
}
stockCommodityIdList = append(stockCommodityIdList, rightId)
usedStockCommodityIdList[commodities[i].ErpCommodityId] = append(usedStockCommodityIdList[commodities[i].ErpCommodityId], rightId)
err = updateErpStockCommodityID(gdb, commodities[i].ID, stockCommodityIdList)
if err != nil {
return err
}
}
}
}
}
} else if erpOrder.RetailType == RetailTypeRejected { // 零售退货订单
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Updates(map[string]interface{}{"state": InStock}).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 = ?",
erpOrder.StoreId, commodities[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
var stockCommodityIdList []uint32
if commodities[i].ErpStockCommodityID != "" {
err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID).
Updates(map[string]interface{}{"state": InStock}).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 = ?",
erpOrder.StoreId, commodities[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 {
// 添加的一条零售商品包含的非串码商品可能不止1个
for j := 0; j < int(commodities[i].Count); j++ {
// 通过门店id商品id查找状态为2-已售的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, SoldOut, NoIMEICommodity).
Order("first_stock_time 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")
}
// 找一个可用的库存商品表主键ID
rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList,
commodities[i].ErpCommodityId, stockCommodity)
if err != nil {
return err
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId).
Updates(map[string]interface{}{"state": InStock}).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 = ?",
erpOrder.StoreId, commodities[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
}
stockCommodityIdList = append(stockCommodityIdList, rightId)
usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId)
}
err = updateErpStockCommodityID(gdb, commodities[i].ID, stockCommodityIdList)
if err != nil {
return err
}
}
}
}
} else {
return errors.New("订单类型错误")
}
// 判断用户是不是会员,只有会员才会积分,否则不积分
userInfo, err := GetUserInfoByUid(uint32(erpOrder.Uid))
if err != nil {
logger.Error("UpdateStock GetUserInfoByUid err:", logger.Field("err", err))
return err
}
if IsInMemberLevels(userInfo.MemberLevel) {
// 更新用户积分
var vmCount int
var describe, event string
if erpOrder.RetailType == RetailTypeSale && state == SoldOut { // 零售订单,而且订单已支付,更新用户积分
if auditState == 2 {
describe = "零售退货反审核获得积分"
} else {
describe = "零售销售获得积分"
}
event = VmEventErpOrderSale
vmCount = tools.RoundFloat64(erpOrder.TotalAmount)
} else if erpOrder.RetailType == RetailTypeRejected { // 退货订单,扣减用户积分(需校验购物时已积分,有则扣除)
var count int64
err = orm.Eloquent.Table("user_vm_record").Where("erp_order_id = ?", erpOrder.SaleOrderId).
Count(&count).Error
if err != nil {
logger.Errorf("query user_vm_record error, erp_order_id is:", erpOrder.SaleOrderId)
}
// 积过分才扣除
if count > 0 {
describe = "零售退货扣除积分"
event = VmEventErpOrderReject
vmCount = 0 - tools.RoundFloat64(erpOrder.TotalAmount)
} else {
return nil
}
} else {
return nil
}
err = UserVmUpdate(gdb, erpOrder.ID, uint32(erpOrder.Uid), vmCount, event, describe)
if err != nil {
logger.Errorf("err:", err)
return err
}
}
return nil
}
// CheckIsOnlinePay 检查是否包含线上支付
func CheckIsOnlinePay(jCashier []ErpOrderCashier) bool {
for _, cashier := range jCashier {
if cashier.CashierId == OnlinePay || strings.Contains(cashier.Name, "微信") || strings.Contains(cashier.Name, "支付宝") {
return true
}
}
return false
}
// NewErpBillSn 生成零售订单号
func NewErpBillSn() 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_order WHERE bill_sn='%s'", sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
}
max++
}
}
// ErpOrderRetailDetailSetCommodity 添加零售明细中订单的商品信息
func ErpOrderRetailDetailSetCommodity(list []ErpOrder) {
for i, _ := range list {
list[i].SetRetailDetailCommodity()
list[i].StorePer = tools.RoundToTwoDecimalPlaces(list[i].StorePer)
if list[i].RetailType == RetailTypeRejected { // 退货订单,金额需要转换为负值
list[i].TotalRetailPrice = -math.Abs(list[i].TotalRetailPrice)
list[i].TotalAmount = -math.Abs(list[i].TotalAmount)
list[i].TotalCount = -int32(math.Abs(float64(list[i].TotalCount)))
//list[i].TotalSalesProfit = -math.Abs(list[i].TotalSalesProfit)
//list[i].TotalStaffProfit = -math.Abs(list[i].TotalStaffProfit)
list[i].TotalSalesProfit = -list[i].TotalSalesProfit
list[i].TotalStaffProfit = -list[i].TotalStaffProfit
list[i].TotalDiscount = -math.Abs(list[i].TotalDiscount)
list[i].VmCount = -uint32(math.Abs(float64(list[i].VmCount)))
if list[i].TotalStaffProfit > 0 {
list[i].StorePer = math.Abs(list[i].StorePer)
} else {
list[i].StorePer = -math.Abs(list[i].StorePer)
}
}
}
}
func (m *ErpOrder) SetRetailDetailCommodity() {
var orderCommodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", m.ID).Find(&orderCommodities).Error
if err != nil {
logger.Error("SetCommodity query erp_order_commodity err:", logger.Field("err", err))
}
var respOrderCommodities []ErpOrderCommodity
for _, item := range orderCommodities {
if m.RetailType == RetailTypeRejected { // 退货订单,金额需要转换为负值
item.Count = -item.Count
item.RetailPrice = -item.RetailPrice
item.SalePrice = -item.SalePrice
item.Amount = -item.Amount
item.SaleDiscount = -item.SaleDiscount
item.MemberDiscount = -item.MemberDiscount
item.VmDiscount = -item.VmDiscount
item.ReceivedAmount = -item.ReceivedAmount
item.RejectedAmount = -item.RejectedAmount
item.SalesProfit = -item.SalesProfit
item.StaffProfit = -item.StaffProfit
item.StaffCostPrice = -item.StaffCostPrice
item.WholesalePrice = -item.WholesalePrice
}
item.StaffPrice = item.StaffCostPrice + item.WholesalePrice
if item.IMEIType == 2 || item.IMEIType == 3 || item.IMEI != "" { // 串码
respOrderCommodities = append(respOrderCommodities, item)
} else { // 非串码
idList, err := stringToIntArray(item.ErpStockCommodityID)
if err != nil {
respOrderCommodities = append(respOrderCommodities, item)
continue
}
for _, stockCommodityId := range idList {
var orderCommodity ErpOrderCommodity
orderCommodity = item
if m.RetailType == RetailTypeRejected { // 退货订单,数量需要转换为负值
orderCommodity.Count = -1
} else {
orderCommodity.Count = 1
}
nCount := math.Abs(float64(item.Count))
orderCommodity.SaleDiscount = item.SaleDiscount / nCount
orderCommodity.VmDiscount = item.VmDiscount / nCount
orderCommodity.ReceivedAmount = item.ReceivedAmount / nCount
orderCommodity.RejectedAmount = item.RejectedAmount / nCount
orderCommodity.SalesProfit = item.SalesProfit / nCount
orderCommodity.StaffProfit = item.StaffProfit / nCount
// 查询库存商品信息
var stockCommodity ErpStockCommodity
err = orm.Eloquent.Table("erp_stock_commodity").
Where("id = ?", stockCommodityId).Find(&stockCommodity).Error
if err != nil {
respOrderCommodities = append(respOrderCommodities, item)
continue
}
orderCommodity.ErpSupplierId = stockCommodity.ErpSupplierId
orderCommodity.ErpSupplierName = stockCommodity.ErpSupplierName
orderCommodity.WholesalePrice = stockCommodity.WholesalePrice
orderCommodity.StaffCostPrice = stockCommodity.StaffCostPrice
orderCommodity.StaffPrice = orderCommodity.WholesalePrice + orderCommodity.StaffCostPrice
if m.RetailType == RetailTypeRejected { // 退货订单,数量需要转换为负值
orderCommodity.WholesalePrice = -orderCommodity.WholesalePrice
orderCommodity.StaffCostPrice = -orderCommodity.StaffCostPrice
orderCommodity.StaffPrice = -orderCommodity.StaffPrice
}
respOrderCommodities = append(respOrderCommodities, orderCommodity)
}
}
}
m.Commodities = respOrderCommodities
}
// 添加订单的商品信息
func erpOrderListSetCommodity(list []ErpOrder) {
for i, _ := range list {
list[i].SetCommodity()
}
}
func (m *ErpOrder) SetCommodity() {
var orderCommodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", m.ID).Find(&orderCommodities).Error
if err != nil {
logger.Error("SetCommodity query erp_order_commodity err:", logger.Field("err", err))
}
m.Commodities = mergeOrderCommodities(orderCommodities)
}
// 合并重复的商品数据
func mergeOrderCommodities(orderCommodities []ErpOrderCommodity) []ErpOrderCommodity {
// 创建一个map来存储每个(ErpOrderId, ErpCommodityId)组合的合并结果
type key struct {
ErpOrderId uint32
ErpCommodityId uint32
IMEI string
}
commodityMap := make(map[key]*ErpOrderCommodity)
// 遍历orderCommodities将相同ErpCommodityId的数量累加
for _, commodity := range orderCommodities {
comboKey := key{ErpOrderId: commodity.ErpOrderId, ErpCommodityId: commodity.ErpCommodityId, IMEI: commodity.IMEI}
if existingCommodity, exists := commodityMap[comboKey]; exists {
existingCommodity.Count += commodity.Count
existingCommodity.SalesProfit += commodity.SalesProfit
existingCommodity.StaffProfit += commodity.StaffProfit
existingCommodity.SaleDiscount += commodity.SaleDiscount
existingCommodity.MemberDiscount += commodity.MemberDiscount
existingCommodity.ReceivedAmount += commodity.ReceivedAmount
existingCommodity.ErpStockCommodityID = strings.Join([]string{existingCommodity.ErpStockCommodityID, commodity.ErpStockCommodityID}, ",")
} else {
// 使用commodity的副本避免对原始数据的修改
commodityCopy := commodity
commodityMap[comboKey] = &commodityCopy
}
}
// 将map转换回orderCommodities列表
var mergedCommodities []ErpOrderCommodity
for _, commodity := range commodityMap {
mergedCommodities = append(mergedCommodities, *commodity)
}
return mergedCommodities
}
// 添加订单的销售员信息
func erpOrderListSetSalesmanByRetailDetail(userId uint32, list []ErpOrder) {
for i, _ := range list {
_ = list[i].SetOrderSalesmanRetailDetail(userId)
}
}
func (m *ErpOrder) SetOrderSalesmanRetailDetail(userId uint32) error {
var salesProfit, staffProfit, totalStaffProfit float64
//获取销售毛利、员工毛利数据
for _, item := range m.Commodities {
erpCommodity, err := GetCommodity(item.ErpCommodityId)
if err != nil {
logger.Error("GetCommodity err:", logger.Field("err", err))
}
salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
totalStaffProfit += item.StaffProfit
}
// 四舍五入并保留两位小数
salesProfit = math.Round(salesProfit*100) / 100
staffProfit = math.Round(staffProfit*100) / 100
totalStaffProfit = math.Round(totalStaffProfit*100) / 100
var salesmanInfo []ErpOrderSales
err := orm.Eloquent.Model(&ErpOrderSales{}).Where("erp_order_id = ?", m.ID).Find(&salesmanInfo).Error
if err != nil {
return err
}
var salesmanList []ErpOrderSales
for _, item := range salesmanInfo {
item.SalesProfitPer = salesProfit / float64(len(salesmanInfo))
item.StaffProfitPer = staffProfit / float64(len(salesmanInfo))
// 获取员工毛利
userInfo, err := GetSysUserInfoById(item.Uid)
if err != nil {
logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
}
item.Name = userInfo.NickName
item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(salesmanInfo))
//if m.RetailType == RetailTypeRejected {
// item.SalesProfitPer = -item.SalesProfitPer
// item.StaffProfitPer = -item.StaffProfitPer
// item.SalesmanPer = -item.SalesmanPer
//}
if userId != item.Uid {
item.SalesProfitPer = 0
item.StaffProfitPer = 0
item.SalesmanPer = 0
}
salesmanList = append(salesmanList, item)
}
if len(salesmanList) == 0 {
m.Salesman = []ErpOrderSales{}
} else {
m.Salesman = salesmanList
}
m.SalesmanList = ""
return nil
}
// 添加订单的销售员信息
func erpOrderListSetSalesman(list []ErpOrder) {
for i, _ := range list {
_ = list[i].SetOrderSalesman()
}
}
func (m *ErpOrder) SetOrderSalesman() error {
var salesProfit, staffProfit, totalStaffProfit float64
//获取销售毛利、员工毛利数据
for _, item := range m.Commodities {
erpCommodity, err := GetCommodity(item.ErpCommodityId)
if err != nil {
logger.Error("GetCommodity err:", logger.Field("err", err))
}
salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
totalStaffProfit += item.StaffProfit
}
// 四舍五入并保留两位小数
salesProfit = math.Round(salesProfit*100) / 100
staffProfit = math.Round(staffProfit*100) / 100
totalStaffProfit = math.Round(totalStaffProfit*100) / 100
var salesmanInfo []ErpOrderSales
err := orm.Eloquent.Model(&ErpOrderSales{}).Where("erp_order_id = ?", m.ID).Find(&salesmanInfo).Error
if err != nil {
return err
}
var salesmanList []ErpOrderSales
for _, item := range salesmanInfo {
item.SalesProfitPer = salesProfit / float64(len(salesmanInfo))
item.StaffProfitPer = staffProfit / float64(len(salesmanInfo))
// 获取员工毛利
userInfo, err := GetSysUserInfoById(item.Uid)
if err != nil {
logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
}
item.Name = userInfo.NickName
item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(salesmanInfo))
//if m.RetailType == RetailTypeRejected {
// item.SalesProfitPer = -item.SalesProfitPer
// item.StaffProfitPer = -item.StaffProfitPer
// item.SalesmanPer = -item.SalesmanPer
//}
salesmanList = append(salesmanList, item)
}
if len(salesmanList) == 0 {
m.Salesman = []ErpOrderSales{}
} else {
m.Salesman = salesmanList
}
m.SalesmanList = ""
return nil
}
func (m *ErpOrder) SetSalesman() {
if m.SalesmanList != "" {
var salesman []ErpOrderSales
err := json.Unmarshal([]byte(m.SalesmanList), &salesman)
if err != nil {
logger.Error("unmarshal err:", logger.Field("err", err))
}
m.Salesman = salesman
m.SalesmanList = ""
}
}
func (m *ErpOrderCreateReq) GetSalesmanList() (string, error) {
var salesProfit, staffProfit, totalStaffProfit float64
//获取销售毛利、员工毛利数据
for _, item := range m.ErpOrderCommodities {
erpCommodity, err := GetCommodity(item.ErpCommodityId)
if err != nil {
logger.Error("GetCommodity err:", logger.Field("err", err))
}
salesProfit += item.SalesProfit * erpCommodity.Brokerage1 * 0.01
staffProfit += item.StaffProfit * erpCommodity.Brokerage2 * 0.01
totalStaffProfit += item.StaffProfit
}
var salesmanList []ErpOrderSales
for _, item := range m.Salesman {
item.SalesProfitPer = salesProfit / float64(len(m.Salesman))
item.StaffProfitPer = staffProfit / float64(len(m.Salesman))
// 获取员工毛利
userInfo, err := GetSysUserInfoById(item.Uid)
if err != nil {
logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
}
item.Name = userInfo.NickName
//item.SalesmanPer = staffProfit * userInfo.SalesCommRate * 0.01 / float64(len(m.Salesman))
item.SalesmanPer = totalStaffProfit * userInfo.SalesCommRate * 0.01 / float64(len(m.Salesman))
// 四舍五入并保留两位小数
item.SalesProfitPer = math.Round(item.SalesProfitPer*100) / 100
item.StaffProfitPer = math.Round(item.StaffProfitPer*100) / 100
item.SalesmanPer = math.Round(item.SalesmanPer*100) / 100
salesmanList = append(salesmanList, item)
}
m.Salesman = salesmanList
jSalesman, err := json.Marshal(m.Salesman)
if err != nil {
logger.Error("salesman marshal err:", logger.Field("err", err))
return "", err
}
return string(jSalesman), nil
}
// 添加订单的付款信息
func erpOrderListSetCashier(list []ErpOrder) {
for i, _ := range list {
list[i].SetErpCashier()
}
}
func (m *ErpOrder) SetErpCashier() {
//if m.CashierList != "" && m.RetailType == RetailTypeSale { // 临时限制,退货订单不展示具体付款方式
if m.CashierList != "" {
var cashiers []ErpOrderCashier
err := json.Unmarshal([]byte(m.CashierList), &cashiers)
if err != nil {
logger.Error("unmarshal err:", logger.Field("err", err))
}
if m.RetailType == RetailTypeRejected {
for i, _ := range cashiers {
cashiers[i].Amount = -cashiers[i].Amount
}
}
m.Cashiers = cashiers
m.CashierList = ""
}
}
// 添加订单的付款信息
func erpRetailDetailSetCashier(list []ErpOrder) {
for i, _ := range list {
list[i].SetErpRetailDetailCashier()
}
}
func (m *ErpOrder) SetErpRetailDetailCashier() {
if m.CashierList != "" {
var cashiers []ErpOrderCashier
err := json.Unmarshal([]byte(m.CashierList), &cashiers)
if err != nil {
logger.Error("unmarshal err:", logger.Field("err", err))
}
if m.RetailType == RetailTypeRejected {
for i, _ := range cashiers {
cashiers[i].Amount = -cashiers[i].Amount
}
}
var nTotalOtherAmount float64
var newCashiers []ErpOrderCashier
for _, item := range cashiers {
if item.CashierId > 4 {
nTotalOtherAmount += item.Amount
} else {
newCashiers = append(newCashiers, item)
}
}
// 将所有其他类型的支付方式合并到一起
newCashiers = append(newCashiers, ErpOrderCashier{8090, "", nTotalOtherAmount})
m.Cashiers = newCashiers
m.CashierList = ""
}
}
func GetErpOrderCommodityMap(ids []uint32, req *ErpOrderCreateReq) (map[uint32]ErpOrderCommodity, error) {
commodityMap := make(map[uint32]ErpOrderCommodity, 0)
if len(ids) == 0 {
return commodityMap, nil
}
var commodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id ").
Where("erp_order_commodity.erp_commodity_id IN (?) and erp_order.store_id = ? "+
"and erp_order.retail_type = ? and erp_order.pay_status = ? and erp_order.tel = ?",
ids, req.StoreId, RetailTypeSale, HavePaid, req.Tel).
Find(&commodities).Order("audit_time DESC").Error
//var commodities []ErpOrderCommodity
//err := orm.Eloquent.Table("erp_order_commodity").Where("erp_commodity_id IN (?)", ids).Find(&commodities).Error
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return commodityMap, err
}
// 合并数据
commodities = mergeOrderCommodities(commodities)
for i, _ := range commodities {
commodityMap[commodities[i].ErpCommodityId] = commodities[i]
}
return commodityMap, nil
}
func SetUserInfo(tel string) {
var user UserInfo
err := orm.Eloquent.Table("user").Where("tel=?", tel).Find(&user).Error
if err != nil {
logger.Error("user err:", logger.Field("err", err))
return
}
if user.FirstRetailOrder == nil {
err := orm.Eloquent.Table("user").Where("uid=?", user.Uid).
Updates(map[string]interface{}{"first_retail_order": time.Now()}).Error
if err != nil {
logger.Error("update user err:", logger.Field("err", err))
}
}
}
// SetInvoice 设置发票内容
func SetInvoice(req *ErpOrderAddInvoiceReq, c *gin.Context) error {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
logger.Errorf("err:%#v", err)
return err
}
var orderInfo ErpOrder
err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error
if err != nil {
logger.Error("操作失败,未查询到订单", logger.Field("err", err))
return errors.New("未查询到订单")
}
if orderInfo.State == ErpOrderStateUnAudit {
logger.Errorf("order delete err, state is:", orderInfo.State)
return errors.New("订单未审核")
}
if orderInfo.PayStatus != 2 {
logger.Errorf("order delete err, state is:", orderInfo.State)
return errors.New("订单未支付")
}
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
// 校验入参门店是否包含在用户所有门店中,是否过期
if !CheckUserStore(orderInfo.StoreId, sysUser) {
return errors.New("操作失败:您没有该门店权限")
}
}
err = orm.Eloquent.Table("erp_order").Where("id = ?", orderInfo.ID).Updates(map[string]interface{}{
"invoice_code": req.InvoiceCode,
"invoice_number": req.InvoiceNumber,
}).Error
if err != nil {
logger.Error("AddInvoice err:", logger.Field("err", err))
return err
}
return nil
}
// DeleteOrder 删除订单
func DeleteOrder(req *ErpOrderDeleteReq, c *gin.Context) error {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
logger.Errorf("err:%#v", err)
return err
}
var orderInfo ErpOrder
err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error
if err != nil {
logger.Error("order delete err:", logger.Field("err", err))
return errors.New("未查询到订单")
}
if orderInfo.State != ErpOrderStateUnAudit {
logger.Errorf("order delete err, state is:", orderInfo.State)
return errors.New("已审核订单不能删除")
}
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
// 校验入参门店是否包含在用户所有门店中,是否过期
if !CheckUserStore(orderInfo.StoreId, sysUser) {
return errors.New("操作失败:您没有该门店权限")
}
}
var orderCommodities []ErpOrderCommodity
err = orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", orderInfo.ID).Find(&orderCommodities).Error
if err != nil {
logger.Error("order delete err:", logger.Field("err", err))
return errors.New("未查询到订单商品信息")
}
begin := orm.Eloquent.Begin()
err = begin.Delete(&orderCommodities).Error
if err != nil {
begin.Rollback()
logger.Error("order delete1 err:", logger.Field("err", err))
return err
}
err = begin.Delete(orderInfo).Error
if err != nil {
begin.Rollback()
logger.Error("order delete2 err:", logger.Field("err", err))
return err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("order delete3 err:", logger.Field("err", err))
return err
}
return nil
}
// 生成序列号
func genErpOrderSerialNo() string {
currentDate := time.Now().Format("20060102")
tradeNO := "sale" + currentDate + pay.RandomNumString(10000000, 99999999)
return tradeNO
}
// GetErpOrderSn 生成零售订单号
func GetErpOrderSn() string {
var erpOrderSn string
for {
erpOrderSn = genErpOrderSerialNo()
var count int64
err := orm.Eloquent.Table("erp_order_record").Where("out_order_no=?", erpOrderSn).Count(&count)
if err != nil {
logger.Error("err:", logger.Field("err", err))
}
if count == 0 {
break
}
}
return erpOrderSn
}
// 查询是否有已支付的订单
func checkIsPayOk(billSn string) bool {
var count int64
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, PayOk).
Count(&count).Error
if err != nil {
logger.Error("checkIsPayOk err:", logger.Field("err", err))
}
return count > 0
}
// 查询是否有待支付的订单
func checkIsPaying(billSn string) bool {
var count int64
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, Paying).
Count(&count).Error
if err != nil {
logger.Error("checkIsPayOk err:", logger.Field("err", err))
}
return count > 0
}
// 查询是否有刚初始化的订单
func checkIsPayInit(billSn string) bool {
var count int64
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, PayInit).
Count(&count).Error
if err != nil {
logger.Error("checkIsPayOk err:", logger.Field("err", err))
}
return count > 0
}
// ErpOrderPay 零售订单支付
func ErpOrderPay(req *ErpOrderPayReq, c *gin.Context) (*ErpOrderPayResp, error) {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
logger.Errorf("err:%#v", err)
return nil, err
}
resp := &ErpOrderPayResp{
Status: PayFailed,
}
//通过单据号查询收款金额
var orderInfo ErpOrder
err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error
if err != nil {
logger.Error("未查询到订单:", logger.Field("err", err))
return resp, err
}
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
// 校验入参门店是否包含在用户所有门店中,是否过期
if !CheckUserStore(orderInfo.StoreId, sysUser) {
return nil, errors.New("操作失败:您没有该门店权限")
}
}
if orderInfo.PayStatus == HavePaid {
logger.Error("ErpOrderPay err, 订单已支付")
return resp, errors.New("订单已支付")
}
if orderInfo.PayStatus != WaitForPaying {
logger.Error("ErpOrderPay err, 订单不是待支付状态")
return resp, errors.New("订单不是待支付状态")
}
var cashiers []ErpOrderCashier
err = json.Unmarshal([]byte(orderInfo.CashierList), &cashiers)
if err != nil {
logger.Error("unmarshal CashierList err:", logger.Field("err", err))
}
var amount float64
for i, _ := range cashiers {
if cashiers[i].CashierId == OnlinePay { //线上支付
amount = cashiers[i].Amount
break
}
}
if amount == 0 {
logger.Error("ErpOrderPay err, 订单金额为0")
return resp, errors.New("订单金额为0")
}
// dev环境测试默认金额都为0.1元
if config.ApplicationConfig.Mode == "dev" {
amount = 0.1
}
// 查询是否有已支付的订单
if checkIsPayOk(req.BillSn) {
// 更新零售订单表
err = orm.Eloquent.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).
Updates(map[string]interface{}{"pay_status": HavePaid}).Error
if err != nil {
logger.Error("ErpOrderPay update erp_order_record err:", logger.Field("err", err))
}
resp.Status = PayOk
logger.Error("ErpOrderPay err2, 订单已支付")
return resp, errors.New("订单已支付")
}
// 查询是否有待支付订单
if checkIsPaying(req.BillSn) {
queryResp, err := QueryErpOrderPayStatus(req.BillSn)
if err != nil {
logger.Error("查询订单失败", logger.Field("err", err))
return resp, err
}
// 等待支付或成功支付则返回,否则新建订单
if queryResp.Status == Paying || queryResp.Status == PayOk {
resp.Status = queryResp.Status
return resp, nil
}
}
// 查询是否有刚初始化的订单
var orderSn string
if checkIsPayInit(req.BillSn) {
var orderRecordInfo ErpOrderRecord
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", req.BillSn, PayInit).
Find(&orderRecordInfo).Error
if err != nil {
logger.Error("未查询到订单:", logger.Field("err", err))
return resp, errors.New("未查询到待支付订单")
}
orderSn = orderRecordInfo.OutOrderNo
} else {
// 创建支付订单号,并记录到支付记录表,关联零售订单号
orderSn = GetErpOrderSn()
var erpOrderRecord ErpOrderRecord
erpOrderRecord.ErpOrderId = orderInfo.ID
erpOrderRecord.BillSn = orderInfo.BillSn
erpOrderRecord.OutOrderNo = orderSn
erpOrderRecord.Status = PayInit
err = orm.Eloquent.Table("erp_order_record").Create(&erpOrderRecord).Error
if err != nil {
logger.Error("Create erp_order_record err:", logger.Field("err", err))
return resp, err
}
}
resp.Status = Paying
// 发起支付扣款
hmPayResp, err := pay.HmJsPayBToCOrder(orderSn, amount, req.AuthCode, "")
if err != nil {
logger.Error("HmJsPayBToCOrder err")
return resp, err
}
// 更新支付状态
var payStatus string
switch hmPayResp.SubCode {
case "SUCCESS":
payStatus = PayOk
case "FAILED":
payStatus = PayFailed
case "WAITING_PAYMENT":
payStatus = Paying
//default:
// payStatus = PayUnknown
}
updateInfo := map[string]interface{}{
"bank_order_no": hmPayResp.BankOrderNo,
"plat_trx_no": hmPayResp.PlatTrxNo,
"total_amount": hmPayResp.TotalAmount,
"pay_way": hmPayResp.PayWay,
"status": payStatus,
}
begin := orm.Eloquent.Begin()
err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderSn).
Updates(updateInfo).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order_record err:", logger.Field("err", err))
return resp, err
}
if payStatus == PayOk { // 支付成功
// 更新零售订单表
err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).
Updates(map[string]interface{}{"pay_status": HavePaid}).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order_record err:", logger.Field("err", err))
return resp, err
}
//// 更新库存订单表
//err = updateErpStockCommodity(begin, req.BillSn)
//if err != nil {
// logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err))
// return resp, err
//}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
return resp, fmt.Errorf("ErpOrderPay[commit err]%v", err)
}
resp.Status = payStatus
return resp, nil
}
// QueryErpOrderPayStatus 查询零售订单支付状态
func QueryErpOrderPayStatus(billSn string) (*ErpOrderPayResp, error) {
resp := &ErpOrderPayResp{
Status: Paying,
}
// 查询待支付订单
var orderRecordInfo ErpOrderRecord
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status in (?)", billSn, []string{Paying, PayOk}).
Find(&orderRecordInfo).Error
if err != nil {
logger.Error("未查询到订单:", logger.Field("err", err))
resp.Status = PayFailed
return resp, errors.New("未查询到待支付订单")
}
if orderRecordInfo.OutOrderNo == "" {
logger.Info("还未创建支付订单")
resp.Status = NoPayOrder
return resp, nil
}
if orderRecordInfo.Status == PayOk {
logger.Info("订单已支付")
resp.Status = PayOk
return resp, nil
}
// 查询支付状态
hmQueryResp, err := pay.HmQueryOrder(orderRecordInfo.OutOrderNo)
if err != nil {
logger.Error("查询失败:", logger.Field("err", err))
return resp, err
}
// 更新订单状态
var payStatus string
switch hmQueryResp.SubCode {
case "SUCCESS":
payStatus = PayOk
case "FAILED":
payStatus = PayFailed
case "WAITING_PAYMENT":
payStatus = Paying
//default:
// payStatus = PayUnknown
}
updateInfo := map[string]interface{}{
"bank_order_no": hmQueryResp.BankOrderNo,
"plat_trx_no": hmQueryResp.PlatTrxNo,
"total_amount": hmQueryResp.TotalAmount,
"pay_way": hmQueryResp.PayWayCode,
"status": payStatus,
}
begin := orm.Eloquent.Begin()
err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderRecordInfo.OutOrderNo).
Updates(updateInfo).Error
if err != nil {
begin.Rollback()
logger.Error("query update erp_order_record err:", logger.Field("err", err))
return resp, err
}
if payStatus == PayOk { // 支付成功
// 更新零售订单表
err = begin.Model(&ErpOrder{}).Where("id = ?", orderRecordInfo.ErpOrderId).
Updates(map[string]interface{}{"pay_status": HavePaid}).Error
if err != nil {
begin.Rollback()
logger.Error("query update erp_order_record err:", logger.Field("err", err))
return resp, err
}
//// 更新库存订单表
//err = updateErpStockCommodity(begin, billSn)
//if err != nil {
// logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err))
// return resp, err
//}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
return resp, fmt.Errorf("QueryErpOrderPayStatus[commit err]%v", err)
}
resp.Status = payStatus
return resp, nil
}
// 更新库存订单表
func updateErpStockCommodity(gdb *gorm.DB, billSn string) error {
//通过单据号查询订单
var erpOrderInfo []ErpOrder
err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", billSn).Find(&erpOrderInfo).Error
if err != nil {
logger.Error("erp_order 未查询到订单:", logger.Field("err", err))
return err
}
if len(erpOrderInfo) == 0 {
return errors.New("未查询到订单")
}
err = UpdateStock(gdb, erpOrderInfo[0], SoldOut, 0)
if err != nil {
gdb.Rollback()
logger.Error("updateErpStockCommodity UpdateStock err:", logger.Field("err", err))
return errors.New("审核失败:" + err.Error())
}
return nil
}
// CommodityIsHaveStock 查询商品是否有库存
func CommodityIsHaveStock(req ErpOrderCommodity, storeId uint32) bool {
qs := orm.Eloquent.Table("erp_stock_commodity")
if req.IMEI != "" { // 串码商品
qs.Where("imei = ? and state = ?", req.IMEI, InStock)
} else { // 非串码商品
qs.Where("erp_commodity_id = ? and store_id = ? and state = ? and imei_type = ?",
req.ErpCommodityId, storeId, InStock, NoIMEICommodity)
}
var count int64
err := qs.Count(&count).Error
if err != nil {
logger.Error("CommodityIsHaveStock err:", logger.Field("err", err))
}
return count > 0
}
// QueryStoreManageData 查询门店经营数据
func QueryStoreManageData(req *ErpOrderStoreManageDataReq, c *gin.Context) (*ErpOrderStoreManageDataResp, error) {
showConfig, err := GetErpOrderShowConfig()
if err != nil {
logger.Errorf("List err:", err)
showConfig.ShowAll = "ON"
}
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpOrderStoreManageDataResp{
PageIndex: req.PageIndex,
PageSize: req.PageSize,
}
var storeManageDataList []StoreManageData
// 构建查询条件
qs := orm.Eloquent.Model(&ErpOrder{})
if req.StoreId != 0 {
qs = qs.Where("store_id = ?", req.StoreId)
}
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
if len(storeList) == 1 {
qs = qs.Where("store_id = ?", storeList[0])
} else {
qs = qs.Where("store_id IN (?)", storeList)
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
if showConfig.ShowAll == "OFF" {
qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
}
if req.StartTime != "" && req.EndTime != "" {
startTime, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Error("startTime parse err")
}
endTime, err := time.Parse(QueryTimeFormat, req.EndTime)
if err != nil {
logger.Error("endTime parse err")
}
//startTime, _ := time.Parse("2006-01-02", req.StartTime)
//endTime, _ := time.Parse("2006-01-02", req.EndTime)
qs = qs.Where("maker_time BETWEEN ? AND ?", startTime, endTime)
} else {
qs = qs.Where("maker_time IS NOT NULL")
}
qs.Where("state = ?", ErpOrderStateAudited)
// 查询数据
if req.SortType == "asc" {
err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_discount ELSE -total_discount END) AS promotion_fee, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_amount ELSE -total_amount END) AS total_sales_amount, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_sales_profit ELSE -total_sales_profit END) AS sales_profit, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_staff_profit ELSE -total_staff_profit END) AS staff_profit, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_count ELSE -total_count END) AS count").
Group("date").
Order("date ASC").
Find(&storeManageDataList).Error
} else {
err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_discount ELSE -total_discount END) AS promotion_fee, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_amount ELSE -total_amount END) AS total_sales_amount, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_sales_profit ELSE -total_sales_profit END) AS sales_profit, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_staff_profit ELSE -total_staff_profit END) AS staff_profit, " +
"SUM(CASE WHEN retail_type = 'sale' THEN total_count ELSE -total_count END) AS count").
Group("date").
Order("date DESC").
Find(&storeManageDataList).Error
}
if err != nil {
logger.Error("QueryStoreManageData err:", logger.Field("err", err))
return nil, err
}
finalStoreManageDataList := constructFinalStoreManageDataList(storeManageDataList, req)
if req.IsExport == 1 { //导出excel
storeName := "所有门店"
if req.StoreId != 0 {
storeInfo, err := GetStore(req.StoreId)
if err != nil {
logger.Error("GetStore err:", logger.Field("err", err))
return nil, err
}
storeName = storeInfo.Name
}
finalStoreManageDataList = constructFinalStoreManageDataList(storeManageDataList, req)
filePath, err := storeManageDataExport(finalStoreManageDataList, storeName)
if err != nil {
logger.Error("StoreManageDataExport err:", logger.Field("err", err))
return nil, err
}
resp.ExportUrl = filePath
} else {
// 根据页码和页面条数截取结果
startIndex := (req.PageIndex - 1) * req.PageSize
endIndex := startIndex + req.PageSize
if endIndex > len(finalStoreManageDataList) {
endIndex = len(finalStoreManageDataList)
}
resp.List = finalStoreManageDataList[startIndex:endIndex]
resp.Total = len(finalStoreManageDataList)
}
return resp, nil
}
// 查询门店经营数据为空的日期默认填充数据为0
func constructFinalStoreManageDataList(storeManageDataList []StoreManageData, req *ErpOrderStoreManageDataReq) []StoreManageData {
// Create a map to store data by date for easier processing
storeDataMap := make(map[string]StoreManageData)
for _, data := range storeManageDataList {
storeDataMap[data.Date] = data
}
// Construct the final response with consecutive dates and defaulting to 0 for missing data
var finalStoreManageDataList []StoreManageData
startDate, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err))
return storeManageDataList
}
endDate, err := time.Parse(QueryTimeFormat, req.EndTime)
if err != nil {
logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err))
return storeManageDataList
}
for d := endDate; d.After(startDate) || d.Equal(startDate); d = d.AddDate(0, 0, -1) {
dateStr := d.Format("2006-01-02")
data, found := storeDataMap[dateStr]
if !found {
data = StoreManageData{
Date: dateStr,
TotalSalesAmount: 0,
PromotionFee: 0,
SalesProfit: 0,
StaffProfit: 0,
Count: 0,
}
}
finalStoreManageDataList = append(finalStoreManageDataList, data)
}
sortType := strings.ToLower(req.SortType)
switch sortType {
case "asc":
sort.Slice(finalStoreManageDataList, func(i, j int) bool {
return finalStoreManageDataList[i].Date < finalStoreManageDataList[j].Date
})
case "desc":
sort.Slice(finalStoreManageDataList, func(i, j int) bool {
return finalStoreManageDataList[i].Date > finalStoreManageDataList[j].Date
})
}
return finalStoreManageDataList
}
// StoreManageDataExport 导出门店经营数据
func storeManageDataExport(list []StoreManageData, storeName string) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + storeName + "经营数据" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"时间", "销售额", "推广费", "销售毛利", "员工毛利", "销售数量"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Errorf("file set value err:", err)
}
}
var row []interface{}
nExcelStartRow := 0
for rowId := 0; rowId < len(list); rowId++ {
row = []interface{}{
list[rowId].Date,
list[rowId].TotalSalesAmount,
list[rowId].PromotionFee,
list[rowId].SalesProfit,
list[rowId].StaffProfit,
list[rowId].Count,
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 18)
endRow := fmt.Sprintf("F"+"%d", nExcelStartRow+1)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// retailMarginDataExport 导出商品零售毛利汇总数据
func retailMarginDataExport(req *ErpOrderRetailMarginResp) (string, error) {
file := excelize.NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")
if err != nil {
fmt.Println(err)
}
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "商品零售毛利汇总" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"店铺名称", "零售类型", "商品名称", "商品分类", "数量", "销售/退货金额", "销售成本", "销售毛利", "销售毛利率"}
cell, _ := excelize.CoordinatesToCellName(1, 1)
if err = streamWriter.SetRow(cell, title); err != nil {
fmt.Println(err)
}
var row []interface{}
nExcelStartRow := 0
for rowId := 0; rowId < len(req.List); rowId++ {
var saleType string
if req.List[rowId].RetailType == RetailTypeSale {
saleType = "零售销售"
} else if req.List[rowId].RetailType == RetailTypeRejected {
saleType = "零售退货"
} else {
logger.Error("订单类型异常")
return "", errors.New("RetailMarginDataExport, 订单类型异常:" + req.List[rowId].RetailType)
}
row = []interface{}{
req.List[rowId].StoreName,
saleType,
req.List[rowId].ErpCommodityName,
req.List[rowId].ErpCategoryName,
req.List[rowId].Count,
req.List[rowId].SalesAmount,
req.List[rowId].SalesCost,
req.List[rowId].SalesMargin,
req.List[rowId].GrossMargins,
}
cell, _ := excelize.CoordinatesToCellName(1, nExcelStartRow+2)
if err := streamWriter.SetRow(cell, row); err != nil {
fmt.Println(err)
}
nExcelStartRow++
}
totalData := "汇总 记录数:" + strconv.FormatInt(int64(req.TotalCount), 10)
end := []interface{}{totalData, "", "", "", req.TotalCount, fmt.Sprintf("%.2f", req.TotalSalesAmount),
fmt.Sprintf("%.2f", req.TotalSalesCost),
fmt.Sprintf("%.2f", req.TotalSalesMargin),
req.TotalGrossMargins}
cell, _ = excelize.CoordinatesToCellName(1, nExcelStartRow+2)
if err := streamWriter.SetRow(cell, end); err != nil {
fmt.Println(err)
}
if err := streamWriter.Flush(); err != nil {
fmt.Println(err)
}
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// QueryRetailMargin 查询零售毛利汇总数据
func QueryRetailMargin(req *ErpOrderRetailMarginReq, c *gin.Context) (*ErpOrderRetailMarginResp, error) {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
req.StoreId = CompareLists(storeList, req.StoreId)
if len(req.StoreId) == 0 { // 没有匹配的数据,表示入参门店不是用户有权限的门店
return &ErpOrderRetailMarginResp{}, nil
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
showConfig, err := GetErpOrderShowConfig()
if err != nil {
logger.Errorf("List err:", err)
showConfig.ShowAll = "ON"
}
resp := &ErpOrderRetailMarginResp{
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_order_commodity").
Select("erp_order_commodity.*, erp_order.store_id, erp_order.store_name, erp_order.retail_type").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")
if len(req.StoreId) != 0 {
qs.Where("erp_order.store_id in ?", req.StoreId)
}
if len(req.RetailType) != 0 {
qs.Where("erp_order.retail_type in ?", req.RetailType)
}
if len(req.ErpCommodityName) != 0 {
qs.Where("erp_order_commodity.erp_commodity_name in ?", req.ErpCommodityName)
}
if len(req.ErpCategoryId) != 0 {
qs.Where("erp_order_commodity.erp_category_id in ?", req.ErpCategoryId)
}
if req.StartTime != "" {
startTime, err := time.Parse(QueryTimeFormat, req.StartTime)
if err == nil {
qs = qs.Where("erp_order.audit_time>?", startTime)
} else {
logger.Errorf("QueryRetailMargin time start parse err:", err.Error())
}
}
if req.EndTime != "" {
endTime, err := time.Parse(QueryTimeFormat, req.EndTime)
if err == nil {
qs = qs.Where("erp_order.audit_time<?", endTime)
} else {
logger.Errorf("QueryRetailMargin time end parse err:", err.Error())
}
}
if showConfig.ShowAll == "OFF" {
qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
}
var result []struct {
ErpOrderCommodity
StoreID uint32
StoreName string
RetailType string
}
qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
// 添加排序规则
//qs = qs.Order("erp_order_commodity.erp_commodity_id ASC, erp_order.store_id ASC, erp_order.retail_type ASC")
qs = qs.Order(`
erp_order_commodity.erp_commodity_id ASC,
erp_order.store_id ASC,
CASE erp_order.retail_type
WHEN 'sale' THEN 0
WHEN 'rejected' THEN 1
ELSE 2
END ASC`)
if req.IsExport == 1 { //导出excel
err := qs.Find(&result).Error
if err != nil {
logger.Errorf("QueryRetailMargin find err:", err.Error())
return nil, err
}
} else {
err := qs.Find(&result).Offset(page * req.PageSize).Limit(req.PageSize).Error
if err != nil {
logger.Errorf("QueryRetailMargin find err:", err.Error())
return nil, err
}
}
//var data RetailMarginData
var list []RetailMarginData
//for _, item := range result {
// data.StoreId = item.StoreID
// data.StoreName = item.StoreName
// data.RetailType = item.RetailType
// data.ErpCommodityId = item.ErpCommodityId
// data.ErpCommodityName = item.ErpCommodityName
// data.ErpCategoryId = item.ErpCategoryId
// data.ErpCategoryName = item.ErpCategoryName
// data.Total = item.Total
// data.SalesAmount = item.ReceivedAmount
// data.SalesCost = float64(item.WholesalePrice * item.Total)
// data.SalesMargin = data.SalesAmount - data.SalesCost
// data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount)
// if data.RetailType == RetailTypeRejected {
// data.SalesAmount = -data.SalesAmount
// data.SalesCost = -data.SalesCost
// data.SalesMargin = -data.SalesMargin
// }
// list = append(list, data)
//
// resp.TotalCount += data.Total
// resp.TotalSalesAmount += data.SalesAmount
// resp.TotalSalesCost += data.SalesCost
// resp.TotalSalesMargin += data.SalesMargin
//}
//
//if resp.TotalSalesAmount != 0 {
// resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount)
//}
// 创建一个 map 用来存储已经处理过的数据key 是 StoreId 和 ErpCommodityId 的组合
processedData := make(map[string]*RetailMarginData)
// 遍历 result 中的每一条数据
for _, item := range result {
// 生成一个唯一的键,可以使用 StoreId 和 ErpCommodityId 的组合
key := fmt.Sprintf("%d_%d_%s", item.StoreID, item.ErpCommodityId, item.RetailType)
var nCount int32
var salesAmount, salesCost, employeeCost, salesMargin float64
if item.RetailType == RetailTypeRejected {
nCount = -int32(item.Count)
salesAmount = -item.RejectedAmount // 退货订单要以实际退货金额为准
salesCost = -item.WholesalePrice * float64(item.Count)
employeeCost = -(item.WholesalePrice + item.StaffCostPrice) * float64(item.Count)
salesMargin = -(item.ReceivedAmount - item.WholesalePrice*float64(item.Count))
} else {
nCount = int32(item.Count)
salesAmount = item.ReceivedAmount
salesCost = item.WholesalePrice * float64(item.Count)
employeeCost = (item.WholesalePrice + item.StaffCostPrice) * float64(item.Count)
salesMargin = item.ReceivedAmount - item.WholesalePrice*float64(item.Count)
}
// 检查是否已经处理过这个组合的数据
if existingData, ok := processedData[key]; ok {
// 如果存在,说明已经有数据,进行合并操作
existingData.Count += nCount
existingData.SalesAmount += salesAmount
existingData.SalesCost += salesCost
existingData.SalesMargin += salesMargin
existingData.EmployeeCost += employeeCost
if existingData.SalesAmount == 0 {
existingData.GrossMargins = "--"
} else {
existingData.GrossMargins = float64ToPercentage(existingData.SalesMargin / existingData.SalesAmount)
}
} else {
// 如果不存在,说明是新数据,直接添加到列表中
data := &RetailMarginData{
StoreId: item.StoreID,
StoreName: item.StoreName,
RetailType: item.RetailType,
ErpCommodityId: item.ErpCommodityId,
ErpCommodityName: item.ErpCommodityName,
ErpCategoryId: item.ErpCategoryId,
ErpCategoryName: item.ErpCategoryName,
Count: nCount,
SalesAmount: item.ReceivedAmount,
SalesCost: item.WholesalePrice * float64(item.Count),
EmployeeCost: (item.WholesalePrice + item.StaffCostPrice) * float64(item.Count),
SalesMargin: item.ReceivedAmount - item.WholesalePrice*float64(item.Count),
GrossMargins: "--",
//GrossMargins: float64ToPercentage((item.ReceivedAmount - float64(int32(item.WholesalePrice)*item.Total)) / item.ReceivedAmount),
}
if item.ReceivedAmount != 0 {
data.GrossMargins = float64ToPercentage((item.ReceivedAmount - item.WholesalePrice*float64(item.Count)) / item.ReceivedAmount)
}
// 如果是拒绝的销售,进行相应的处理
if data.RetailType == RetailTypeRejected {
data.SalesAmount = -data.SalesAmount
data.SalesCost = -data.SalesCost
data.SalesMargin = -data.SalesMargin
data.EmployeeCost = -data.EmployeeCost
}
// 处理数据四舍五入保留2位小数
data.SalesAmount = math.Round(data.SalesAmount*100) / 100
data.SalesCost = math.Round(data.SalesCost*100) / 100
data.SalesMargin = math.Round(data.SalesMargin*100) / 100
data.EmployeeCost = math.Round(data.EmployeeCost*100) / 100
// 将新数据添加到 map 中
processedData[key] = data
}
}
// 将处理过的数据添加到 resp.List 中
for _, data := range processedData {
list = append(list, *data)
}
// 计算总数
for _, data := range list {
resp.TotalCount += data.Count
resp.TotalSalesAmount += data.SalesAmount
resp.TotalSalesCost += data.SalesCost
resp.TotalSalesMargin += data.SalesMargin
resp.TotalEmployeeCost += data.EmployeeCost
}
// 处理数据四舍五入保留2位小数
resp.TotalSalesAmount = math.Round(resp.TotalSalesAmount*100) / 100
resp.TotalSalesCost = math.Round(resp.TotalSalesCost*100) / 100
resp.TotalSalesMargin = math.Round(resp.TotalSalesMargin*100) / 100
resp.TotalEmployeeCost = math.Round(resp.TotalEmployeeCost*100) / 100
if resp.TotalSalesAmount != 0 {
resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount)
} else {
resp.TotalGrossMargins = "--"
}
// 对列表按照您想要的顺序进行排序
sort.Slice(list, func(i, j int) bool {
// 按照 StoreId 升序排列
if list[i].StoreId != list[j].StoreId {
return list[i].StoreId < list[j].StoreId
}
// 按照 ErpCommodityId 升序排列
if list[i].ErpCommodityId != list[j].ErpCommodityId {
return list[i].ErpCommodityId < list[j].ErpCommodityId
}
// 按照 RetailType 的顺序进行排序
retailTypeOrder := map[string]int{"sale": 0, "rejected": 1}
return retailTypeOrder[list[i].RetailType] < retailTypeOrder[list[j].RetailType]
})
// 将结果赋值给 resp.List
resp.List = list
if req.IsExport == 1 { //导出excel
filePath, err := retailMarginDataExport(resp)
if err != nil {
logger.Error("StoreManageDataExport err:", logger.Field("err", err))
return nil, err
}
resp.ExportUrl = filePath
} else {
// 计算分页所需的切片索引
startIndex := page * req.PageSize
endIndex := (page + 1) * req.PageSize
if endIndex > len(list) {
endIndex = len(list)
}
resp.List = list[startIndex:endIndex]
resp.Total = len(list)
resp.PageIndex = req.PageIndex
resp.PageSize = req.PageSize
}
return resp, nil
}
// 将float64转换为百分比
func float64ToPercentage(value float64) string {
// 将浮点数乘以100然后格式化为字符串
percentage := fmt.Sprintf("%.2f%%", value*100)
return percentage
}
// QueryRetailDetail 查询零售明细
func QueryRetailDetail(req *ErpOrderRetailDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
resp := &ErpOrderRetailDetailResp{}
var err error
if (req.ErpCategoryId != 0 || req.ErpCommodityName != "" || req.IMEI != "") && req.BillSn == "" { // 商品分类or商品名称不为空且订单编号为空
// 联表查询
resp, err = queryRetailDetailByJoin(req, c)
} else {
// 普通单表查询,然后补充收款数据和商品数据
resp, err = queryRetailDetailCommon(req, c)
}
if err != nil {
logger.Error("queryRetailDetailCommon err")
return nil, err
}
return resp, nil
}
// 导出零售明细报表excel-合并单元格版本
func retailDetailExportBack(list []ErpOrder, sumData RetailDetailTotalData) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "零售明细" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"订单编号", "订单类型", "用户ID", "客户手机号", "审核时间", "店铺", "销售员", "商品分类", "商品名称",
"供应商", "是否串码", "商品串码", "是否赠送", "销售数量", "指导零售价", "零售价", "零售优惠", "会员优惠", "实际零售价/退货价",
"采购单价", "员工成本价", "销售毛利", "员工毛利", "订单总指导零售价", "订单总优惠", "订单实收", "【扫码付", "现金收款", "pos机收款",
"商场积分抵扣", "其他付款方式】", "订单总销售毛利", "订单总员工毛利", "销售毛利提成", "员工毛利提成", "销售员提成", "门店提成", "备注"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row []interface{}
nAmount := 0.0
nExcelStartRow := 0
for i := 0; i < len(list); i++ {
var saleType string
if list[i].RetailType == RetailTypeSale {
saleType = "零售销售"
} else if list[i].RetailType == RetailTypeRejected {
saleType = "零售退货"
} else {
logger.Error("订单类型异常")
return "", errors.New("RetailMarginDataExport, 订单类型异常:" + list[i].RetailType)
}
commodityIdMap := make(map[uint32]bool)
// 先判断商品数量,确定要写几行数据
for rowId := 0; rowId < len(list[i].Commodities); rowId++ {
if list[i].RetailType == RetailTypeSale {
nAmount = list[i].Commodities[rowId].Amount
} else if list[i].RetailType == RetailTypeRejected {
nAmount = list[i].Commodities[rowId].RejectedAmount
list[i].CashierList = "" // 目前零售退货订单暂时不展示各个方式的付款金额
}
isIMEIType := "是"
if list[i].Commodities[rowId].IMEIType == 1 {
isIMEIType = "否"
}
strPresentType := "非赠送"
if list[i].Commodities[rowId].PresentType == 2 {
strPresentType = "赠送"
}
// 组合销售员名称,提成数据
salesMan := ""
strSalesProfitPer := ""
strStaffProfitPer := ""
strSalesmanPer := ""
//var salesList []ErpOrderSales
//err := json.Unmarshal([]byte(list[i].SalesmanList), &salesList)
//if err != nil {
// logger.Error("unmarshal err:", logger.Field("err", err))
//}
for j, item := range list[i].Salesman {
salesMan += item.Name
// 将浮点数转换为字符串,保留两位小数
strNumber1 := strconv.FormatFloat(item.SalesProfitPer, 'f', 2, 64)
strSalesProfitPer += strNumber1
strNumber2 := strconv.FormatFloat(item.StaffProfitPer, 'f', 2, 64)
strStaffProfitPer += strNumber2
strNumber3 := strconv.FormatFloat(item.SalesmanPer, 'f', 2, 64)
strSalesmanPer += strNumber3
if j < len(list[i].Salesman)-1 {
salesMan += "\n"
strSalesProfitPer += "\n"
strStaffProfitPer += "\n"
strSalesmanPer += "\n"
}
}
// 组合支付相关信息
var cashierData TotalCashierData
var cashiers []ErpOrderCashier
err := json.Unmarshal([]byte(list[i].CashierList), &cashiers)
if err != nil {
logger.Error("unmarshal err:", logger.Field("err", err))
}
for _, item := range cashiers {
switch item.CashierId {
case 1:
cashierData.ScanAmount = item.Amount
case 2:
cashierData.CashAmount = item.Amount
case 3:
cashierData.PosAmount = item.Amount
case 4:
cashierData.StoreVmAmount = item.Amount
default:
cashierData.OtherAmount += item.Amount
}
}
// 单个订单的汇总数据只记录一次
var temp RetailDetailTotalData
if !commodityIdMap[list[i].Commodities[rowId].ErpCommodityId] {
commodityIdMap[list[i].Commodities[rowId].ErpCommodityId] = true
temp.TotalRetailPrice = list[i].TotalRetailPrice
temp.TotalDiscount = list[i].TotalDiscount
temp.TotalAmount = list[i].TotalAmount
temp.TotalSalesProfit = list[i].TotalSalesProfit
temp.TotalStaffProfit = list[i].TotalStaffProfit
temp.StorePer = list[i].StorePer
}
row = []interface{}{
list[i].BillSn,
saleType,
list[i].Uid,
list[i].Tel,
list[i].AuditTime,
list[i].StoreName,
salesMan, //销售员
list[i].Commodities[rowId].ErpCategoryName,
list[i].Commodities[rowId].ErpCommodityName,
list[i].Commodities[rowId].ErpSupplierName, //供应商
isIMEIType,
list[i].Commodities[rowId].IMEI,
strPresentType,
list[i].Commodities[rowId].Count,
list[i].Commodities[rowId].RetailPrice,
list[i].Commodities[rowId].SalePrice,
list[i].Commodities[rowId].SaleDiscount,
list[i].Commodities[rowId].MemberDiscount,
nAmount,
list[i].Commodities[rowId].WholesalePrice,
list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
list[i].Commodities[rowId].SalesProfit,
list[i].Commodities[rowId].StaffProfit,
temp.TotalRetailPrice,
temp.TotalDiscount,
temp.TotalAmount,
cashierData.ScanAmount, // 扫码付
cashierData.CashAmount, // 现金收款
cashierData.PosAmount, // pos机收款
cashierData.StoreVmAmount, // 商场积分抵扣
cashierData.OtherAmount, // 其他付款方式
temp.TotalSalesProfit,
temp.TotalStaffProfit,
strSalesProfitPer, // 销售毛利提成
strStaffProfitPer, // 员工毛利提成
strSalesmanPer, // 销售员提成
temp.StorePer,
list[i].Commodities[rowId].Remark,
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err = file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
//合并单元格
nRow := len(list[i].Commodities)
if nRow > 1 {
for j := 'A'; j <= 'G'; j++ {
colName := string(j)
str1 := fmt.Sprintf("%s%d", colName, nExcelStartRow-nRow+2)
str2 := fmt.Sprintf("%s%d", colName, nExcelStartRow+1)
_ = file.MergeCell(fSheet, str1, str2)
}
for j := 'X'; j <= 'Z'; j++ {
colName := string(j)
str1 := fmt.Sprintf("%s%d", colName, nExcelStartRow-nRow+2)
str2 := fmt.Sprintf("%s%d", colName, nExcelStartRow+1)
_ = file.MergeCell(fSheet, str1, str2)
}
for j := 'A'; j <= 'L'; j++ {
colName := string(j)
str1 := fmt.Sprintf("A%s%d", colName, nExcelStartRow-nRow+2)
str2 := fmt.Sprintf("A%s%d", colName, nExcelStartRow+1)
_ = file.MergeCell(fSheet, str1, str2)
}
}
}
totalData := "订单数:" + strconv.FormatInt(int64(sumData.Count), 10)
end := []interface{}{totalData, "", "", "", "", "", "", "", "", "", "", "", "",
sumData.Count,
sumData.RetailPrice,
sumData.SalePrice,
sumData.SaleDiscount,
sumData.MemberDiscount,
sumData.Amount,
sumData.WholesalePrice,
sumData.StaffPrice,
sumData.SalesProfit,
sumData.StaffProfit,
sumData.TotalRetailPrice,
sumData.TotalDiscount,
sumData.TotalAmount,
sumData.ScanAmount, // 扫码付
sumData.CashAmount, // 现金收款
sumData.PosAmount, // pos机收款
sumData.StoreVmAmount, // 商场积分抵扣
sumData.OtherAmount, // 其他付款方式
sumData.TotalSalesProfit,
sumData.TotalStaffProfit,
sumData.TotalSalesProfitPer, // 销售毛利提成
sumData.TotalStaffProfitPer, // 员工毛利提成
sumData.SalesmanPer, // 销售员提成
sumData.StorePer,
""}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
// 设置单元格的样式: 居中、加边框、自动换行
style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
endRow := fmt.Sprintf("AL%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
//需要自动换行的列
endRow1 := fmt.Sprintf("G%d", nExcelStartRow+2)
endRow2 := fmt.Sprintf("AH%d", nExcelStartRow+2)
endRow3 := fmt.Sprintf("AI%d", nExcelStartRow+2)
endRow4 := fmt.Sprintf("AJ%d", nExcelStartRow+2)
_ = file.SetCellStyle("Sheet1", "A1", "AL1", style1)
_ = file.SetCellStyle("Sheet1", "G2", endRow1, style1)
_ = file.SetCellStyle("Sheet1", "AH2", endRow2, style1)
_ = file.SetCellStyle("Sheet1", "AI2", endRow3, style1)
_ = file.SetCellStyle("Sheet1", "AJ2", endRow4, style1)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// 导出零售明细报表excel-不合并
func retailDetailExport(list []ErpOrder, sumData RetailDetailTotalData) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "零售明细" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"订单编号", "订单类型", "用户ID", "客户手机号", "审核时间", "店铺", "销售员", "商品分类", "商品名称",
"供应商", "是否串码", "商品串码", "是否赠送", "销售数量", "指导零售价", "零售价", "零售优惠", "会员优惠", "实际零售价/退货价",
"采购单价", "员工成本价", "销售毛利", "员工毛利", "订单总指导零售价", "订单总优惠", "订单实收", "【扫码付", "现金收款", "pos机收款",
"商场积分抵扣", "其他付款方式】", "订单总销售毛利", "订单总员工毛利", "销售毛利提成", "员工毛利提成", "销售员提成", "门店提成", "备注"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row []interface{}
nAmount := 0.0
nExcelStartRow := 0
for i := 0; i < len(list); i++ {
var saleType string
if list[i].RetailType == RetailTypeSale {
saleType = "零售销售"
} else if list[i].RetailType == RetailTypeRejected {
saleType = "零售退货"
} else {
logger.Error("订单类型异常")
return "", errors.New("RetailMarginDataExport, 订单类型异常:" + list[i].RetailType)
}
commodityIdMap := make(map[uint32]bool)
// 先判断商品数量,确定要写几行数据
for rowId := 0; rowId < len(list[i].Commodities); rowId++ {
if list[i].RetailType == RetailTypeSale {
nAmount = list[i].Commodities[rowId].Amount
} else if list[i].RetailType == RetailTypeRejected {
nAmount = list[i].Commodities[rowId].RejectedAmount
list[i].CashierList = "" // 目前零售退货订单暂时不展示各个方式的付款金额
}
isIMEIType := "是"
if list[i].Commodities[rowId].IMEIType == 1 {
isIMEIType = "否"
}
strPresentType := "非赠送"
if list[i].Commodities[rowId].PresentType == 2 {
strPresentType = "赠送"
}
// 组合支付相关信息
var cashierData TotalCashierData
var cashiers []ErpOrderCashier
err := json.Unmarshal([]byte(list[i].CashierList), &cashiers)
if err != nil {
logger.Error("unmarshal err:", logger.Field("err", err))
}
for _, item := range cashiers {
switch item.CashierId {
case 1:
cashierData.ScanAmount = item.Amount
case 2:
cashierData.CashAmount = item.Amount
case 3:
cashierData.PosAmount = item.Amount
case 4:
cashierData.StoreVmAmount = item.Amount
default:
cashierData.OtherAmount += item.Amount
}
}
// 单个订单的汇总数据只记录一次
if !commodityIdMap[list[i].Commodities[rowId].ErpCommodityId] {
commodityIdMap[list[i].Commodities[rowId].ErpCommodityId] = true
salesMan := ""
nSalesProfitPer := 0.0
nStaffProfitPer := 0.0
nSalesmanPer := 0.0
if len(list[i].Salesman) > 0 {
salesMan = list[i].Salesman[0].Name
nSalesProfitPer = math.Round(list[i].Salesman[0].SalesProfitPer*100) / 100
nStaffProfitPer = math.Round(list[i].Salesman[0].StaffProfitPer*100) / 100
nSalesmanPer = math.Round(list[i].Salesman[0].SalesmanPer*100) / 100
}
row = []interface{}{
list[i].BillSn,
saleType,
list[i].Uid,
list[i].Tel,
list[i].AuditTime,
list[i].StoreName,
salesMan, //销售员
list[i].Commodities[rowId].ErpCategoryName,
list[i].Commodities[rowId].ErpCommodityName,
list[i].Commodities[rowId].ErpSupplierName, //供应商
isIMEIType,
list[i].Commodities[rowId].IMEI,
strPresentType,
list[i].Commodities[rowId].Count,
list[i].Commodities[rowId].RetailPrice,
list[i].Commodities[rowId].SalePrice,
list[i].Commodities[rowId].SaleDiscount,
list[i].Commodities[rowId].MemberDiscount,
nAmount,
list[i].Commodities[rowId].WholesalePrice,
list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
list[i].Commodities[rowId].SalesProfit,
list[i].Commodities[rowId].StaffProfit,
list[i].TotalRetailPrice,
list[i].TotalDiscount,
list[i].TotalAmount,
cashierData.ScanAmount, // 扫码付
cashierData.CashAmount, // 现金收款
cashierData.PosAmount, // pos机收款
cashierData.StoreVmAmount, // 商场积分抵扣
cashierData.OtherAmount, // 其他付款方式
list[i].TotalSalesProfit,
list[i].TotalStaffProfit,
nSalesProfitPer, // 销售毛利提成
nStaffProfitPer, // 员工毛利提成
nSalesmanPer, // 销售员提成
list[i].StorePer,
list[i].Commodities[rowId].Remark,
}
} else {
if len(list[i].Salesman) == 2 && rowId == 1 {
row = []interface{}{
"",
"",
"",
"",
"",
"",
list[i].Salesman[1].Name, //销售员
list[i].Commodities[rowId].ErpCategoryName,
list[i].Commodities[rowId].ErpCommodityName,
list[i].Commodities[rowId].ErpSupplierName, //供应商
isIMEIType,
list[i].Commodities[rowId].IMEI,
strPresentType,
list[i].Commodities[rowId].Count,
list[i].Commodities[rowId].RetailPrice,
list[i].Commodities[rowId].SalePrice,
list[i].Commodities[rowId].SaleDiscount,
list[i].Commodities[rowId].MemberDiscount,
nAmount,
list[i].Commodities[rowId].WholesalePrice,
list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
list[i].Commodities[rowId].SalesProfit,
list[i].Commodities[rowId].StaffProfit,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
math.Round(list[i].Salesman[1].SalesProfitPer*100) / 100, // 销售毛利提成
math.Round(list[i].Salesman[1].StaffProfitPer*100) / 100, // 员工毛利提成
math.Round(list[i].Salesman[1].SalesmanPer*100) / 100, // 销售员提成
"",
"",
}
} else {
row = []interface{}{
"",
"",
"",
"",
"",
"",
"", //销售员
list[i].Commodities[rowId].ErpCategoryName,
list[i].Commodities[rowId].ErpCommodityName,
list[i].Commodities[rowId].ErpSupplierName, //供应商
isIMEIType,
list[i].Commodities[rowId].IMEI,
strPresentType,
list[i].Commodities[rowId].Count,
list[i].Commodities[rowId].RetailPrice,
list[i].Commodities[rowId].SalePrice,
list[i].Commodities[rowId].SaleDiscount,
list[i].Commodities[rowId].MemberDiscount,
nAmount,
list[i].Commodities[rowId].WholesalePrice,
list[i].Commodities[rowId].WholesalePrice + list[i].Commodities[rowId].StaffCostPrice,
list[i].Commodities[rowId].SalesProfit,
list[i].Commodities[rowId].StaffProfit,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"", // 销售毛利提成
"", // 员工毛利提成
"", // 销售员提成
"",
"",
}
}
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err = file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
if len(list[i].Commodities) == 1 && len(list[i].Salesman) == 2 {
row = []interface{}{
"",
"",
"",
"",
"",
"",
list[i].Salesman[1].Name, //销售员
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
math.Round(list[i].Salesman[1].SalesProfitPer*100) / 100, // 销售毛利提成
math.Round(list[i].Salesman[1].StaffProfitPer*100) / 100, // 员工毛利提成
math.Round(list[i].Salesman[1].SalesmanPer*100) / 100, // 销售员提成
"",
"",
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err = file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
}
}
totalData := "订单数:" + strconv.FormatInt(int64(len(list)), 10)
end := []interface{}{totalData, "", "", "", "", "", "", "", "", "", "", "", "",
sumData.Count,
sumData.RetailPrice,
sumData.SalePrice,
sumData.SaleDiscount,
sumData.MemberDiscount,
sumData.Amount,
sumData.WholesalePrice,
sumData.StaffPrice,
sumData.SalesProfit,
sumData.StaffProfit,
sumData.TotalRetailPrice,
sumData.TotalDiscount,
sumData.TotalAmount,
sumData.ScanAmount, // 扫码付
sumData.CashAmount, // 现金收款
sumData.PosAmount, // pos机收款
sumData.StoreVmAmount, // 商场积分抵扣
sumData.OtherAmount, // 其他付款方式
sumData.TotalSalesProfit,
sumData.TotalStaffProfit,
sumData.TotalSalesProfitPer, // 销售毛利提成
sumData.TotalStaffProfitPer, // 员工毛利提成
sumData.SalesmanPer, // 销售员提成
sumData.StorePer,
""}
for i, _ := range end {
cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, end[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}}`)
// 设置单元格的样式: 居中、加边框、自动换行
style1, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center","wrap_text":true}}`)
endRow := fmt.Sprintf("AL%d", nExcelStartRow+2)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
//需要自动换行的列
endRow1 := fmt.Sprintf("G%d", nExcelStartRow+2)
endRow2 := fmt.Sprintf("AH%d", nExcelStartRow+2)
endRow3 := fmt.Sprintf("AI%d", nExcelStartRow+2)
endRow4 := fmt.Sprintf("AJ%d", nExcelStartRow+2)
_ = file.SetCellStyle("Sheet1", "A1", "AL1", style1)
_ = file.SetCellStyle("Sheet1", "G2", endRow1, style1)
_ = file.SetCellStyle("Sheet1", "AH2", endRow2, style1)
_ = file.SetCellStyle("Sheet1", "AI2", endRow3, style1)
_ = file.SetCellStyle("Sheet1", "AJ2", endRow4, style1)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// RetailDetailByJoin 联表查询扫描参数
type RetailDetailByJoin struct {
ErpOrderCommodity
ErpOrder
}
// 联表查询
func queryRetailDetailByJoin(req *ErpOrderRetailDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
showConfig, err := GetErpOrderShowConfig()
if err != nil {
logger.Errorf("List err:", err)
showConfig.ShowAll = "ON"
}
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpOrderRetailDetailResp{
PageIndex: page + 1,
PageSize: req.PageSize,
}
qs := orm.Eloquent.Debug().Table("erp_order_commodity").
Select("erp_order_commodity.*, erp_order.*").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")
es := orm.Eloquent.Debug().Table("erp_order_commodity").
Select("erp_order_commodity.*, erp_order.*").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")
orderSumQs := orm.Eloquent.Table("erp_order_commodity AS oc").Select("oc.*, eo.*").
Joins("JOIN erp_order AS eo ON oc.erp_order_id = eo.id")
rejectedOrderSumQs := orm.Eloquent.Table("erp_order_commodity AS oc").Select("oc.*, eo.*").
Joins("JOIN erp_order AS eo ON oc.erp_order_id = eo.id")
if req.ErpCategoryId != 0 { // 商品分类
qs = qs.Where("erp_order_commodity.erp_category_id=?", req.ErpCategoryId)
es = es.Where("erp_order_commodity.erp_category_id=?", req.ErpCategoryId)
orderSumQs = orderSumQs.Where("oc.erp_category_id=?", req.ErpCategoryId)
rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.erp_category_id=?", req.ErpCategoryId)
}
if req.ErpCommodityName != "" { // 商品名称
qs = qs.Where("erp_order_commodity.erp_commodity_name = ?", req.ErpCommodityName)
es = es.Where("erp_order_commodity.erp_commodity_name = ?", req.ErpCommodityName)
orderSumQs = orderSumQs.Where("oc.erp_commodity_name = ?", req.ErpCommodityName)
rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.erp_commodity_name = ?", req.ErpCommodityName)
}
if req.RetailType != "" { // 销售类型
qs = qs.Where("erp_order.retail_type=?", req.RetailType)
es = es.Where("erp_order.retail_type=?", req.RetailType)
orderSumQs = orderSumQs.Where("eo.retail_type=?", req.RetailType)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.retail_type=?", req.RetailType)
}
if req.Uid != 0 { // 用户ID
qs = qs.Where("erp_order.uid=?", req.Uid)
es = es.Where("erp_order.uid=?", req.Uid)
orderSumQs = orderSumQs.Where("eo.uid=?", req.Uid)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.uid=?", req.Uid)
}
if req.Tel != "" { // 用户手机号
qs = qs.Where("erp_order.tel=?", req.Tel)
es = es.Where("erp_order.tel=?", req.Tel)
orderSumQs = orderSumQs.Where("eo.tel=?", req.Tel)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.tel=?", req.Tel)
}
if req.StoreId != 0 { // 门店ID
qs = qs.Where("erp_order.store_id=?", req.StoreId)
es = es.Where("erp_order.store_id=?", req.StoreId)
orderSumQs = orderSumQs.Where("eo.store_id=?", req.StoreId)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id=?", req.StoreId)
}
if req.IMEI != "" { // 串码
qs = qs.Where("erp_order_commodity.imei=?", req.IMEI)
es = es.Where("erp_order_commodity.imei=?", req.IMEI)
orderSumQs = orderSumQs.Where("oc.imei=?", req.IMEI)
rejectedOrderSumQs = rejectedOrderSumQs.Where("oc.imei=?", req.IMEI)
}
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
if len(storeList) == 1 {
qs = qs.Where("erp_order.store_id = ?", storeList[0])
es = es.Where("erp_order.store_id = ?", storeList[0])
orderSumQs = orderSumQs.Where("eo.store_id = ?", storeList[0])
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id = ?", storeList[0])
} else {
qs = qs.Where("erp_order.store_id IN (?)", storeList)
es = es.Where("erp_order.store_id IN (?)", storeList)
orderSumQs = orderSumQs.Where("eo.store_id IN (?)", storeList)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.store_id IN (?)", storeList)
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
if req.Salesman != 0 { // 销售员
qs = qs.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
es = es.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
orderSumQs = orderSumQs.Where("JSON_CONTAINS(eo.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
rejectedOrderSumQs = rejectedOrderSumQs.Where("JSON_CONTAINS(eo.salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
}
if req.StartTime != "" { // 审核开始时间
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("erp_order.audit_time > ?", parse)
es = es.Where("erp_order.audit_time > ?", parse)
orderSumQs = orderSumQs.Where("eo.audit_time > ?", parse)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.audit_time > ?", parse)
}
if req.EndTime != "" { // 审核结束时间
parse, err := time.Parse(QueryTimeFormat, req.EndTime)
if err != nil {
logger.Errorf("err:", err)
}
//parse = parse.AddDate(0, 0, 1)
qs = qs.Where("erp_order.audit_time < ?", parse)
es = es.Where("erp_order.audit_time < ?", parse)
orderSumQs = orderSumQs.Where("eo.audit_time < ?", parse)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.audit_time < ?", parse)
}
if showConfig.ShowAll == "OFF" {
qs = qs.Where("erp_order.is_print = ? or erp_order.retail_type = ?", HavePrinted, RetailTypeRejected)
es = es.Where("erp_order.is_print = ? or erp_order.retail_type = ?", HavePrinted, RetailTypeRejected)
orderSumQs = orderSumQs.Where("eo.is_print = ? or eo.retail_type = ?", HavePrinted, RetailTypeRejected)
rejectedOrderSumQs = rejectedOrderSumQs.Where("eo.is_print = ? or eo.retail_type = ?", HavePrinted, RetailTypeRejected)
}
qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
es.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
orderSumQs.Where("eo.pay_status = ? or (eo.retail_type = ? and eo.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
rejectedOrderSumQs.Where("eo.pay_status = ? or (eo.retail_type = ? and eo.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
// 销售订单的汇总数据
var sumData RetailDetailTotalData
sumData, err = getRetailDetailTotalDataJoinErpOrderSale(orderSumQs, RetailTypeSale)
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return resp, err
}
// 退货订单的汇总数据
var rejectedSumData RetailDetailTotalData
rejectedSumData, err = getRetailDetailTotalDataJoinErpOrderRejected(rejectedOrderSumQs, RetailTypeRejected)
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return resp, err
}
// 计算销售订单和退货订单汇总后的销售数据
sumData = subtractRetailData(sumData, rejectedSumData)
// 销售订单提成汇总
var totalPerData TotalPerData
totalPerQs := qs
totalPerData, err = getTotalPerData(totalPerQs, RetailTypeSale)
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return resp, err
}
// 退货订单提成汇总
var rejectedTotalPerData TotalPerData
rejectedTotalPerQs := qs
rejectedTotalPerData, err = getTotalPerData(rejectedTotalPerQs, RetailTypeRejected)
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return resp, err
}
// 计算销售订单和退货订单汇总后的提成数据
totalPerData = subtractTotalPerData(totalPerData, rejectedTotalPerData)
// 销售订单支持汇总
var cashier TotalCashierData
cashierQs := qs
cashier, err = getTotalCashierData(cashierQs, RetailTypeSale)
if err != nil {
logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
return resp, err
}
// 退货订单支付汇总:目前零售退货订单暂时不展示各个方式的付款金额
var rejectedCashier TotalCashierData
//rejectedCashierQs := qs
//rejectedCashier, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected)
//if err != nil {
// logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
// return resp, err
//}
// 计算销售订单和退货订单汇总后的支付数据
cashier = subtractCashierData(cashier, rejectedCashier)
// 处理汇总数据四舍五入保留2位小数
roundValues(&sumData, &totalPerData, &cashier)
sumData.TotalSalesProfit = 0 // 订单总销售毛利
sumData.TotalStaffProfit = 0 // 订单总员工毛利
sumData.TotalRetailPrice = 0 // 订单总指导零售价
sumData.TotalDiscount = 0 // 订单总优惠
sumData.TotalAmount = 0 // 订单实收金额
sumData.StorePer = 0 // 门店提成
sumData.ScanAmount = cashier.ScanAmount
sumData.CashAmount = cashier.CashAmount
sumData.PosAmount = cashier.PosAmount
sumData.StoreVmAmount = cashier.StoreVmAmount
sumData.OtherAmount = cashier.OtherAmount
var result []RetailDetailByJoin
if req.IsExport == 1 { //导出excel
err = qs.Order("erp_order.audit_time DESC").Find(&result).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Errorf("QueryRetailMargin count err:", err.Error())
return nil, err
}
orders := packData(result)
fileUrl, err := retailDetailExport(orders, sumData)
if err != nil {
logger.Error("retailDetailExport err:", logger.Field("err", err))
return resp, err
}
resp.ExportUrl = fileUrl
} else {
//err = qs.Order("erp_order.audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&result).Error
err = qs.Order("erp_order.audit_time DESC").Find(&result).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Errorf("QueryRetailMargin count err:", err.Error())
return nil, err
}
orders := packData(result)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
pagedOrders := paginate(orders, page, req.PageSize)
resp.List = pagedOrders
//跟之前保持一致
resp.Total = len(orders)
resp.PageIndex = page + 1
resp.PageSize = req.PageSize
resp.SumData = sumData
}
return resp, nil
}
// 分页函数
func paginate(orders []ErpOrder, page int, pageSize int) []ErpOrder {
start := page * pageSize
end := start + pageSize
if start >= len(orders) {
return []ErpOrder{}
}
if end > len(orders) {
end = len(orders)
}
return orders[start:end]
}
// 组合数据
func packData(result []RetailDetailByJoin) []ErpOrder {
var orders []ErpOrder
orderIdMap := make(map[uint32]ErpOrder)
for _, item := range result {
var order ErpOrder
var commodity ErpOrderCommodity
// 判断是否有重复数据
if len(orderIdMap) != 0 && orderIdMap[item.ErpOrderId].BillSn != "" {
order = orderIdMap[item.ErpOrderId]
} else {
// 订单数据
order.CreatedAt = item.ErpOrderCommodity.CreatedAt
order.ID = item.ErpOrderId
order.BillSn = item.BillSn
order.RetailType = item.RetailType
order.Uid = item.Uid
order.Tel = item.Tel
order.StoreId = item.StoreId
order.StoreName = item.StoreName
order.MakerId = item.MakerId
order.MakerName = item.MakerName
order.MakerTime = item.MakerTime
order.AuditorId = item.AuditorId
order.AuditorName = item.AuditorName
order.AuditTime = item.AuditTime
order.CashierList = item.CashierList
order.SalesmanList = item.SalesmanList
order.MemberType = item.MemberType
order.State = item.State
order.TotalRetailPrice = item.TotalRetailPrice
order.TotalAmount = item.TotalAmount
order.TotalCount = item.TotalCount
order.TotalSalesProfit = item.TotalSalesProfit
order.TotalStaffProfit = item.TotalStaffProfit
order.VmCount = item.VmCount
order.SaleOrderId = item.SaleOrderId
order.PayStatus = item.PayStatus
order.IsPrint = item.IsPrint
order.PrintCount = item.PrintCount
order.InvoiceCode = item.InvoiceCode
order.InvoiceNumber = item.InvoiceNumber
order.RejectedTotalAmount = item.RejectedTotalAmount
order.RejectedTotalCount = item.RejectedTotalCount
if order.RetailType == RetailTypeRejected { // 退货订单,金额需要转换为负值
order.TotalRetailPrice = -math.Abs(order.TotalRetailPrice)
order.TotalAmount = -math.Abs(order.TotalAmount)
order.TotalCount = -int32(math.Abs(float64(order.TotalCount)))
order.TotalSalesProfit = -order.TotalSalesProfit
order.TotalStaffProfit = -order.TotalStaffProfit
order.TotalDiscount = -math.Abs(order.TotalDiscount)
order.VmCount = -uint32(math.Abs(float64(order.VmCount)))
order.StorePer = -math.Abs(order.StorePer)
}
}
if order.RetailType == RetailTypeRejected { // 退货订单,金额需要转换为负值
item.Count = -item.Count
item.RetailPrice = -item.RetailPrice
item.SalePrice = -item.SalePrice
item.Amount = -item.Amount
item.SaleDiscount = -item.SaleDiscount
item.MemberDiscount = -item.MemberDiscount
item.VmDiscount = -item.VmDiscount
item.ReceivedAmount = -item.ReceivedAmount
item.RejectedAmount = -item.RejectedAmount
item.SalesProfit = -item.SalesProfit
item.StaffProfit = -item.StaffProfit
item.StaffCostPrice = -item.StaffCostPrice
item.WholesalePrice = -item.WholesalePrice
}
// 订单商品数据
commodity.CreatedAt = item.ErpOrderCommodity.CreatedAt
commodity.ErpOrderId = item.ErpOrderId
commodity.ErpCategoryId = item.ErpCategoryId
commodity.ErpCategoryName = item.ErpCategoryName
commodity.ErpCommodityId = item.ErpCommodityId
commodity.ErpCommodityName = item.ErpCommodityName
commodity.IMEIType = item.IMEIType
commodity.IMEI = item.IMEI
commodity.PresentType = item.PresentType
commodity.RetailPrice = item.RetailPrice
commodity.SalePrice = item.SalePrice
commodity.Count = item.Count
commodity.SaleDiscount = item.SaleDiscount
commodity.MemberDiscount = item.MemberDiscount
commodity.VmDiscount = item.VmDiscount
commodity.Amount = item.Amount
commodity.ReceivedAmount = item.ReceivedAmount
commodity.Remark = item.Remark
commodity.RejectedPrice = item.RejectedPrice
commodity.RejectedCount = item.RejectedCount
commodity.RejectedAmount = item.RejectedAmount
commodity.RejectedOrderCommodityId = item.RejectedOrderCommodityId
commodity.StaffCostPrice = item.StaffCostPrice
commodity.WholesalePrice = item.WholesalePrice
commodity.ErpSupplierId = item.ErpSupplierId
commodity.ErpSupplierName = item.ErpSupplierName
commodity.SalesProfit = item.SalesProfit
commodity.StaffProfit = item.StaffProfit
order.Commodities = append(order.Commodities, commodity)
orderIdMap[item.ErpOrderId] = order
}
for _, item := range orderIdMap {
orders = append(orders, item)
}
return orders
}
// 普通单表查询,然后补充收款数据和商品数据
func queryRetailDetailCommon(req *ErpOrderRetailDetailReq, c *gin.Context) (*ErpOrderRetailDetailResp, error) {
showConfig, err := GetErpOrderShowConfig()
if err != nil {
logger.Errorf("List err:", err)
showConfig.ShowAll = "ON"
}
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
resp := &ErpOrderRetailDetailResp{
PageIndex: page + 1,
PageSize: req.PageSize,
}
qs := orm.Eloquent.Table("erp_order")
totalPerQs := orm.Eloquent.Table("erp_order")
if showConfig.ShowAll == "OFF" {
qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
totalPerQs = totalPerQs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected)
}
if req.BillSn != "" { // 订单编号
qs = qs.Where("bill_sn=?", req.BillSn)
totalPerQs = totalPerQs.Where("bill_sn=?", req.BillSn)
} else {
if req.RetailType != "" { // 销售类型
qs = qs.Where("retail_type=?", req.RetailType)
totalPerQs = totalPerQs.Where("retail_type=?", req.RetailType)
}
if req.Uid != 0 { // 用户ID
qs = qs.Where("erp_order.uid=?", req.Uid)
totalPerQs = totalPerQs.Where("erp_order.uid=?", req.Uid)
}
if req.Tel != "" { // 用户手机号
qs = qs.Where("tel=?", req.Tel)
totalPerQs = totalPerQs.Where("tel=?", req.Tel)
}
if req.StoreId != 0 { // 门店ID
qs = qs.Where("store_id=?", req.StoreId)
totalPerQs = totalPerQs.Where("store_id=?", req.StoreId)
}
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 返回sysUser未过期的门店id列表
storeList := GetValidStoreIDs(sysUser.StoreData)
if len(storeList) > 0 {
if len(storeList) == 1 {
qs = qs.Where("store_id = ?", storeList[0])
totalPerQs = totalPerQs.Where("store_id = ?", storeList[0])
} else {
qs = qs.Where("store_id IN (?)", storeList)
totalPerQs = totalPerQs.Where("store_id IN (?)", storeList)
}
} else {
return nil, errors.New("用户未绑定门店")
}
}
if req.Salesman != 0 { // 销售员
qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, req.Salesman))
totalPerQs = totalPerQs.Where("erp_order_sales.uid = ?", req.Salesman)
}
if req.StartTime != "" { // 审核开始时间
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("audit_time > ?", parse)
totalPerQs = totalPerQs.Where("audit_time > ?", parse)
}
if req.EndTime != "" { // 审核结束时间
parse, err := time.Parse(QueryTimeFormat, req.EndTime)
if err != nil {
logger.Errorf("err:", err)
}
//parse = parse.AddDate(0, 0, 1)
qs = qs.Where("audit_time < ?", parse)
totalPerQs = totalPerQs.Where("audit_time < ?", parse)
}
}
qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
totalPerQs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)",
HavePaid, RetailTypeRejected, ErpOrderStateUnAudit)
es := qs
rejectedTotalPerQs := totalPerQs
// 销售订单的汇总数据
orderSumQs := qs
var sumData RetailDetailTotalData
sumData, err = getRetailDetailTotalDataSale(orderSumQs, RetailTypeSale)
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return resp, err
}
// 退货订单的汇总数据
var rejectedSumData RetailDetailTotalData
rejectedOrderSumQs := qs
rejectedSumData, err = getRetailDetailTotalDataRejected(rejectedOrderSumQs, RetailTypeRejected)
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return resp, err
}
// 计算销售订单和退货订单汇总后的销售数据
sumData = subtractRetailData(sumData, rejectedSumData)
// 销售订单提成汇总
var totalPerData TotalPerData
totalPerData, err = getTotalPerData(totalPerQs, RetailTypeSale)
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return resp, err
}
// 退货订单提成汇总
var rejectedTotalPerData TotalPerData
rejectedTotalPerData, err = getTotalPerData(rejectedTotalPerQs, RetailTypeRejected)
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return resp, err
}
// 计算销售订单和退货订单汇总后的提成数据
totalPerData = subtractTotalPerData(totalPerData, rejectedTotalPerData)
// 销售订单支付汇总
var cashier TotalCashierData
cashierQs := qs
cashier, err = getTotalCashierData(cashierQs, RetailTypeSale)
if err != nil {
logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
return resp, err
}
// 退货订单支付汇总:目前零售退货订单暂时不展示各个方式的付款金额
var rejectedCashier TotalCashierData
//rejectedCashierQs := qs
//rejectedCashier, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected)
//if err != nil {
// logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
// return resp, err
//}
// 计算销售订单和退货订单汇总后的支付数据
cashier = subtractCashierData(cashier, rejectedCashier)
// 处理汇总数据四舍五入保留2位小数
roundValues(&sumData, &totalPerData, &cashier)
sumData.TotalSalesProfitPer = totalPerData.TotalSalesProfitPer
sumData.TotalStaffProfitPer = totalPerData.TotalStaffProfitPer
sumData.SalesmanPer = totalPerData.SalesmanPer
sumData.ScanAmount = cashier.ScanAmount
sumData.CashAmount = cashier.CashAmount
sumData.PosAmount = cashier.PosAmount
sumData.StoreVmAmount = cashier.StoreVmAmount
sumData.OtherAmount = cashier.OtherAmount
if req.IsExport == 1 { // 导出excel
var orders []ErpOrder
err = qs.Order("id DESC").Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
ErpOrderRetailDetailSetCommodity(orders)
erpOrderListSetSalesman(orders)
fileUrl, err := retailDetailExport(orders, sumData)
if err != nil {
logger.Error("retailDetailExport err:", logger.Field("err", err))
return resp, err
}
resp.ExportUrl = fileUrl
} else {
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
var orders []ErpOrder
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
// 添加付款、销售员、商品信息
ErpOrderRetailDetailSetCommodity(orders)
erpOrderListSetSalesman(orders)
erpOrderListSetCashier(orders)
//erpOrderListSetSalesmanByRetailDetail(req.Salesman, orders)
resp.List = orders
//跟之前保持一致
resp.Total = int(count)
resp.PageIndex = page + 1
resp.PageSize = req.PageSize
resp.SumData = sumData
}
return resp, nil
}
// 四舍五入保留2位小数
func roundValues(data *RetailDetailTotalData, totalPerData *TotalPerData, cashier *TotalCashierData) {
roundMap := map[*float64]*float64{
&data.StorePer: &data.StorePer,
&totalPerData.TotalSalesProfitPer: &totalPerData.TotalSalesProfitPer,
&totalPerData.TotalStaffProfitPer: &totalPerData.TotalStaffProfitPer,
&totalPerData.SalesmanPer: &totalPerData.SalesmanPer,
&cashier.ScanAmount: &cashier.ScanAmount,
&cashier.CashAmount: &cashier.CashAmount,
&cashier.PosAmount: &cashier.PosAmount,
&cashier.StoreVmAmount: &cashier.StoreVmAmount,
&cashier.OtherAmount: &cashier.OtherAmount,
}
for original, rounded := range roundMap {
*rounded = tools.RoundToTwoDecimalPlaces(*original)
}
}
// 查询零售订单的汇总数据
func getRetailDetailTotalDataSale(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
var sumData RetailDetailTotalData
err := qs.Debug().
Select("SUM(cs.count) as count, "+
"SUM(cs.retail_price) as retail_price, "+
"SUM(cs.sale_price) as sale_price, "+
"SUM(cs.sale_discount) as sale_discount, "+
"SUM(cs.member_discount) as member_discount, "+
"SUM(cs.amount) as Amount, "+
"SUM(cs.wholesale_price) as wholesale_price, "+
"(SUM(cs.wholesale_price) + SUM(cs.staff_cost_price)) as staff_price, "+
"(SUM(cs.amount) - SUM(cs.wholesale_price)) as sales_profit, "+
"(SUM(cs.amount) - SUM(cs.wholesale_price) - SUM(cs.staff_cost_price)) as staff_profit, "+
"SUM(erp_order.total_retail_price) as total_retail_price, "+
"(SUM(erp_order.total_retail_price) - SUM(erp_order.total_amount)) as total_discount, "+
"SUM(erp_order.total_amount) as total_amount, "+
"SUM(erp_order.total_sales_profit) as total_sales_profit, "+
"SUM(erp_order.total_staff_profit) as total_staff_profit, "+
"SUM(erp_order.store_per) as store_per").
Joins("JOIN (SELECT erp_order_id, "+
"SUM(count) as count, "+
"SUM(retail_price) as retail_price, "+
"SUM(sale_price) as sale_price, "+
"SUM(sale_discount) as sale_discount, "+
"SUM(member_discount) as member_discount, "+
"SUM(amount) as amount, "+
"SUM(wholesale_price) as wholesale_price, "+
"SUM(staff_cost_price) as staff_cost_price "+
"FROM erp_order_commodity "+
"GROUP BY erp_order_id) as cs ON cs.erp_order_id = erp_order.id").
Where("erp_order.retail_type = ?", retailType).
Scan(&sumData).Error
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return sumData, err
}
return sumData, nil
}
// 查询零售退货订单的汇总数据
func getRetailDetailTotalDataRejected(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
var sumData RetailDetailTotalData
err := qs.Debug().
Select("SUM(cs.count) as count, "+
"SUM(cs.retail_price) as retail_price, "+
"SUM(cs.sale_price) as sale_price, "+
"SUM(cs.sale_discount) as sale_discount, "+
"SUM(cs.member_discount) as member_discount, "+
"SUM(cs.amount) as Amount, "+
"SUM(cs.wholesale_price) as wholesale_price, "+
"(SUM(cs.wholesale_price) + SUM(cs.staff_cost_price)) as staff_price, "+
"(SUM(cs.amount) - SUM(cs.wholesale_price)) as sales_profit, "+
"(SUM(cs.amount) - SUM(cs.wholesale_price) - SUM(cs.staff_cost_price)) as staff_profit, "+
"SUM(erp_order.total_retail_price) as total_retail_price, "+
"(SUM(erp_order.total_retail_price) - SUM(erp_order.total_amount)) as total_discount, "+
"SUM(erp_order.total_amount) as total_amount, "+
"SUM(erp_order.total_sales_profit) as total_sales_profit, "+
"SUM(erp_order.total_staff_profit) as total_staff_profit, "+
"SUM(erp_order.store_per) as store_per").
Joins("JOIN (SELECT erp_order_id, "+
"SUM(count) as count, "+
"SUM(retail_price) as retail_price, "+
"SUM(sale_price) as sale_price, "+
"SUM(sale_discount) as sale_discount, "+
"SUM(member_discount) as member_discount, "+
"SUM(rejected_amount) as amount, "+
"SUM(wholesale_price) as wholesale_price, "+
"SUM(staff_cost_price) as staff_cost_price "+
"FROM erp_order_commodity "+
"GROUP BY erp_order_id) as cs ON cs.erp_order_id = erp_order.id").
Where("erp_order.retail_type = ?", retailType).
Scan(&sumData).Error
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return sumData, err
}
return sumData, nil
}
// 查询零售订单的汇总数据
func getRetailDetailTotalDataJoinErpOrderSale(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
var sumData RetailDetailTotalData
qs = qs.Where("eo.retail_type = ?", retailType) // 添加额外的条件
err := qs.Debug().Select("SUM(oc.count) as count, " +
"SUM(oc.retail_price) as retail_price, " +
"SUM(oc.sale_price) as sale_price, " +
"SUM(oc.sale_discount) as sale_discount, " +
"SUM(oc.member_discount) as member_discount, " +
"SUM(oc.amount) as Amount, " +
"SUM(oc.wholesale_price) as wholesale_price, " +
"(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) as staff_price, " +
"(SUM(oc.Amount) - SUM(oc.wholesale_price)) as sales_profit, " +
"(SUM(oc.Amount) - SUM(oc.wholesale_price) - SUM(oc.staff_cost_price)) as staff_profit").
Scan(&sumData).Error
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return sumData, err
}
return sumData, nil
}
// 查询零售订单的汇总数据
func getRetailDetailTotalDataJoinErpOrderRejected(qs *gorm.DB, retailType string) (RetailDetailTotalData, error) {
var sumData RetailDetailTotalData
qs = qs.Where("eo.retail_type = ?", retailType) // 添加额外的条件
err := qs.Debug().Select("SUM(oc.count) as count, " +
"SUM(oc.retail_price) as retail_price, " +
"SUM(oc.sale_price) as sale_price, " +
"SUM(oc.sale_discount) as sale_discount, " +
"SUM(oc.member_discount) as member_discount, " +
"SUM(oc.rejected_amount) as Amount, " +
"SUM(oc.wholesale_price) as wholesale_price, " +
"(SUM(oc.wholesale_price) + SUM(oc.staff_cost_price)) as staff_price, " +
"SUM(oc.sales_profit) as sales_profit, " +
"SUM(oc.staff_profit) as staff_profit").
Scan(&sumData).Error
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return sumData, err
}
return sumData, nil
}
// 查询零售订单的提成汇总数据
func getTotalPerData(qs *gorm.DB, retailType string) (TotalPerData, error) {
var totalPerData TotalPerData
err := qs.Debug().Select("SUM(erp_order_sales.sales_profit_per) as total_sales_profit_per, "+
"SUM(erp_order_sales.staff_profit_per) as total_staff_profit_per, "+
"SUM(erp_order_sales.salesman_per) as salesman_per").
Joins("JOIN erp_order_sales ON erp_order_sales.erp_order_id = erp_order.id and erp_order.retail_type = ?", retailType).
Scan(&totalPerData).Error
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return totalPerData, err
}
return totalPerData, nil
}
// 查询零售订单的支付汇总数据
func getTotalCashierData(qs *gorm.DB, retailType string) (TotalCashierData, error) {
var cashier TotalCashierData
err := qs.Debug().Select(
"SUM(CASE WHEN erp_order_pay_way.cashier_id = 1 THEN erp_order_pay_way.amount ELSE 0 END) AS scan_amount,"+
"SUM(CASE WHEN erp_order_pay_way.cashier_id = 2 THEN erp_order_pay_way.amount ELSE 0 END) AS cash_amount,"+
"SUM(CASE WHEN erp_order_pay_way.cashier_id = 3 THEN erp_order_pay_way.amount ELSE 0 END) AS pos_amount,"+
"SUM(CASE WHEN erp_order_pay_way.cashier_id = 4 THEN erp_order_pay_way.amount ELSE 0 END) AS store_vm_amount,"+
"SUM(CASE WHEN erp_order_pay_way.cashier_id not in (1,2,3,4) THEN erp_order_pay_way.amount ELSE 0 END) AS other_amount").
Joins("JOIN erp_order_pay_way ON erp_order_pay_way.erp_order_id = erp_order.id and erp_order.retail_type = ?", retailType).
Scan(&cashier).Error
if err != nil {
logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
return cashier, err
}
return cashier, nil
}
// 计算销售订单和退货订单汇总后的销售数据
func subtractRetailData(sumData, rejectedSumData RetailDetailTotalData) RetailDetailTotalData {
result := RetailDetailTotalData{
Count: sumData.Count - rejectedSumData.Count,
RetailPrice: sumData.RetailPrice - rejectedSumData.RetailPrice,
SalePrice: sumData.SalePrice - rejectedSumData.SalePrice,
SaleDiscount: sumData.SaleDiscount - rejectedSumData.SaleDiscount,
MemberDiscount: sumData.MemberDiscount - rejectedSumData.MemberDiscount,
VmDiscount: sumData.VmDiscount - rejectedSumData.VmDiscount,
Amount: sumData.Amount - rejectedSumData.Amount,
WholesalePrice: sumData.WholesalePrice - rejectedSumData.WholesalePrice,
StaffPrice: sumData.StaffPrice - rejectedSumData.StaffPrice,
SalesProfit: sumData.SalesProfit - rejectedSumData.SalesProfit,
StaffProfit: sumData.StaffProfit - rejectedSumData.StaffProfit,
TotalRetailPrice: sumData.TotalRetailPrice - rejectedSumData.TotalRetailPrice,
TotalDiscount: sumData.TotalDiscount - rejectedSumData.TotalDiscount,
TotalAmount: sumData.TotalAmount - rejectedSumData.TotalAmount,
TotalSalesProfit: sumData.TotalSalesProfit - rejectedSumData.TotalSalesProfit,
TotalStaffProfit: sumData.TotalStaffProfit - rejectedSumData.TotalStaffProfit,
StorePer: sumData.StorePer - rejectedSumData.StorePer,
}
//if sumData.TotalSalesProfit != 0 {
// result.TotalSalesProfit = sumData.TotalSalesProfit - rejectedSumData.TotalSalesProfit
//} else {
// result.TotalSalesProfit = rejectedSumData.TotalSalesProfit
//}
//if sumData.TotalStaffProfit != 0 {
// result.TotalStaffProfit = sumData.TotalStaffProfit - rejectedSumData.TotalStaffProfit
//} else {
// result.TotalStaffProfit = rejectedSumData.TotalStaffProfit
//}
return result
}
// 计算销售订单和退货订单汇总后的提成数据
func subtractTotalPerData(totalPerData, rejectedTotalPerData TotalPerData) TotalPerData {
result := TotalPerData{
TotalSalesProfitPer: totalPerData.TotalSalesProfitPer - rejectedTotalPerData.TotalSalesProfitPer,
TotalStaffProfitPer: totalPerData.TotalStaffProfitPer - rejectedTotalPerData.TotalStaffProfitPer,
SalesmanPer: totalPerData.SalesmanPer - rejectedTotalPerData.SalesmanPer,
}
return result
}
// 计算销售订单和退货订单汇总后的支付数据
func subtractCashierData(cashier, rejectedCashier TotalCashierData) TotalCashierData {
result := TotalCashierData{
ScanAmount: cashier.ScanAmount - rejectedCashier.ScanAmount,
CashAmount: cashier.CashAmount - rejectedCashier.CashAmount,
PosAmount: cashier.PosAmount - rejectedCashier.PosAmount,
StoreVmAmount: cashier.StoreVmAmount - rejectedCashier.StoreVmAmount,
OtherAmount: cashier.OtherAmount - rejectedCashier.OtherAmount,
}
return result
}
// QueryReceiptData 查询小票数据
func QueryReceiptData(req *ErpOrderDeleteReq, c *gin.Context) (*ErpOrderReceiptDataResp, error) {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
logger.Errorf("err:%#v", err)
return nil, err
}
var orders []ErpOrder
err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orders).Error
if err != nil {
logger.Error("erp_order find err:", logger.Field("err", err))
return nil, err
}
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
// 校验入参门店是否包含在用户所有门店中,是否过期
if !CheckUserStore(orders[0].StoreId, sysUser) {
return nil, errors.New("操作失败:您没有该门店权限")
}
}
if orders[0].PayStatus != HavePaid {
logger.Error("订单未支付")
return nil, errors.New("该订单未支付,不支持打印小票")
}
// 添加付款、销售员、商品信息
erpOrderListSetCommodity(orders)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
// 查询门店信息
storeInfo, err := GetStore(orders[0].StoreId)
if err != nil {
logger.Error("QueryReceiptData GetStore err:", logger.Field("err", err))
return nil, err
}
// 记录打印信息
if orders[0].IsPrint != HavePrinted {
err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Updates(map[string]interface{}{
"is_print": HavePrinted,
}).Error
if err != nil {
return nil, err
}
}
err = orm.Eloquent.Model(&ErpOrder{}).
Where("bill_sn = ? ", req.BillSn).
UpdateColumn("print_count", gorm.Expr("print_count + ?", 1)).Error
if err != nil {
return nil, err
}
order := orders[0]
resp := new(ErpOrderReceiptDataResp)
resp.StoreName = order.StoreName
resp.Barcode = order.BillSn
resp.OddNum = order.BillSn
resp.Time = Now()
resp.CollectS = order.MakerName
commodityMap := make(map[string]TableData, 0)
for i, item := range order.Commodities {
var tableData TableData
tableData.Name = item.ErpCommodityName
tableData.SL = uint32(item.Count)
tableData.DJ = item.RetailPrice
tableData.JE = float64(item.Count) * item.RetailPrice
key := fmt.Sprintf("commodity_%d", i)
commodityMap[key] = tableData
resp.TotalAmount += item.SaleDiscount
resp.IntegrationAmount += item.VmDiscount
if order.MemberType != ErpOrderMemberTypeGeneral {
resp.MembersAmount += item.MemberDiscount
}
}
resp.ChandiseObj = commodityMap
resp.TotalRetailP = order.TotalRetailPrice
resp.TotalNum = uint32(order.TotalCount)
resp.ToDealWith = order.TotalAmount
cashierMap := make(map[string]ErpOrderCashier, 0)
for i, item := range order.Cashiers {
key := fmt.Sprintf("payment_%d", i)
cashierMap[key] = item
}
resp.ModeOfPayment = cashierMap
resp.ActualPayment = order.TotalAmount
resp.Tel = order.Tel
if order.MemberType != ErpOrderMemberTypeGeneral {
resp.Uid = order.Uid
}
resp.StoreTel = storeInfo.Tel
resp.StoreAddress = storeInfo.Address
return resp, nil
}
// CreateErpOrder 创建零售订单
func CreateErpOrder(req *ErpOrderCreateReq, c *gin.Context) error {
for i, _ := range req.ErpOrderCommodities {
req.ErpOrderCommodities[i].ID = 0
}
// 校验订单数据
erpOrder, err := checkOrderData(req, c)
if err != nil {
return err
}
begin := orm.Eloquent.Begin()
// 0-创建用户信息
userInfo, err := GetUserInfoByTel(req.Tel)
if err != nil {
logger.Error("checkOrderData GetUserInfoByTel err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
if userInfo.Uid == 0 {
user := UserInfo{
Uid: uint32(erpOrder.Uid),
Tel: req.Tel,
StoreId: uint64(req.StoreId),
UserType: UserTypeConsumer, // 用户
OpenMemberLevel: MemberLevelConsumer, // 普通用户
MemberLevel: MemberLevelConsumer, // 普通用户
CooperativeBusinessId: 1, // 合作商默认为1
}
err = begin.Create(&user).Error
if err != nil {
begin.Rollback()
logger.Error("create user err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
}
// 1-创建零售订单
err = begin.Create(erpOrder).Error
if err != nil {
begin.Rollback()
logger.Error("create erp_order err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 销售信息添加零售订单id
for i, _ := range req.Salesman {
req.Salesman[i].ErpOrderId = erpOrder.ID
}
// 2-创建销售员信息记录
err = begin.Create(&req.Salesman).Error
if err != nil {
begin.Rollback()
logger.Error("Create erp_order_sales err")
return errors.New("操作失败:" + err.Error())
}
// 支付方式添加零售订单id
var orderPayWay ErpOrderPayWay
var orderPayWayList []ErpOrderPayWay
for _, item := range req.Cashiers {
orderPayWay.ErpOrderId = erpOrder.ID
orderPayWay.CashierId = item.CashierId
orderPayWay.Name = item.Name
orderPayWay.Amount = item.Amount
orderPayWayList = append(orderPayWayList, orderPayWay)
}
// 3-创建支付方式记录
err = begin.Create(&orderPayWayList).Error
if err != nil {
begin.Rollback()
logger.Error("Create erp_order_pay_way err")
return errors.New("操作失败:" + err.Error())
}
// 订单商品表信息添加零售订单id
for i, _ := range req.ErpOrderCommodities {
req.ErpOrderCommodities[i].ErpOrderId = erpOrder.ID
}
// 4-创建商品订单信息
err = begin.Create(&req.ErpOrderCommodities).Error
if err != nil {
begin.Rollback()
logger.Error("Create erp_order_commodity err")
return errors.New("操作失败:" + err.Error())
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
return nil
}
// EditErpOrder 编辑订单
func EditErpOrder(req *ErpOrderCreateReq, c *gin.Context) error {
var orderInfo ErpOrder
err := orm.Eloquent.Table("erp_order").Where("bill_sn=?", req.BillSn).Find(&orderInfo).Error
if err != nil {
logger.Error("query erp_order err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
if orderInfo.State != ErpOrderStateUnAudit {
logger.Error("EditErpOrder err:", logger.Field("err", err))
return errors.New("订单状态不是待审核,操作失败")
}
// 校验订单数据
erpOrder, err := checkOrderData(req, c)
if err != nil {
return err
}
erpOrder.ID = orderInfo.ID
erpOrder.BillSn = orderInfo.BillSn // 编辑的订单单据号不能改变
begin := orm.Eloquent.Begin()
// 1-更新零售订单
err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).Updates(erpOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 2-更新零售订单商品信息
err = updateCommodityData(begin, orderInfo.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_order_commodity err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 3-更新销售员信息记录
err = updateSalesData(begin, orderInfo.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_order_sales err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 4-更新支付方式记录
err = updatePayWayData(begin, orderInfo.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_order_pay_way err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
return nil
}
// CheckUserStore 校验用户门店是否包含在门店数据中且未过期
func CheckUserStore(userStoreId uint32, sysUser *SysUser) bool {
// 解析门店数据
var stores []StoreInfo
if err := json.Unmarshal([]byte(sysUser.StoreData), &stores); err != nil {
return false
}
// 查找用户门店并检查是否过期
for _, store := range stores {
if store.StoreID == int(userStoreId) {
expireTime, err := time.Parse(StoreDateTimeFormat, store.ExpireTime)
if err != nil {
return false
}
expireTime = expireTime.Add(24*time.Hour - time.Second)
// 如果过期时间在当前时间之后,则未过期
if expireTime.After(time.Now()) {
return true
}
return false
}
}
// 没有找到对应的门店
return false
}
// AuthUserStore 校验是否有某个门店的权限
func AuthUserStore(c *gin.Context, storeId uint32) error {
// 非管理员才判断所属门店
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return err
}
// 校验入参门店是否包含在用户所有门店中,是否过期
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
if !CheckUserStore(storeId, sysUser) {
return errors.New("操作失败:您没有该门店权限")
}
}
}
return nil
}
// checkOrderData 校验订单数据
func checkOrderData(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) {
sysUser, err := GetSysUserByCtx(c)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
// 校验入参门店是否包含在用户所有门店中,是否过期
if !(tools.GetRoleName(c) == "admin" || tools.GetRoleName(c) == "系统管理员") {
if !CheckUserStore(req.StoreId, sysUser) {
return nil, errors.New("操作失败:您没有该门店权限")
}
}
var rejectedOrderSaleId uint32
if req.RetailType == RetailTypeSale {
// 校验商品是否有库存,是否是对应门店库存商品
err = CheckOrderCommodityStock(req)
if err != nil {
return nil, err
}
} else { // 零售退货单,需校验退货商品是否是本门店售卖商品,同一个退货单中只能添加同一销售订单的商品
rejectedOrderSaleId, err = checkRejectedOrderRule(req)
if err != nil {
return nil, err
}
}
jCashier, err := json.Marshal(req.Cashiers)
if err != nil {
logger.Error("cashiers marshal err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
// 通过手机号查询用户id如果没有则新建一个用户id
userInfo, err := GetUserInfoByTel(req.Tel)
if err != nil {
logger.Error("checkOrderData GetUserInfoByTel err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
var userUid uint32
if userInfo.Uid == 0 {
userUid = CreateUid() // 没有用户则新建
} else {
userUid = userInfo.Uid
}
erpOrder := &ErpOrder{
BillSn: NewErpBillSn(),
RetailType: req.RetailType,
Uid: int(userUid),
Tel: req.Tel,
StoreId: req.StoreId,
StoreName: req.StoreName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
MakerTime: time.Now(),
CashierList: string(jCashier),
MemberType: req.MemberType,
State: ErpOrderStateUnAudit,
PayStatus: NoCreatePayOrder,
IsPrint: NoPrint, // 未打印
PrintCount: 0, // 打印次数
TotalRetailPrice: req.TotalRetailPrice,
VmCount: req.VmAmount,
}
if req.RetailType == RetailTypeRejected {
erpOrder.SaleOrderId = rejectedOrderSaleId
}
commodityMap := make(map[uint32]ErpStockCommodity)
imeiCommodityMap := make(map[string]ErpStockCommodity)
if req.RetailType == RetailTypeSale { // 零售订单,查商品表信息
commodityIds := make([]uint32, 0, len(req.ErpOrderCommodities)) // 非串码商品的商品id列表
imeiList := make([]string, 0, len(req.ErpOrderCommodities)) // 串码商品的串码列表
for i, _ := range req.ErpOrderCommodities {
if req.ErpOrderCommodities[i].IMEIType == 1 { // 非串码商品
commodityIds = append(commodityIds, req.ErpOrderCommodities[i].ErpCommodityId)
} else { // 串码商品
imeiList = append(imeiList, req.ErpOrderCommodities[i].IMEI)
}
}
// 商品的相关价格以库存表为准,商品表的价格除了最低零售价,其他只是参考
// 串码商品直接查询;非串码商品查询库存时间最久的商品
var commodities []ErpStockCommodity
if len(imeiList) != 0 {
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei IN (?)", imeiList).
Find(&commodities).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
for i, _ := range commodities { // 串码
imeiCommodityMap[commodities[i].IMEI] = commodities[i]
}
}
if len(commodityIds) != 0 {
commodities = nil
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id IN (?)", commodityIds).
Find(&commodities).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
for _, commodity := range commodities { // 非串码
v, ok := commodityMap[commodity.ErpCommodityId]
if !ok { // 没有则直接添加
commodityMap[commodity.ErpCommodityId] = commodity
} else {
// 已有则比较非串码的入库时间,添加入库时间最早的商品
if commodity.FirstStockTime.Before(v.FirstStockTime) {
commodityMap[commodity.ErpCommodityId] = commodity
}
}
}
}
// 更新用户信息表,添加首次零售订单时间
SetUserInfo(req.Tel)
}
//var orderCommodityMap map[uint32]ErpOrderCommodity
//if req.RetailType == RetailTypeRejected { // 零售退货订单,查零售商品表
// ids := make([]uint32, 0, len(req.ErpOrderCommodities))
// for i, _ := range req.ErpOrderCommodities {
// ids = append(ids, req.ErpOrderCommodities[i].ErpCommodityId)
// }
// orderCommodityMap, err = GetErpOrderCommodityMap(ids, req)
// if err != nil {
// logger.Error("order commodity map err:", logger.Field("err", err))
// return nil, err
// }
//}
bCheckFlag := false
// 校验商品相关金额是否符合要求
var respErpOrderCommodities []ErpOrderCommodity
for i, _ := range req.ErpOrderCommodities {
if req.RetailType == RetailTypeRejected { // 零售退货订单
//v, ok := orderCommodityMap[req.ErpOrderCommodities[i].ErpCommodityId]
//if ok {
// v.RejectedPrice = req.ErpOrderCommodities[i].RejectedPrice // 退货单价
// v.RejectedCount = req.ErpOrderCommodities[i].RejectedCount
// v.RejectedAmount = float64(v.RejectedCount) * v.RejectedPrice
//} else {
// logger.Error("rejected order commodity id is null")
// return nil, errors.New("rejected order commodity id is null")
//}
//v.ID = 0
//v.Remark = req.ErpOrderCommodities[i].Remark // 备注
//v.RejectedRemark = req.ErpOrderCommodities[i].RejectedRemark // 退货备注
//if v.PresentType == 1 { // 有非赠送商品
// bCheckFlag = true
//}
//req.ErpOrderCommodities[i] = v
if req.ErpOrderCommodities[i].RejectedPrice > req.ErpOrderCommodities[i].Amount { // 退货单价不能大于实际零售价
logger.Error("rejected price gt retail price ")
return nil, errors.New("退货单价大于实际零售价")
}
if int32(req.ErpOrderCommodities[i].RejectedCount) > req.ErpOrderCommodities[i].Count { // 退货数量不能大于销售数量
logger.Error("rejected count gt retail count ")
return nil, errors.New("退货数量大于销售数量")
}
// 更新订单表总退款金额和数量 备注2024-03-12 订单表没有退款金额的字段,默认都使用订单金额字段,根据订单类型判断是零售或退款
//erpOrder.RejectedTotalAmount += req.ErpOrderCommodities[i].RejectedAmount
//erpOrder.RejectedTotalCount += req.ErpOrderCommodities[i].RejectedCount
erpOrder.TotalAmount += req.ErpOrderCommodities[i].RejectedAmount
erpOrder.TotalCount += int32(req.ErpOrderCommodities[i].Count)
// 订单总优惠
erpOrder.TotalDiscount += req.ErpOrderCommodities[i].MemberDiscount + req.ErpOrderCommodities[i].SaleDiscount
// 销售毛利:实际退货金额-采购金额(需要先取负值,然后再计算),结果等同于:采购金额-实际退货金额
//salesProfit := (-v.RejectedAmount) - (-float64(int32(v.WholesalePrice) * v.Count))
salesProfit := req.ErpOrderCommodities[i].RejectedAmount - req.ErpOrderCommodities[i].WholesalePrice*float64(req.ErpOrderCommodities[i].Count)
// 员工毛利 // todo 待测试核实
//StaffProfit := salesProfit - (-float64(int32(v.StaffCostPrice) * v.Count))
StaffProfit := salesProfit - req.ErpOrderCommodities[i].StaffCostPrice*float64(req.ErpOrderCommodities[i].Count)
req.ErpOrderCommodities[i].SalesProfit = salesProfit // 销售毛利
req.ErpOrderCommodities[i].StaffProfit = StaffProfit // 员工毛利
erpOrder.TotalSalesProfit += salesProfit
erpOrder.TotalStaffProfit += StaffProfit
// 单个商品的销售毛利
req.ErpOrderCommodities[i].SalesProfit = salesProfit / float64(req.ErpOrderCommodities[i].Count)
// 单个商品的员工毛利
req.ErpOrderCommodities[i].StaffProfit = StaffProfit / float64(req.ErpOrderCommodities[i].Count)
// 单个商品的零售优惠
req.ErpOrderCommodities[i].SaleDiscount = req.ErpOrderCommodities[i].SaleDiscount / float64(req.ErpOrderCommodities[i].Count)
// 单个商品的会员优惠
req.ErpOrderCommodities[i].MemberDiscount = req.ErpOrderCommodities[i].MemberDiscount / float64(req.ErpOrderCommodities[i].Count)
// 单个商品实收金额
req.ErpOrderCommodities[i].ReceivedAmount = req.ErpOrderCommodities[i].ReceivedAmount / float64(req.ErpOrderCommodities[i].Count)
// 单个商品退货金额
req.ErpOrderCommodities[i].RejectedAmount = req.ErpOrderCommodities[i].RejectedAmount / float64(req.ErpOrderCommodities[i].Count)
for j := 0; j < int(req.ErpOrderCommodities[i].Count); j++ {
stockIdList, _ := stringToIntArray(req.ErpOrderCommodities[i].ErpStockCommodityID)
temp := req.ErpOrderCommodities[i]
temp.Count = 1
if len(stockIdList) > j {
temp.ErpStockCommodityID = fmt.Sprintf("%d", stockIdList[j])
}
respErpOrderCommodities = append(respErpOrderCommodities, temp)
}
} else if req.RetailType == RetailTypeSale { // 零售订单
var v ErpStockCommodity
var ok bool
if req.ErpOrderCommodities[i].IMEIType == 1 { // 非串码商品
v, ok = commodityMap[req.ErpOrderCommodities[i].ErpCommodityId]
if !ok {
return nil, errors.New("遍历商品信息报错")
}
} else { // 串码商品
v, ok = imeiCommodityMap[req.ErpOrderCommodities[i].IMEI]
if !ok {
return nil, errors.New("遍历商品信息报错")
}
}
// 赠送类型商品进行校验最低零售价为0才能赠送
if req.ErpOrderCommodities[i].PresentType == 2 && v.MinRetailPrice != 0 {
logger.Error("PresentType is 2, MinRetailPrice no equal 0")
return nil, errors.New("赠送商品最低零售价不为0不符合赠送条件请检查")
}
if req.ErpOrderCommodities[i].SalePrice < v.MinRetailPrice { //零售价不能低于最低零售价
logger.Error("SalePrice less than MinRetailPrice")
return nil, errors.New("零售价不能低于最低零售价,请检查")
}
if req.ErpOrderCommodities[i].PresentType == 1 { // 有非赠送商品
bCheckFlag = true
}
req.ErpOrderCommodities[i].ErpCommodityId = v.ErpCommodityId // 商品id
req.ErpOrderCommodities[i].ErpCommodityName = v.ErpCommodityName // 商品名称
req.ErpOrderCommodities[i].ErpCategoryId = v.ErpCategoryId // 分类id
req.ErpOrderCommodities[i].ErpCategoryName = v.ErpCategoryName // 分类名称
req.ErpOrderCommodities[i].ErpSupplierId = v.ErpSupplierId // 供应商id
req.ErpOrderCommodities[i].ErpSupplierName = v.ErpSupplierName // 供应商名称
req.ErpOrderCommodities[i].RetailPrice = v.RetailPrice // 指导零售价
req.ErpOrderCommodities[i].StaffCostPrice = v.StaffCostPrice // 员工成本价加价
req.ErpOrderCommodities[i].WholesalePrice = v.WholesalePrice // 指导采购价
// 销售毛利 备注:产品说有亏本销售的情况,不用判断毛利是否<0
salesProfit := req.ErpOrderCommodities[i].ReceivedAmount -
req.ErpOrderCommodities[i].WholesalePrice*float64(req.ErpOrderCommodities[i].Count)
// 员工毛利
StaffProfit := salesProfit - req.ErpOrderCommodities[i].StaffCostPrice*float64(req.ErpOrderCommodities[i].Count)
// 单个商品的销售毛利
req.ErpOrderCommodities[i].SalesProfit = salesProfit / float64(req.ErpOrderCommodities[i].Count)
// 单个商品的员工毛利
req.ErpOrderCommodities[i].StaffProfit = StaffProfit / float64(req.ErpOrderCommodities[i].Count)
// 订单总销售毛利
erpOrder.TotalSalesProfit += salesProfit
// 订单总员工毛利
erpOrder.TotalStaffProfit += StaffProfit
// 更新订单表总金额和数量
erpOrder.TotalAmount += req.ErpOrderCommodities[i].ReceivedAmount
erpOrder.TotalCount += int32(req.ErpOrderCommodities[i].Count)
// 单个商品的零售优惠
req.ErpOrderCommodities[i].SaleDiscount = req.ErpOrderCommodities[i].SaleDiscount / float64(req.ErpOrderCommodities[i].Count)
// 单个商品的会员优惠
req.ErpOrderCommodities[i].MemberDiscount = req.ErpOrderCommodities[i].MemberDiscount / float64(req.ErpOrderCommodities[i].Count)
// 单个商品实收金额
req.ErpOrderCommodities[i].ReceivedAmount = req.ErpOrderCommodities[i].ReceivedAmount / float64(req.ErpOrderCommodities[i].Count)
for j := 0; j < int(req.ErpOrderCommodities[i].Count); j++ {
temp := req.ErpOrderCommodities[i]
temp.Count = 1
respErpOrderCommodities = append(respErpOrderCommodities, temp)
}
}
}
if erpOrder.TotalAmount == 0 && bCheckFlag {
return nil, errors.New("订单包含非赠送商品实收金额不能为0")
}
req.ErpOrderCommodities = respErpOrderCommodities
// 判断线上支付金额是否>0
if req.RetailType == RetailTypeSale {
onlinePayFlag := false
onlinePayAmount := erpOrder.TotalAmount
var nWaitPayAmount float64
for _, item := range req.Cashiers {
if item.CashierId == 1 { // 线上支付
onlinePayFlag = true
} else {
onlinePayAmount -= item.Amount
}
nWaitPayAmount += item.Amount
}
if onlinePayFlag && onlinePayAmount <= 0 { // 线上支付且金额小于0则报错
logger.Error("线上支付金额小于0")
return nil, errors.New("扫码付金额需>0")
}
if nWaitPayAmount > erpOrder.TotalAmount { // 收款金额大于订单金额
logger.Error("收款金额大于订单金额")
return nil, errors.New("收款金额大于订单金额")
}
if nWaitPayAmount < erpOrder.TotalAmount { // 收款金额小于订单金额
logger.Error("收款金额小于订单金额")
return nil, errors.New("收款金额小于订单金额")
}
}
// 添加销售员相关信息
jSalesman, err := req.GetSalesmanList()
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
erpOrder.SalesmanList = jSalesman
// 添加门店提成
store, err := GetStore(req.StoreId)
if err != nil {
return nil, errors.New("操作失败:" + err.Error())
}
erpOrder.StorePer = erpOrder.TotalStaffProfit * (store.SalesCommRate / 100)
erpOrder.StorePer = math.Round(erpOrder.StorePer*100) / 100
// 订单总优惠
if req.RetailType == RetailTypeSale {
erpOrder.TotalDiscount = erpOrder.TotalRetailPrice - erpOrder.TotalAmount
}
return erpOrder, nil
}
// CheckOrderCommodityStock 校验商品是否有库存
func CheckOrderCommodityStock(req *ErpOrderCreateReq) error {
if len(req.ErpOrderCommodities) != 0 {
// 统计串码和非串码商品信息
commodityMap := make(map[uint32]uint32) // 记录非串码商品id及其数量
imeiCommodityMap := make(map[uint32]string) // 记录串码商品id及其串码
commodityNameMap := make(map[uint32]string) // 记录商品名称
for _, commodity := range req.ErpOrderCommodities {
if commodity.IMEIType == 1 {
_, ok := commodityMap[commodity.ErpCommodityId]
if !ok { // 没有则直接添加
commodityMap[commodity.ErpCommodityId] = uint32(commodity.Count)
} else {
commodityMap[commodity.ErpCommodityId] += uint32(commodity.Count)
}
commodityNameMap[commodity.ErpCommodityId] = commodity.ErpCommodityName
} else {
imeiCommodityMap[commodity.ErpCommodityId] = commodity.IMEI
commodityNameMap[commodity.ErpCommodityId] = commodity.ErpCommodityName
}
}
// 查询库存表,确认是否有库存
if len(commodityMap) != 0 { // 查询非串码商品库存
var count int64
for commodityId, nCount := range commodityMap {
err := orm.Eloquent.Table("erp_stock_commodity").
Where("erp_commodity_id = ? and store_id = ? and state = ? and imei_type = ?",
commodityId, req.StoreId, InStock, NoIMEICommodity).
Count(&count).Error
if err != nil {
return err
}
if count < int64(nCount) {
// 获取商品名称
return errors.New("商品" + "[" + commodityNameMap[commodityId] + "]库存不足")
}
}
}
if len(imeiCommodityMap) != 0 { // 查询串码商品库存
for commodityId, imei := range imeiCommodityMap {
var imeiStockCommodity ErpStockCommodity
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", imei, InStock).
Find(&imeiStockCommodity).Error
if err != nil {
return err
}
if imeiStockCommodity.ID == 0 {
// 获取商品名称
return errors.New("商品" + "[" + commodityNameMap[commodityId] + "]库存不足")
}
if imeiStockCommodity.StoreId != req.StoreId {
return errors.New(commodityNameMap[commodityId] + "商品非所选门店库存,请检查")
}
}
}
} else {
return errors.New("该零售订单未添加商品")
}
return nil
}
// 退货校验
// 1校验退货商品销售时的手机号与当前填写的手机号是否相同不匹配报错所退商品的历史订单手机号与当前不符。
// 2校验商品是否是当前用户购买
// 3校验退货商品是否是本门店售卖商品
// 4同一个退货单中只能添加同一销售订单的商品
func checkRejectedOrderRule(req *ErpOrderCreateReq) (uint32, error) {
if req.RetailType != RetailTypeRejected {
return 0, errors.New("订单类型有误,非退货订单")
}
if len(req.ErpOrderCommodities) == 0 {
return 0, errors.New("未添加退货商品")
}
var salesId uint32
rejectOrderSalesMap := make(map[string]bool)
for _, item := range req.ErpOrderCommodities {
// 查询退货商品之前的销售情况
if item.IMEIType == NoIMEICommodity { //非串码商品
var commodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id ").
Where("erp_order_commodity.erp_commodity_id = ? and erp_order.store_id = ? "+
"and erp_order.retail_type = ? and erp_order.pay_status = ? and erp_order.tel = ?",
item.ErpCommodityId, req.StoreId, RetailTypeSale, HavePaid, req.Tel).
Find(&commodities).Order("audit_time DESC").Error
if err != nil {
logger.Error("query erp_order_commodity err:", logger.Field("err", err))
return 0, errors.New("操作失败:" + err.Error())
}
if len(commodities) == 0 {
return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售情况", item.ErpCommodityName))
}
var orderInfo ErpOrder
err = orm.Eloquent.Table("erp_order").Where("id = ?", commodities[0].ErpOrderId).
Find(&orderInfo).Error
if err != nil {
logger.Error("query erp_order err:", logger.Field("err", err))
return 0, errors.New("操作失败:" + err.Error())
}
if orderInfo.BillSn == "" {
return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售订单", item.ErpCommodityName))
}
rejectOrderSalesMap[orderInfo.BillSn] = true
if len(rejectOrderSalesMap) > 1 {
return 0, errors.New("只可添加相同零售订单的商品")
}
salesId = orderInfo.ID
} else { // 串码商品
if item.IMEI == "" {
return 0, errors.New("退货商品串码为空")
}
var commodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id ").
Where("erp_order_commodity.imei = ? and erp_order.retail_type = ? and erp_order.pay_status = ?",
item.IMEI, RetailTypeSale, HavePaid).
Order("erp_order_id DESC").Find(&commodities).Error
if err != nil {
logger.Error("query erp_order_commodity err:", logger.Field("err", err))
return 0, errors.New("操作失败:" + err.Error())
}
if len(commodities) == 0 {
return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售情况", item.ErpCommodityName))
}
var orderInfo ErpOrder
err = orm.Eloquent.Table("erp_order").Where("id = ?", commodities[0].ErpOrderId).
Find(&orderInfo).Error
if err != nil {
logger.Error("query erp_order err:", logger.Field("err", err))
return 0, errors.New("操作失败:" + err.Error())
}
if orderInfo.BillSn == "" {
return 0, errors.New(fmt.Sprintf("未查询到商品[%s]销售订单", item.ErpCommodityName))
}
if orderInfo.Tel != req.Tel {
return 0, errors.New(fmt.Sprintf("所退商品[%s]的历史订单手机号与当前不符", item.ErpCommodityName))
}
if orderInfo.StoreId != req.StoreId {
return 0, errors.New(fmt.Sprintf("[%s]非当前门店所售商品,需前往对应门店退货", item.ErpCommodityName))
}
rejectOrderSalesMap[orderInfo.BillSn] = true
if len(rejectOrderSalesMap) > 1 {
return 0, errors.New("只可添加相同零售订单的商品")
}
salesId = orderInfo.ID
}
}
return salesId, nil
}
// updateCommodityData 更新订单商品信息
func updateCommodityData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
// 查询现有的零售订单信息
var commodities []ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", orderId).Find(&commodities).Error
if err != nil {
logger.Error("query erp_order_commodity err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 1-删除所有的商品信息
if len(commodities) != 0 {
err = gdb.Delete(&commodities).Error
if err != nil {
logger.Error("更新商品订单信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
for i, _ := range req.ErpOrderCommodities {
req.ErpOrderCommodities[i].ID = 0
}
// 2-更新商品订单信息-新增
err = gdb.Create(&req.ErpOrderCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
return nil
}
// updateSalesData 更新订单销售员信息
func updateSalesData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
// 查询现有的零售订单销售员信息
var orderSales []ErpOrderSales
err := orm.Eloquent.Table("erp_order_sales").Where("erp_order_id = ?", orderId).Find(&orderSales).Error
if err != nil {
logger.Error("query erp_order_sales err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
var newOrderSales []ErpOrderSales
var deletedOrderSales []ErpOrderSales
var matchingOrderSales []ErpOrderSales
// 找到新增的商品
for _, reqSales := range req.Salesman {
var found bool
for _, dbSales := range orderSales {
if reqSales.Uid == dbSales.Uid {
found = true
break
}
}
if !found {
reqSales.ID = 0
reqSales.CreatedAt = Now()
newOrderSales = append(newOrderSales, reqSales)
}
}
// 找到删除的商品
for _, dbSales := range orderSales {
var found bool
for _, reqSales := range req.Salesman {
if reqSales.Uid == dbSales.Uid {
found = true
// 找到匹配的商品,加入匹配列表
matchingOrderSales = append(matchingOrderSales, dbSales)
break
}
}
if !found {
deletedOrderSales = append(deletedOrderSales, dbSales)
}
}
// 更新
for _, orderSaleInfo := range matchingOrderSales {
if err = gdb.Model(&ErpOrderSales{}).Where("id = ?", orderSaleInfo.ID).Updates(orderSaleInfo).Error; err != nil {
logger.Error("更新订单销售员信息-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 新增
if len(newOrderSales) != 0 {
err = gdb.Create(&newOrderSales).Error
if err != nil {
logger.Error("更新订单销售员信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
// 删除
if len(deletedOrderSales) != 0 {
err = gdb.Delete(&deletedOrderSales).Error
if err != nil {
logger.Error("更新订单销售员信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}
// updatePayWayData 更新零售订单支付方式记录表
func updatePayWayData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
// 查询现有的零售订单销售员信息
var orderPayWay []ErpOrderPayWay
err := orm.Eloquent.Table("erp_order_pay_way").Where("erp_order_id = ?", orderId).Find(&orderPayWay).Error
if err != nil {
logger.Error("query erp_order_sales err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
var newOrderPayWay []ErpOrderPayWay
var deletedOrderPayWay []ErpOrderPayWay
var matchingOrderPayWay []ErpOrderPayWay
// 找到新增的商品
for _, reqPayWay := range req.Cashiers {
var found bool
for _, dbPayWay := range orderPayWay {
if reqPayWay.CashierId == dbPayWay.CashierId {
found = true
break
}
}
if !found {
payWay := ErpOrderPayWay{
ErpOrderId: orderId,
CashierId: reqPayWay.CashierId,
Name: reqPayWay.Name,
Amount: reqPayWay.Amount,
}
newOrderPayWay = append(newOrderPayWay, payWay)
}
}
// 找到删除的商品
for _, dbPayWay := range orderPayWay {
var found bool
for _, reqPayWay := range req.Cashiers {
if reqPayWay.CashierId == dbPayWay.CashierId {
found = true
// 找到匹配的商品,加入匹配列表
matchingOrderPayWay = append(matchingOrderPayWay, dbPayWay)
break
}
}
if !found {
deletedOrderPayWay = append(deletedOrderPayWay, dbPayWay)
}
}
// 更新
for _, orderPayWayInfo := range matchingOrderPayWay {
if err = gdb.Model(&ErpOrderPayWay{}).Where("id = ?", orderPayWayInfo.ID).Updates(orderPayWayInfo).Error; err != nil {
logger.Error("更新零售订单支付方式-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 新增
if len(newOrderPayWay) != 0 {
err = gdb.Create(&newOrderPayWay).Error
if err != nil {
logger.Error("更新零售订单支付方式-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
// 删除
if len(deletedOrderPayWay) != 0 {
err = gdb.Delete(&deletedOrderPayWay).Error
if err != nil {
logger.Error("更新零售订单支付方式-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}