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"` // 订单总优惠:订单所有商品零售优惠+会员优惠+会员积分抵扣之和 BankTrxNo string `json:"bank_trx_no" gorm:"-"` // 银行流水号 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"` // 销售员用户ID(20240322:更换为系统用户表主键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"` // 银行订单号 BankTrxNo string `json:"bank_trx_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"` // 会员手机号 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"` TotalSalesAmount float64 `json:"total_sales_amount"` // 总销售额 TotalPromotionFee float64 `json:"total_promotion_fee"` // 总推广费 TotalSalesProfit float64 `json:"total_sales_profit"` // 总销售毛利 TotalStaffProfit float64 `json:"total_staff_profit"` // 总员工毛利 TotalCount int64 `json:"total_count"` // 总销售数量 } // 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"` // 销售毛利率:销售毛利/销售/退货金额 TotalEmployeeMargin float64 `json:"total_employee_margin"` // 总员工毛利:销售金额/实际退货金额-员工成本 TotalEmployeeGrossMargins string `json:"total_employee_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"` // 销售毛利率:销售毛利/销售/退货金额 EmployeeMargin float64 `json:"employee_margin"` // 员工毛利:零售销售时:销售金额-员工成本 零售退货时:实际退货金额-员工成本 EmployeeGrossMargins string `json:"employee_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"` // 结束时间 BankTrxNo string `json:"bank_trx_no"` // 银联流水号 CashierId uint32 `json:"cashier_id"` // 收付款方式id 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("maker_time 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) erpOrderSetBankTrxNo(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.BillSn != "" { qs = qs.Where("erp_order.bill_sn=?", req.BillSn) } 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, commodity ErpOrderCommodity, nIdList []uint32) error { fmt.Println("nIdList is:", nIdList) 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 = ?", commodity.ID). Updates(map[string]interface{}{ "erp_stock_commodity_id": strId, "retail_price": stockCommodity.RetailPrice, "wholesale_price": stockCommodity.WholesalePrice, "staff_cost_price": stockCommodity.StaffCostPrice, "sales_profit": commodity.SalePrice - stockCommodity.WholesalePrice, "staff_profit": commodity.SalePrice - stockCommodity.WholesalePrice - 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 } // FindRightErpStockCommodityId 找一个可用的库存商品表主键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, "updated_at": time.Now(), }).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), "updated_at": time.Now(), }).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), "updated_at": time.Now(), }).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, "updated_at": time.Now(), }).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), "updated_at": time.Now(), }).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, "updated_at": time.Now(), }).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), "updated_at": time.Now(), }).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 } logger.Info("rightId is:", logger.Field("rightId", rightId)) if rightId == 0 { logger.Error("rightId is 0") return errors.New("查询商品库存出错") } // 优先出库库存时间最长的数据 err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId). Updates(map[string]interface{}{ "state": state, "updated_at": time.Now(), }).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), "updated_at": time.Now(), }).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], stockCommodityIdList) if err != nil { return err } } } } } } else if erpOrder.RetailType == RetailTypeRejected { // 零售退货订单 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": InStock, "updated_at": Now(), }).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), "updated_at": time.Now(), }).Error // 库存数量+1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } } else { // 非串码商品 var stockCommodity []ErpStockCommodity var stockCommodityIdList []uint32 stockCommodityID, _ := tools.StringToInt(commodities[i].ErpStockCommodityID) if stockCommodityID > 0 { err = gdb.Table("erp_stock_commodity").Where("id = ?", commodities[i].ErpStockCommodityID). Updates(map[string]interface{}{ "state": InStock, "updated_at": Now(), }).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), "updated_at": time.Now(), }).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, "updated_at": Now(), }).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), "updated_at": time.Now(), }).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], 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, "支付宝") { if cashier.CashierId == OnlinePay { 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++ } } // 添加零售订单的银行流水号 func erpOrderSetBankTrxNo(list []ErpOrder) { for i, _ := range list { list[i].SetBankTrxNo() } } func (m *ErpOrder) SetBankTrxNo() { var orderPayWay ErpOrderRecord err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", m.BillSn, PayOk).Find(&orderPayWay).Error if err != nil { logger.Error("SetBankTrxNo query erp_order_record err:", logger.Field("err", err)) } m.BankTrxNo = orderPayWay.BankTrxNo } // 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.RejectedCount += commodity.RejectedCount existingCommodity.RejectedAmount += commodity.RejectedAmount stockCommodityID, _ := tools.StringToInt(commodity.ErpStockCommodityID) if stockCommodityID > 0 { 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 { // 对float64类型的字段进行四舍五入处理 commodity.SalesProfit = tools.RoundFloat(commodity.SalesProfit) commodity.StaffProfit = tools.RoundFloat(commodity.StaffProfit) commodity.SaleDiscount = tools.RoundFloat(commodity.SaleDiscount) commodity.MemberDiscount = tools.RoundFloat(commodity.MemberDiscount) commodity.ReceivedAmount = tools.RoundFloat(commodity.ReceivedAmount) commodity.RejectedPrice = tools.RoundFloat(commodity.RejectedPrice) commodity.RejectedAmount = tools.RoundFloat(commodity.RejectedAmount) commodity.StaffCostPrice = tools.RoundFloat(commodity.StaffCostPrice) commodity.WholesalePrice = tools.RoundFloat(commodity.WholesalePrice) mergedCommodities = append(mergedCommodities, *commodity) } // 对mergedCommodities按ErpCommodityId进行排序 sort.Slice(mergedCommodities, func(i, j int) bool { return mergedCommodities[i].ID < mergedCommodities[j].ID }) 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(orderInfo.StoreId, 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, "bank_trx_no": hmPayResp.BankTrxNo, "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 orderInfo ErpOrder err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", billSn).Find(&orderInfo).Error if err != nil { logger.Error("未查询到订单:", logger.Field("err", err)) resp.Status = PayFailed return resp, errors.New("未查询到待支付订单") } // 查询待支付订单 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, orderInfo.StoreId) 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, "bank_trx_no": hmQueryResp.BankTrxNo, "total_amount": hmQueryResp.TotalAmount, "pay_way": hmQueryResp.PayWayCode, "status": payStatus, "updated_at": time.Now(), } 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, "updated_at": time.Now(), }).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) // 查询汇总数据 var summary struct { TotalSalesAmount float64 TotalPromotionFee float64 TotalSalesProfit float64 TotalStaffProfit float64 TotalCount int64 } err = qs.Select("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_discount ELSE -total_discount END) AS total_promotion_fee, " + "SUM(CASE WHEN retail_type = 'sale' THEN total_sales_profit ELSE -total_sales_profit END) AS total_sales_profit, " + "SUM(CASE WHEN retail_type = 'sale' THEN total_staff_profit ELSE -total_staff_profit END) AS total_staff_profit, " + "SUM(CASE WHEN retail_type = 'sale' THEN total_count ELSE -total_count END) AS total_count"). Find(&summary).Error if err != nil { logger.Error("QueryStoreManageData summary err:", logger.Field("err", err)) return nil, err } // 查询分页数据 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) // 汇总数据赋值给响应 resp.TotalSalesAmount = math.Round(summary.TotalSalesAmount*100) / 100 resp.TotalPromotionFee = math.Round(summary.TotalPromotionFee*100) / 100 resp.TotalSalesProfit = math.Round(summary.TotalSalesProfit*100) / 100 resp.TotalStaffProfit = math.Round(summary.TotalStaffProfit*100) / 100 resp.TotalCount = summary.TotalCount 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, summary, c) 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 { data.TotalSalesAmount = math.Round(data.TotalSalesAmount*100) / 100 data.PromotionFee = math.Round(data.PromotionFee*100) / 100 data.SalesProfit = math.Round(data.SalesProfit*100) / 100 data.StaffProfit = math.Round(data.StaffProfit*100) / 100 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, summary struct { TotalSalesAmount float64 TotalPromotionFee float64 TotalSalesProfit float64 TotalStaffProfit float64 TotalCount int64 }, c *gin.Context) (string, error) { file := excelize.NewFile() fSheet := "Sheet1" url := ExportUrl fileName := time.Now().Format(TimeFormat) + storeName + "经营数据" + ".xlsx" fmt.Println("url fileName:", url+fileName) // 判断是否有入销售毛利、员工毛利的权限 flag1, _ := checkRoleMenu(c, SalesProfitMenu) flag2, _ := checkRoleMenu(c, StaffProfitMenu) fmt.Println("flag1 is:", flag1) fmt.Println("flag2 is:", flag2) logger.Info("flag1 is:", logger.Field("flag1", flag1)) logger.Info("flag2 is:", logger.Field("flag2", flag2)) nEndCount := 0 title := []interface{}{"时间", "销售额", "推广费"} if flag1 { // 销售毛利 title = append(title, "销售毛利") nEndCount += 1 } if flag2 { // 员工毛利 title = append(title, "员工毛利") nEndCount += 1 } title = append(title, "销售数量") 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, } // 控制是否导出 if flag1 { // 销售毛利 row = append(row, list[rowId].SalesProfit) } if flag2 { // 员工毛利 row = append(row, list[rowId].StaffProfit) } row = append(row, 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++ } totalData := "汇总 记录数:" + strconv.FormatInt(int64(len(list)), 10) end := []interface{}{totalData, summary.TotalSalesAmount, summary.TotalPromotionFee} if flag1 { // 销售毛利 end = append(end, summary.TotalSalesProfit) } if flag2 { // 员工毛利 end = append(end, summary.TotalStaffProfit) } end = append(end, summary.TotalCount) for i, _ := range end { cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2) err := file.SetCellValue(fSheet, cell, end[i]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } // 设置所有单元格的样式: 居中、加边框 style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}, "border":[{"type":"left","color":"000000","style":1}, {"type":"top","color":"000000","style":1}, {"type":"right","color":"000000","style":1}, {"type":"bottom","color":"000000","style":1}]}`) //设置单元格高度 file.SetRowHeight("Sheet1", 1, 20) // 设置单元格大小 file.SetColWidth("Sheet1", "A", "A", 18) var endRow string switch nEndCount { case 1: endRow = fmt.Sprintf("E"+"%d", nExcelStartRow+2) case 2: endRow = fmt.Sprintf("F"+"%d", nExcelStartRow+2) default: endRow = fmt.Sprintf("D"+"%d", nExcelStartRow+2) } // 应用样式到整个表格 _ = file.SetCellStyle("Sheet1", "A1", endRow, style) fmt.Println("save fileName:", config.ExportConfig.Path+fileName) if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // retailMarginDataExport 导出商品零售毛利汇总数据 func retailMarginDataExport(req *ErpOrderRetailMarginResp, c *gin.Context) (string, error) { file := excelize.NewFile() fSheet := "Sheet1" url := ExportUrl fileName := time.Now().Format(TimeFormat) + "商品零售毛利汇总" + ".xlsx" fmt.Println("url fileName:", url+fileName) nEndCount := 0 title := []interface{}{"店铺名称", "零售类型", "商品名称", "商品分类", "数量", "销售/退货金额"} // 判断是否有权限 flag1, _ := checkRoleMenu(c, SalesCostMenu) flag2, _ := checkRoleMenu(c, EmployeeCostMenu) flag3, _ := checkRoleMenu(c, SalesMarginMenu) flag4, _ := checkRoleMenu(c, EmployeeMarginMenu) flag5, _ := checkRoleMenu(c, GrossMarginsMenu) flag6, _ := checkRoleMenu(c, EmployeeGrossMarginsMenu) if flag1 { title = append(title, "销售成本") nEndCount += 1 } if flag2 { title = append(title, "员工成本") nEndCount += 1 } if flag3 { title = append(title, "销售毛利") nEndCount += 1 } if flag4 { title = append(title, "员工毛利") nEndCount += 1 } if flag5 { title = append(title, "销售毛利率") nEndCount += 1 } if flag6 { title = append(title, "员工毛利率") nEndCount += 1 } 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(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, } if flag1 { // 销售成本 row = append(row, req.List[rowId].SalesCost) } if flag2 { // 员工成本 row = append(row, req.List[rowId].EmployeeCost) } if flag3 { // 销售毛利 row = append(row, req.List[rowId].SalesMargin) } if flag4 { // 员工毛利 row = append(row, req.List[rowId].EmployeeMargin) } if flag5 { // 销售毛利率 row = append(row, req.List[rowId].GrossMargins) } if flag6 { // 员工毛利率 row = append(row, req.List[rowId].EmployeeGrossMargins) } for j, _ := range row { cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2) err := file.SetCellValue(fSheet, cell, row[j]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } nExcelStartRow++ } totalData := "汇总 记录数:" + strconv.FormatInt(int64(req.TotalCount), 10) end := []interface{}{totalData, "", "", "", req.TotalCount, fmt.Sprintf("%.2f", req.TotalSalesAmount)} if flag1 { // 销售成本 end = append(end, req.TotalSalesCost) } if flag2 { // 员工成本 end = append(end, req.TotalEmployeeCost) } if flag3 { // 销售毛利 end = append(end, req.TotalSalesMargin) } if flag4 { // 员工毛利 end = append(end, req.TotalEmployeeMargin) } if flag5 { // 销售毛利率 end = append(end, req.TotalGrossMargins) } if flag6 { // 员工毛利率 end = append(end, req.TotalEmployeeGrossMargins) } for i, _ := range end { cell, _ := excelize.CoordinatesToCellName(1+i, nExcelStartRow+2) err := file.SetCellValue(fSheet, cell, end[i]) if err != nil { logger.Error("file set value err:", logger.Field("err", err)) } } // 设置所有单元格的样式: 居中、加边框 style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"}, "border":[{"type":"left","color":"000000","style":1}, {"type":"top","color":"000000","style":1}, {"type":"right","color":"000000","style":1}, {"type":"bottom","color":"000000","style":1}]}`) //设置单元格高度 file.SetRowHeight("Sheet1", 1, 30) // 设置单元格大小 file.SetColWidth("Sheet1", "A", "A", 26) file.SetColWidth("Sheet1", "C", "C", 45) file.SetColWidth("Sheet1", "F", "F", 15) var endRow string switch nEndCount { case 1: endRow = fmt.Sprintf("G"+"%d", nExcelStartRow+2) case 2: endRow = fmt.Sprintf("H"+"%d", nExcelStartRow+2) case 3: endRow = fmt.Sprintf("I"+"%d", nExcelStartRow+2) case 4: endRow = fmt.Sprintf("J"+"%d", nExcelStartRow+2) case 5: endRow = fmt.Sprintf("K"+"%d", nExcelStartRow+2) case 6: endRow = fmt.Sprintf("L"+"%d", nExcelStartRow+2) default: endRow = fmt.Sprintf("F"+"%d", nExcelStartRow+2) } // 应用样式到整个表格 _ = file.SetCellStyle("Sheet1", "A1", endRow, style) fmt.Println("save fileName:", config.ExportConfig.Path+fileName) if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // 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 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{} // 通过银行流水号查询 if req.BankTrxNo != "" { var orderPayWay ErpOrderRecord err := orm.Eloquent.Table("erp_order_record").Where("bank_trx_no = ? and status = ?", req.BankTrxNo, PayOk).Find(&orderPayWay).Error if err != nil { logger.Error("query erp_order_record err:", logger.Field("err", err)) return nil, err } req.BillSn = orderPayWay.BillSn } 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, c *gin.Context) (string, error) { file := excelize.NewFile() fSheet := "Sheet1" url := ExportUrl fileName := time.Now().Format(TimeFormat) + "零售明细" + ".xlsx" fmt.Println("url fileName:", url+fileName) // 判断是否有权限 flag1, _ := checkRoleMenu(c, DetailWholesalePriceMenu) flag2, _ := checkRoleMenu(c, DetailEmployeeCostMenu) flag3, _ := checkRoleMenu(c, DetailSalesProfitMenu) flag4, _ := checkRoleMenu(c, DetailStaffProfitMenu) flag5, _ := checkRoleMenu(c, DetailTotalSalesProfitMenu) flag6, _ := checkRoleMenu(c, DetailTotalStaffProfitMenu) flag7, _ := checkRoleMenu(c, DetailSalesProfitPerMenu) flag8, _ := checkRoleMenu(c, DetailStaffProfitPerMenu) flag9, _ := checkRoleMenu(c, DetailSalesmanPerMenu) flag10, _ := checkRoleMenu(c, DetailStorePerMenu) nEndCount := 0 title := []interface{}{"订单编号", "订单类型", "用户ID", "客户手机号", "审核时间", "店铺", "银联流水号", "销售员", "商品分类", "商品名称", "供应商", "是否串码", "商品串码", "是否赠送", "销售数量", "指导零售价", "零售价", "零售优惠", "会员优惠", "实际零售价/退货价"} if flag1 { // 采购单价 title = append(title, "采购单价") nEndCount += 1 } if flag2 { // 员工成本价 title = append(title, "员工成本价") nEndCount += 1 } if flag3 { // 销售毛利 title = append(title, "销售毛利") nEndCount += 1 } if flag4 { // 员工毛利 title = append(title, "员工毛利") nEndCount += 1 } title = append(title, "订单总指导零售价", "订单总优惠", "订单实收", "【扫码付", "现金收款", "pos机收款", "商场积分抵扣", "其他付款方式】") if flag5 { // 订单总销售毛利 title = append(title, "订单总销售毛利") nEndCount += 1 } if flag6 { // 订单总员工毛利 title = append(title, "订单总员工毛利") nEndCount += 1 } if flag7 { // 销售毛利提成 title = append(title, "销售毛利提成") nEndCount += 1 } if flag8 { // 员工毛利提成 title = append(title, "员工毛利提成") nEndCount += 1 } if flag9 { // 销售员提成 title = append(title, "销售员提成") nEndCount += 1 } if flag10 { // 门店提成 title = append(title, "门店提成") nEndCount += 1 } title = append(title, "备注") 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) } orderFlag := false // 先判断商品数量,确定要写几行数据 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 !orderFlag { orderFlag = 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, list[i].BankTrxNo, 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, } // 控制是否导出 if flag1 { // 采购单价 row = append(row, list[i].Commodities[rowId].WholesalePrice) } if flag2 { // 员工成本价 row = append(row, list[i].Commodities[rowId].WholesalePrice+list[i].Commodities[rowId].StaffCostPrice) } if flag3 { // 销售毛利 row = append(row, list[i].Commodities[rowId].SalesProfit) } if flag4 { // 员工毛利 row = append(row, list[i].Commodities[rowId].StaffProfit) } row = append(row, list[i].TotalRetailPrice) row = append(row, list[i].TotalDiscount) row = append(row, list[i].TotalAmount) row = append(row, cashierData.ScanAmount) row = append(row, cashierData.CashAmount) row = append(row, cashierData.PosAmount) row = append(row, cashierData.StoreVmAmount) row = append(row, cashierData.OtherAmount) if flag5 { // 订单总销售毛利 row = append(row, list[i].TotalSalesProfit) } if flag6 { // 订单总员工毛利 row = append(row, list[i].TotalStaffProfit) } if flag7 { // 销售毛利提成 row = append(row, nSalesProfitPer) } if flag8 { // 员工毛利提成 row = append(row, nStaffProfitPer) } if flag9 { // 销售员提成 row = append(row, nSalesmanPer) } if flag10 { // 门店提成 row = append(row, list[i].StorePer) } row = append(row, 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, // 销售员提成 //"", //"", } // 控制是否导出 if flag1 { // 采购单价 row = append(row, list[i].Commodities[rowId].WholesalePrice) } if flag2 { // 员工成本价 row = append(row, list[i].Commodities[rowId].WholesalePrice+list[i].Commodities[rowId].StaffCostPrice) } if flag3 { // 销售毛利 row = append(row, list[i].Commodities[rowId].SalesProfit) } if flag4 { // 员工毛利 row = append(row, list[i].Commodities[rowId].StaffProfit) } row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") if flag5 { // 订单总销售毛利 row = append(row, "") } if flag6 { // 订单总员工毛利 row = append(row, "") } if flag7 { // 销售毛利提成 row = append(row, math.Round(list[i].Salesman[1].SalesProfitPer*100)/100) } if flag8 { // 员工毛利提成 row = append(row, math.Round(list[i].Salesman[1].StaffProfitPer*100)/100) } if flag9 { // 销售员提成 row = append(row, math.Round(list[i].Salesman[1].SalesmanPer*100)/100) } if flag10 { // 门店提成 row = append(row, "") } row = append(row, "") } 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, //"", //"", //"", //"", //"", //"", //"", //"", //"", //"", //"", // 销售毛利提成 //"", // 员工毛利提成 //"", // 销售员提成 //"", //"", } // 控制是否导出 if flag1 { // 采购单价 row = append(row, list[i].Commodities[rowId].WholesalePrice) } if flag2 { // 员工成本价 row = append(row, list[i].Commodities[rowId].WholesalePrice+list[i].Commodities[rowId].StaffCostPrice) } if flag3 { // 销售毛利 row = append(row, list[i].Commodities[rowId].SalesProfit) } if flag4 { // 员工毛利 row = append(row, list[i].Commodities[rowId].StaffProfit) } row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") if flag5 { // 订单总销售毛利 row = append(row, "") } if flag6 { // 订单总员工毛利 row = append(row, "") } if flag7 { // 销售毛利提成 row = append(row, "") } if flag8 { // 员工毛利提成 row = append(row, "") } if flag9 { // 销售员提成 row = append(row, "") } if flag10 { // 门店提成 row = append(row, "") } row = append(row, "") } } 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, // 销售员提成 //"", //"", } // 控制是否导出 if flag1 { // 采购单价 row = append(row, "") } if flag2 { // 员工成本价 row = append(row, "") } if flag3 { // 销售毛利 row = append(row, "") } if flag4 { // 员工毛利 row = append(row, "") } row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") row = append(row, "") if flag5 { // 订单总销售毛利 row = append(row, "") } if flag6 { // 订单总员工毛利 row = append(row, "") } if flag7 { // 销售毛利提成 row = append(row, math.Round(list[i].Salesman[1].SalesProfitPer*100)/100) } if flag8 { // 员工毛利提成 row = append(row, math.Round(list[i].Salesman[1].StaffProfitPer*100)/100) } if flag9 { // 销售员提成 row = append(row, math.Round(list[i].Salesman[1].SalesmanPer*100)/100) } if flag10 { // 门店提成 row = append(row, "") } row = append(row, "") 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, //"" } // 控制是否导出 if flag1 { // 采购单价 end = append(end, sumData.WholesalePrice) } if flag2 { // 员工成本价 end = append(end, sumData.StaffPrice) } if flag3 { // 销售毛利 end = append(end, sumData.SalesProfit) } if flag4 { // 员工毛利 end = append(end, sumData.StaffProfit) } end = append(end, sumData.TotalRetailPrice) end = append(end, sumData.TotalDiscount) end = append(end, sumData.TotalAmount) end = append(end, sumData.ScanAmount) end = append(end, sumData.CashAmount) end = append(end, sumData.PosAmount) end = append(end, sumData.StoreVmAmount) end = append(end, sumData.OtherAmount) if flag5 { // 订单总销售毛利 end = append(end, sumData.TotalSalesProfit) } if flag6 { // 订单总员工毛利 end = append(end, sumData.TotalStaffProfit) } if flag7 { // 销售毛利提成 end = append(end, sumData.TotalSalesProfitPer) } if flag8 { // 员工毛利提成 end = append(end, sumData.TotalStaffProfitPer) } if flag9 { // 销售员提成 end = append(end, sumData.SalesmanPer) } if flag10 { // 门店提成 end = append(end, sumData.StorePer) } end = append(end, "") 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}}`) var endRow string switch nEndCount { case 1: endRow = fmt.Sprintf("AD"+"%d", nExcelStartRow+2) case 2: endRow = fmt.Sprintf("AE"+"%d", nExcelStartRow+2) case 3: endRow = fmt.Sprintf("AF"+"%d", nExcelStartRow+2) case 4: endRow = fmt.Sprintf("AG"+"%d", nExcelStartRow+2) case 5: endRow = fmt.Sprintf("AH"+"%d", nExcelStartRow+2) case 6: endRow = fmt.Sprintf("AI"+"%d", nExcelStartRow+2) case 7: endRow = fmt.Sprintf("AJ"+"%d", nExcelStartRow+2) case 8: endRow = fmt.Sprintf("AK"+"%d", nExcelStartRow+2) case 9: endRow = fmt.Sprintf("AL"+"%d", nExcelStartRow+2) case 10: endRow = fmt.Sprintf("AM"+"%d", nExcelStartRow+2) default: endRow = fmt.Sprintf("AC"+"%d", nExcelStartRow+2) } //endRow := fmt.Sprintf("AL%d", nExcelStartRow+2) // 应用样式到整个表格 _ = file.SetCellStyle("Sheet1", "A1", endRow, style) //需要自动换行的列 endRow1 := fmt.Sprintf("H%d", nExcelStartRow+2) endRow2 := fmt.Sprintf("AI%d", nExcelStartRow+2) endRow3 := fmt.Sprintf("AJ%d", nExcelStartRow+2) endRow4 := fmt.Sprintf("AK%d", nExcelStartRow+2) _ = file.SetCellStyle("Sheet1", "A1", "AM1", style1) _ = file.SetCellStyle("Sheet1", "H2", endRow1, style1) _ = file.SetCellStyle("Sheet1", "AI2", endRow2, style1) _ = file.SetCellStyle("Sheet1", "AJ2", endRow3, style1) _ = file.SetCellStyle("Sheet1", "AK2", 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 } // 支付方式筛选 if req.CashierId != 0 { var tempCashier TotalCashierData switch req.CashierId { case 1: tempCashier.ScanAmount = cashier.ScanAmount case 2: tempCashier.CashAmount = cashier.CashAmount case 3: tempCashier.PosAmount = cashier.PosAmount case 4: tempCashier.StoreVmAmount = cashier.StoreVmAmount default: tempCashier = cashier } cashier = tempCashier } // 退货订单支付汇总:目前零售退货订单暂时不展示各个方式的付款金额 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 sumData.ScanAmount = 0 sumData.CashAmount = 0 sumData.PosAmount = 0 sumData.StoreVmAmount = 0 sumData.OtherAmount = 0 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) erpOrderSetBankTrxNo(orders) fileUrl, err := retailDetailExport(orders, sumData, c) 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) erpOrderSetBankTrxNo(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 commodity.StaffPrice = item.WholesalePrice + item.StaffCostPrice order.Commodities = append(order.Commodities, commodity) orderIdMap[item.ErpOrderId] = order } for _, item := range orderIdMap { orders = append(orders, item) } // 根据AuditTime进行降序排序 sort.SliceStable(orders, func(i, j int) bool { return orders[i].AuditTime.After(*orders[j].AuditTime) }) 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.CashierId != 0 { // 支付方式 qs = qs.Where("JSON_CONTAINS(cashier_list, ?)", fmt.Sprintf(`{"cashier_id":%d}`, req.CashierId)) qs = qs.Where("retail_type=?", RetailTypeSale) //totalPerQs = totalPerQs.Where("erp_order_pay_way.cashier_id = ?", req.CashierId) } 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 } // 支付方式筛选 if req.CashierId != 0 { var tempCashier TotalCashierData switch req.CashierId { case 1: tempCashier.ScanAmount = cashier.ScanAmount case 2: tempCashier.CashAmount = cashier.CashAmount case 3: tempCashier.PosAmount = cashier.PosAmount case 4: tempCashier.StoreVmAmount = cashier.StoreVmAmount default: tempCashier = cashier } cashier = tempCashier } // 退货订单支付汇总:目前零售退货订单暂时不展示各个方式的付款金额 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("audit_time 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) erpOrderSetBankTrxNo(orders) fileUrl, err := retailDetailExport(orders, sumData, c) 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("audit_time 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) erpOrderSetBankTrxNo(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 = orders[0].UpdatedAt 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 } // 四舍五入 tools.RoundFloatFields(req) begin := orm.Eloquent.Begin() if req.Tel != "" { // 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 err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).Omit("created_at").Save(&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()) } var userUid uint32 if req.Tel != "" { // 通过手机号查询用户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()) } 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 (?) and state = ? "+ "and store_id = ?", imeiList, InStock, req.StoreId). 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 (?) and state = ? "+ "and store_id = ?", commodityIds, InStock, req.StoreId). 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 } } } } // 更新用户信息表,添加首次零售订单时间 if req.Tel != "" { 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].RejectedCount) for j := 0; j < int(req.ErpOrderCommodities[i].RejectedCount); j++ { stockIdList, _ := stringToIntArray(req.ErpOrderCommodities[i].ErpStockCommodityID) temp := req.ErpOrderCommodities[i] temp.RejectedAmount = req.ErpOrderCommodities[i].RejectedAmount / float64(req.ErpOrderCommodities[i].RejectedCount) temp.Count = 1 temp.RejectedCount = 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 tools.RoundFloatFields(erpOrder) // 判断线上支付金额是否>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 = math.Round((erpOrder.TotalRetailPrice-erpOrder.TotalAmount)*100) / 100 } 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 saleOrderId uint32 if req.Tel != "" { //非串码商品,且手机号不为空才校验 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)) } saleOrderId = commodities[0].ErpOrderId } else { saleOrderId = item.ErpOrderId } var orderInfo ErpOrder err := orm.Eloquent.Table("erp_order").Where("id = ?", saleOrderId). 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 if req.ErpOrderCommodities[i].ErpOrderId == 0 || req.ErpOrderCommodities[i].ErpOrderId != orderId { //发现前端有时会没传,后端打补丁 req.ErpOrderCommodities[i].ErpOrderId = orderId } } // 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()) } // 1-删除所有的零售订单支付方式 if len(orderSales) != 0 { err = gdb.Delete(&orderSales).Error if err != nil { logger.Error("更新订单销售员信息-删除 error") return errors.New("操作失败:" + err.Error()) } } var newOrderSales []ErpOrderSales for _, reqSales := range req.Salesman { reqSales.ID = 0 if reqSales.ErpOrderId == 0 { reqSales.ErpOrderId = orderId } newOrderSales = append(newOrderSales, reqSales) } // 2-新增所有的零售订单支付方式 if len(newOrderSales) != 0 { err = gdb.Create(&newOrderSales).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()) } // 1-删除所有的零售订单支付方式 if len(orderPayWay) != 0 { err = gdb.Delete(&orderPayWay).Error if err != nil { logger.Error("更新零售订单支付方式-删除 error") return errors.New("操作失败:" + err.Error()) } } var newOrderPayWay []ErpOrderPayWay for _, reqPayWay := range req.Cashiers { payWay := ErpOrderPayWay{ ErpOrderId: orderId, CashierId: reqPayWay.CashierId, Name: reqPayWay.Name, Amount: reqPayWay.Amount, } if payWay.ErpOrderId == 0 { payWay.ErpOrderId = orderId } newOrderPayWay = append(newOrderPayWay, payWay) } // 2-新增所有的零售订单支付方式 if len(newOrderPayWay) != 0 { err = gdb.Create(&newOrderPayWay).Error if err != nil { logger.Error("更新零售订单支付方式-新增 error") return errors.New("操作失败:" + err.Error()) } } return nil }