mh_goadmin_server/app/admin/models/erp_order.go

3255 lines
114 KiB
Go
Raw Normal View History

package models
import (
"encoding/json"
"errors"
"fmt"
"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"
"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 uint32 `json:"total_count"` // 订单商品数量
TotalSalesProfit float64 `json:"total_sales_profit"` // 订单总销售毛利
TotalStaffProfit float64 `json:"total_staff_profit"` // 订单总员工毛利
VmCount uint32 `json:"vm_count"` // 使用会员积分
SaleOrderId uint32 `json:"sale_order_id"` // 销售订单id
PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 1-待支付; 2-已支付
IsPrint uint32 `json:"is_print"` // 是否打印小票 1-未打印 2-已打印
PrintCount uint32 `json:"print_count"` // 小票打印次数
InvoiceCode string `json:"invoice_code"` // 发票代码
InvoiceNumber string `json:"invoice_number"` // 发票编码
RejectedTotalAmount float64 `json:"rejected_total_amount" gorm:"-"` // 订单总退货金额
RejectedTotalCount uint32 `json:"rejected_total_count" gorm:"-"` // 订单总退货数量
StorePer float64 `json:"store_per"` // 门店提成订单总员工毛利X该门店设置好的提成比例保留到小数后两位多余舍去
TotalDiscount float64 `json:"total_discount"` // 订单总优惠:订单所有商品零售优惠+会员优惠+会员积分抵扣之和
Commodities []ErpOrderCommodity `json:"commodities" gorm:"-"` // 零售订单商品信息
Cashiers []ErpOrderCashier `json:"cashiers" gorm:"-"` // 收付款方式
Salesman []ErpOrderSales `json:"salesman" gorm:"-"` // 销售员信息
}
// ErpOrderCommodity 零售订单商品表
type ErpOrderCommodity struct {
Model
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id后端生成
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id
ErpCategoryName string `json:"erp_category_name"` // 分类名称
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 主供应商id
ErpSupplierName string `json:"erp_supplier_name"` // 主供应商名称
IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码
IMEI string `json:"imei" gorm:"index"` // 串码
PresentType uint32 `json:"present_type"` // 赠送类型:1-非赠送 2-赠送
RetailPrice uint32 `json:"retail_price"` // 指导零售价
SalePrice uint32 `json:"sale_price"` // 零售价
Count uint32 `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"` // 备注
RejectedPrice float64 `json:"rejected_price"` // 退货单价
RejectedCount uint32 `json:"rejected_count"` // 退货数量
RejectedAmount float64 `json:"rejected_amount"` // 退货金额
RejectedOrderCommodityId uint32 `json:"rejected_order_commodity_id"` // 退货订单商品id
StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价
WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价
SalesProfit float64 `json:"sales_profit"` // 销售毛利:实际零售价-采购单价;如果为退货订单,则为实际退货价-采购单价
StaffProfit float64 `json:"staff_profit"` // 员工毛利:实际零售价-员工成本价;如果为退货订单,则为实际退货价-员工成本价
}
// 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:"uid" binding:"required"` // 销售员用户ID
Name string `json:"name"` // 销售员用户姓名
SalesProfitPer float64 `json:"sales_profit_per"` // 销售毛利提成每个商品销售毛利X其对应的提成比例后求和如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去
StaffProfitPer float64 `json:"staff_profit_per"` // 员工毛利提成每个商品员工毛利X其对应的提成比例后求和如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去
SalesmanPer float64 `json:"salesman_per"` // 销售员提成订单总员工毛利X该销售员设置好的提成比例如果是两个销售员参与那么两个人算出的提成均除以2保留到小数后两位多余舍去
}
// ErpOrderRecord 订单支付记录表
type ErpOrderRecord struct {
Model
ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id
BillSn string `json:"bill_sn" gorm:"index"` // 单据编号
OutOrderNo string `json:"out_order_no"` // 商户订单号
PlatTrxNo string `json:"plat_trx_no"` // 平台交易流水号
BankOrderNo string `json:"bank_order_no"` // 银行订单号
TotalAmount float64 `json:"total_amount"` // 订单总金额
PayWay string `json:"pay_way"` // 支付方式
Status string `json:"status"` // 支付状态
}
// ErpOrderCreateReq 订单创建入参
type ErpOrderCreateReq struct {
BillSn string `json:"bill_sn"` // 单据编号
StoreId uint32 `json:"store_id" binding:"required"` // 门店id
StoreName string `json:"store_name" binding:"required"` // 门店名称
RetailType string `json:"retail_type" binding:"required"` // 销售类型sale 零售销售; rejected 零售退货
Tel string `json:"tel" binding:"required"` // 会员手机号
MemberType string `json:"member_type" binding:"required"` // 会员类型general 普通; member 会员
TotalRetailPrice float64 `json:"total_retail_price" binding:"required"` // 订单总指导零售价
TotalAmount float64 `json:"total_amount" binding:"required"` // 订单实收金额
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-已支付
StartTime string `json:"start_time"` // 开始时间
EndTime string `json:"end_time"` // 结束时间
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-导出
}
// ErpOrderStoreManageDataResp 查询门店经营出参
type ErpOrderStoreManageDataResp struct {
List []StoreManageData `json:"list"`
Total int `json:"total"` // 总条数
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ExportUrl string `json:"export_url"`
}
// StoreManageData 门店经营数据
type StoreManageData struct {
Date string `json:"date"` // 时间,如:"2023-12-25"
TotalSalesAmount float64 `json:"total_sales_amount"` // 销售额
PromotionFee float64 `json:"promotion_fee"` // 推广费
SalesProfit float64 `json:"sales_profit"` // 销售毛利
StaffProfit float64 `json:"staff_profit"` // 员工毛利
Count uint32 `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 uint32 `json:"total_count"` // 总销售数量
TotalSalesAmount float64 `json:"total_sales_amount"` // 总销售/退货金额
TotalSalesCost float64 `json:"total_sales_cost"` // 总销售成本:销售采购价之和
TotalSalesMargin float64 `json:"total_sales_margin"` // 总销售毛利:销售/退货金额-销售成本
TotalGrossMargins string `json:"total_gross_margins"` // 销售毛利率:销售毛利/销售/退货金额
ExportUrl string `json:"export_url"`
}
// RetailMarginData 商品零售毛利数据
type RetailMarginData struct {
StoreId uint32 `json:"store_id" gorm:"index"` // 门店id
StoreName string `json:"store_name"` // 门店名称
RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id
ErpCategoryName string `json:"erp_category_name"` // 分类名称
Count uint32 `json:"count"` // 销售数量
SalesAmount float64 `json:"sales_amount"` // 销售/退货金额
SalesCost float64 `json:"sales_cost"` // 销售成本:销售采购价之和
SalesMargin float64 `json:"sales_margin"` // 销售毛利:销售/退货金额-销售成本
GrossMargins string `json:"gross_margins"` // 销售毛利率:销售毛利/销售/退货金额
}
// ErpOrderRetailDetailReq 零售明细汇总入参
type ErpOrderRetailDetailReq struct {
BillSn string `json:"bill_sn"` // 单据编号
RetailType string `json:"retail_type"` // 销售类型sale 零售销售; rejected 零售退货
Uid int `json:"uid"` // 用户ID
Tel string `json:"tel"` // 客户手机号
StoreId uint32 `json:"store_id"` // 门店ID
ErpCategoryId uint32 `json:"erp_category_id"` // 分类id
ErpCommodityName string `json:"erp_commodity_name"` // 商品名称
Salesman uint32 `json:"salesman"` // 销售人员ID
StartTime string `json:"start_time"` // 开始时间
EndTime string `json:"end_time"` // 结束时间
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 页面条数
IsExport uint32 `json:"is_export"` // 1-导出
}
// ErpOrderRetailDetailResp 零售明细汇总出参
type ErpOrderRetailDetailResp struct {
Total int `json:"total"` // 总条数(总订单数)
PageIndex int `json:"pageIndex"` // 页码
PageSize int `json:"pageSize"` // 每页展示条数
ExportUrl string `json:"export_url"` // 导出excel地址
List []ErpOrder `json:"list"` // 零售明细
SumData RetailDetailTotalData `json:"sumData"` // 汇总数据
}
// RetailDetailTotalData 零售明细相关金额汇总
type RetailDetailTotalData struct {
Count uint32 `json:"count"` // 销售数量
RetailPrice uint32 `json:"retail_price"` // 指导零售价
SalePrice uint32 `json:"sale_price"` // 零售价
SaleDiscount float64 `json:"sale_discount"` // 零售优惠
MemberDiscount float64 `json:"member_discount"` // 会员优惠
VmDiscount float64 `json:"vm_discount"` // 会员积分抵扣
Amount float64 `json:"amount"` // 实际零售价
WholesalePrice uint32 `json:"wholesale_price"` // 采购单价
StaffPrice uint32 `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"` //店铺地址
}
type TableData struct {
Name string `json:"name"`
SL uint32 `json:"SL"` // 销售数量
DJ uint32 `json:"DJ"` // 商品指导零售价
JE uint32 `json:"JE"` // 商品指导零售价乘以销售数量
}
// List 查询零售订单列表
func (m *ErpOrderListReq) List() (*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.ScanCode, showConfig.ShowAll)
}
if m.CommodityName != "" { // 输入了商品名称进行查询
return QueryListByCommodityName(m, showConfig.ShowAll)
}
qs := orm.Eloquent.Table("erp_order")
if showConfig.ShowAll == "OFF" {
qs = qs.Where("invoice_code != ?", 0)
}
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(`{"uid":%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.StartTime != "" {
parse, err := time.Parse(QueryTimeFormat, m.StartTime)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("created_at > ?", parse)
}
if m.EndTime != "" {
parse, err := time.Parse(QueryTimeFormat, m.EndTime)
if err != nil {
logger.Errorf("err:", err)
}
parse = parse.AddDate(0, 0, 1)
qs = qs.Where("created_at < ?", parse)
}
}
var count int64
err = qs.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
var orders []ErpOrder
err = qs.Debug().Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
// 添加付款、销售员、商品信息
erpOrderListSetCommodity(orders)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
resp.List = orders
//跟之前保持一致
resp.Total = int(count)
resp.PageIndex = page + 1
resp.PageSize = m.PageSize
resp.ShowAll = showConfig.ShowAll
return resp, nil
}
// QueryListByScanCode 通过扫描串码查询列表
func QueryListByScanCode(scanCode, showConfig string) (*ErpOrderListResp, error) {
resp := &ErpOrderListResp{}
var commodity ErpOrderCommodity
err := orm.Eloquent.Table("erp_order_commodity").Where("imei = ?", scanCode).Find(&commodity).Error
if err != nil && err != RecordNotFound {
logger.Error("get erp_order_commodity err:", logger.Field("err", err))
return resp, err
}
var orders []ErpOrder
if showConfig == "OFF" {
err = orm.Eloquent.Table("erp_order").Where("id = ? and pay_status = ? and invoice_code != ?", commodity.ErpOrderId, HavePaid, 0).Find(&orders).Error
} else {
err = orm.Eloquent.Table("erp_order").Where("id = ? and pay_status = ?", commodity.ErpOrderId, HavePaid).Find(&orders).Error
}
if err != nil && err != RecordNotFound {
logger.Error("get erp_order err:", logger.Field("err", err))
return resp, err
}
// 添加付款、销售员、商品信息
erpOrderListSetCommodity(orders)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
resp.List = orders
//跟之前保持一致
resp.Total = 1
resp.PageIndex = 1
resp.PageSize = 10
return resp, nil
}
// QueryListByCommodityName 通过商品名称查询列表
func QueryListByCommodityName(req *ErpOrderListReq, showConfig string) (*ErpOrderListResp, error) {
resp := &ErpOrderListResp{
PageIndex: req.PageIndex,
PageSize: req.PageSize,
}
page := req.PageIndex - 1
if page < 0 {
page = 0
}
if req.PageSize == 0 {
req.PageSize = 10
}
qs := orm.Eloquent.Debug().Table("erp_order_commodity").
Select("erp_order_commodity.*, erp_order.*").
Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id")
if req.CommodityName != "" { // 商品名称
qs = qs.Where("erp_order_commodity.erp_commodity_name like ?", "%"+req.CommodityName+"%")
}
if showConfig == "OFF" {
qs = qs.Where("invoice_code != ?", 0)
}
if req.Tel != "" { // 用户手机号
qs = qs.Where("erp_order.tel=?", req.Tel)
}
if req.StoreId != 0 { // 门店ID
qs = qs.Where("erp_order.store_id=?", req.StoreId)
}
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
}
// UpdateStock 扣减or添加库存
// 零售订单:
// 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"已售"
// 非串码通过门店id、商品id、商品名称查找库存详情表找到库存时间最长的然后更改其状态为"已售"。
// 同时扣减库存表对应的数量,-1
// 零售退货:
// 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"在库"
// 非串码通过门店id、商品id、商品名称查找库存详情表找到状态为"已售"且时间最近的单,将其状态改为"在库"
// 同时扣减库存表对应的数量,+1
func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state 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
}
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).
Update("state", state).Error // 状态更新为销售锁定中
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
if state == SoldOut { // 已售的订单才更新库存数量
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
}
} else { // 非串码商品
var stockCommodity []ErpStockCommodity
// 通过门店id商品id查找状态为1-在库的非串码商品
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+
"and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 1, 1).
Order("id DESC").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 ")
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID).
Update("state", state).Error // 状态更新为销售锁定中
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
if state == SoldOut { // 已售的订单才更新库存数量
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return err
}
}
}
}
} else if erpOrder.RetailType == RetailTypeRejected { // 零售退货订单
for i, _ := range commodities {
if commodities[i].IMEIType == 2 { // 串码商品
if commodities[i].IMEI == "" {
return errors.New("串码为空")
}
err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI).
Update("state", InStock).Error // 状态更新为在库
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
} else { // 非串码商品
var stockCommodity []ErpStockCommodity
// 通过门店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, 2, 1).
Order("id DESC").Find(&stockCommodity).Error
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
if stockCommodity == nil {
return errors.New("RetailTypeRejected find no stock commodity")
}
err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID).
Update("state", InStock).Error // 状态更新为在库
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?",
erpOrder.StoreId, commodities[i].ErpCommodityId).
Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1
if err != nil {
logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err))
return err
}
}
}
} else {
return errors.New("订单类型错误")
}
// 更新用户积分
var vmCount int
var describe, event string
if erpOrder.RetailType == RetailTypeSale && state == SoldOut { // 零售订单,而且订单已支付,更新用户积分
describe = "零售销售获得积分"
event = VmEventErpOrderSale
vmCount = tools.RoundFloat64(erpOrder.TotalAmount)
} else if erpOrder.RetailType == RetailTypeRejected { // 退货订单,扣减用户积分
describe = "零售退货扣除积分"
event = VmEventErpOrderReject
vmCount = 0 - tools.RoundFloat64(erpOrder.TotalAmount)
}
err = UserVmUpdate(gdb, uint32(erpOrder.Uid), vmCount, event, describe)
if err != nil {
logger.Errorf("err:", err)
return err
}
return nil
}
// CheckIsOnlinePay 检查是否包含线上支付
func CheckIsOnlinePay(jCashier []ErpOrderCashier) bool {
for _, cashier := range jCashier {
if cashier.CashierId == OnlinePay || strings.Contains(cashier.Name, "微信") || strings.Contains(cashier.Name, "支付宝") {
return true
}
}
return false
}
// NewErpBillSn 生成零售订单号
func NewErpBillSn() string {
nowTime := time.Now()
rand.Seed(nowTime.UnixNano())
max := 1
for {
if max > 5 {
logger.Error("create sn err")
return ""
}
random := rand.Int31n(9999) + 1000
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_order WHERE bill_sn='%s'", sn))
if err != nil {
logger.Error("exist sn err")
}
if !exist {
return sn
}
max++
}
}
// 添加订单的商品信息
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 = orderCommodities
}
// 添加订单的销售员信息
func erpOrderListSetSalesman(list []ErpOrder) {
for i, _ := range list {
_ = list[i].SetOrderSalesman()
}
}
func (m *ErpOrder) SetOrderSalesman() error {
var salesProfit, staffProfit 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
}
// 四舍五入并保留两位小数
salesProfit = math.Round(salesProfit*100) / 100
staffProfit = math.Round(staffProfit*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 := GetSysUserInfoByUid(item.Uid)
if err != nil {
logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
}
item.Name = userInfo.NickName
item.SalesmanPer = staffProfit * userInfo.SalesCommRate / float64(len(salesmanInfo))
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 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
}
// 四舍五入并保留两位小数
salesProfit = math.Round(salesProfit*100) / 100
staffProfit = math.Round(staffProfit*100) / 100
var salesmanList []ErpOrderSales
for _, item := range m.Salesman {
item.SalesProfitPer = salesProfit / float64(len(m.Salesman))
item.StaffProfitPer = staffProfit / float64(len(m.Salesman))
// 获取员工毛利
userInfo, err := GetSysUserInfoByUid(item.Uid)
if err != nil {
logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err))
}
item.Name = userInfo.NickName
item.SalesmanPer = staffProfit * userInfo.SalesCommRate / float64(len(m.Salesman))
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 != "" {
var cashiers []ErpOrderCashier
err := json.Unmarshal([]byte(m.CashierList), &cashiers)
if err != nil {
logger.Error("unmarshal err:", logger.Field("err", err))
}
m.Cashiers = cashiers
m.CashierList = ""
}
}
func GetErpOrderCommodityMap(ids []uint32) (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").Where("erp_commodity_id IN (?)", ids).Find(&commodities).Error
if err != nil {
logger.Error("commodities err:", logger.Field("err", err))
return commodityMap, err
}
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).Update("first_retail_order", time.Now()).Error
if err != nil {
logger.Error("update user err:", logger.Field("err", err))
}
}
}
// SetInvoice 设置发票内容
func SetInvoice(req *ErpOrderAddInvoiceReq) error {
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("订单未支付")
}
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) error {
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("已审核订单不能删除")
}
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) (*ErpOrderPayResp, error) {
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 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).
Update("pay_status", HavePaid).Error
if err != nil {
logger.Error("ErpOrderPay update erp_order_record err:", logger.Field("err", err))
}
resp.Status = PayOk
logger.Error("ErpOrderPay err2, 订单已支付")
return resp, errors.New("订单已支付")
}
// 查询是否有待支付订单
if checkIsPaying(req.BillSn) {
queryResp, err := QueryErpOrderPayStatus(req.BillSn)
if err != nil {
logger.Error("查询订单失败", logger.Field("err", err))
return resp, err
}
// 等待支付或成功支付则返回,否则新建订单
if queryResp.Status == Paying || queryResp.Status == PayOk {
resp.Status = queryResp.Status
return resp, nil
}
}
// 查询是否有刚初始化的订单
var orderSn string
if checkIsPayInit(req.BillSn) {
var orderRecordInfo ErpOrderRecord
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", req.BillSn, PayInit).
Find(&orderRecordInfo).Error
if err != nil {
logger.Error("未查询到订单:", logger.Field("err", err))
return resp, errors.New("未查询到待支付订单")
}
orderSn = orderRecordInfo.OutOrderNo
} else {
// 创建支付订单号,并记录到支付记录表,关联零售订单号
orderSn = GetErpOrderSn()
var erpOrderRecord ErpOrderRecord
erpOrderRecord.ErpOrderId = orderInfo.ID
erpOrderRecord.BillSn = orderInfo.BillSn
erpOrderRecord.OutOrderNo = orderSn
erpOrderRecord.Status = PayInit
err = orm.Eloquent.Table("erp_order_record").Create(&erpOrderRecord).Error
if err != nil {
logger.Error("Create erp_order_record err:", logger.Field("err", err))
return resp, err
}
}
resp.Status = Paying
// 发起支付扣款
hmPayResp, err := pay.HmJsPayBToCOrder(orderSn, amount, req.AuthCode, "")
if err != nil {
logger.Error("HmJsPayBToCOrder err")
return resp, err
}
// 更新支付状态
var payStatus string
switch hmPayResp.SubCode {
case "SUCCESS":
payStatus = PayOk
case "FAILED":
payStatus = PayFailed
case "WAITING_PAYMENT":
payStatus = Paying
//default:
// payStatus = PayUnknown
}
updateInfo := map[string]interface{}{
"bank_order_no": hmPayResp.BankOrderNo,
"plat_trx_no": hmPayResp.PlatTrxNo,
"total_amount": hmPayResp.TotalAmount,
"pay_way": hmPayResp.PayWay,
"status": payStatus,
}
begin := orm.Eloquent.Begin()
err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderSn).
Updates(updateInfo).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order_record err:", logger.Field("err", err))
return resp, err
}
if payStatus == PayOk { // 支付成功
// 更新零售订单表
err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).
Update("pay_status", HavePaid).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order_record err:", logger.Field("err", err))
return resp, err
}
// 更新库存订单表
err = updateErpStockCommodity(begin, req.BillSn)
if err != nil {
logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err))
return resp, err
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
return resp, fmt.Errorf("ErpOrderPay[commit err]%v", err)
}
resp.Status = payStatus
return resp, nil
}
// QueryErpOrderPayStatus 查询零售订单支付状态
func QueryErpOrderPayStatus(billSn string) (*ErpOrderPayResp, error) {
resp := &ErpOrderPayResp{
Status: Paying,
}
// 查询待支付订单
var orderRecordInfo ErpOrderRecord
err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status in (?)", billSn, []string{Paying, PayOk}).
Find(&orderRecordInfo).Error
if err != nil {
logger.Error("未查询到订单:", logger.Field("err", err))
resp.Status = PayFailed
return resp, errors.New("未查询到待支付订单")
}
if orderRecordInfo.OutOrderNo == "" {
logger.Info("还未创建支付订单")
resp.Status = NoPayOrder
return resp, nil
}
if orderRecordInfo.Status == PayOk {
logger.Info("订单已支付")
resp.Status = PayOk
return resp, nil
}
// 查询支付状态
hmQueryResp, err := pay.HmQueryOrder(orderRecordInfo.OutOrderNo)
if err != nil {
logger.Error("查询失败:", logger.Field("err", err))
return resp, err
}
// 更新订单状态
var payStatus string
switch hmQueryResp.SubCode {
case "SUCCESS":
payStatus = PayOk
case "FAILED":
payStatus = PayFailed
case "WAITING_PAYMENT":
payStatus = Paying
//default:
// payStatus = PayUnknown
}
updateInfo := map[string]interface{}{
"bank_order_no": hmQueryResp.BankOrderNo,
"plat_trx_no": hmQueryResp.PlatTrxNo,
"total_amount": hmQueryResp.TotalAmount,
"pay_way": hmQueryResp.PayWayCode,
"status": payStatus,
}
begin := orm.Eloquent.Begin()
err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderRecordInfo.OutOrderNo).
Updates(updateInfo).Error
if err != nil {
begin.Rollback()
logger.Error("query update erp_order_record err:", logger.Field("err", err))
return resp, err
}
if payStatus == PayOk { // 支付成功
// 更新零售订单表
err = begin.Model(&ErpOrder{}).Where("id = ?", orderRecordInfo.ErpOrderId).
Update("pay_status", HavePaid).Error
if err != nil {
begin.Rollback()
logger.Error("query update erp_order_record err:", logger.Field("err", err))
return resp, err
}
// 更新库存订单表
err = updateErpStockCommodity(begin, billSn)
if err != nil {
logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err))
return resp, err
}
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
return resp, fmt.Errorf("QueryErpOrderPayStatus[commit err]%v", err)
}
resp.Status = payStatus
return resp, nil
}
// 更新库存订单表
func updateErpStockCommodity(gdb *gorm.DB, billSn string) error {
//通过单据号查询订单
var erpOrderInfo []ErpOrder
err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", billSn).Find(&erpOrderInfo).Error
if err != nil {
logger.Error("erp_order 未查询到订单:", logger.Field("err", err))
return err
}
if len(erpOrderInfo) == 0 {
return errors.New("未查询到订单")
}
err = UpdateStock(gdb, erpOrderInfo[0], SoldOut)
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) (*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 showConfig.ShowAll == "OFF" {
qs = qs.Where("invoice_code != ?", 0)
}
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)
}
qs = qs.Where("maker_time IS NOT NULL")
// 查询数据
err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, SUM(total_amount) AS total_sales_amount, " +
"(SUM(total_retail_price) - SUM(total_amount)) AS promotion_fee, " +
"SUM(total_sales_profit) AS sales_profit, SUM(total_staff_profit) AS staff_profit, SUM(total_count) AS count").
Group("date").
Order("date DESC").
Find(&storeManageDataList).Error
if err != nil {
logger.Error("QueryStoreManageData err:", logger.Field("err", err))
return nil, err
}
2024-02-23 10:06:21 +00:00
finalStoreManageDataList := constructFinalStoreManageDataList(storeManageDataList, req)
if req.IsExport == 1 { //导出excel
storeName := "所有门店"
if req.StoreId != 0 {
storeInfo, err := GetStore(req.StoreId)
if err != nil {
logger.Error("GetStore err:", logger.Field("err", err))
return nil, err
}
storeName = storeInfo.Name
}
2024-02-23 10:06:21 +00:00
finalStoreManageDataList = constructFinalStoreManageDataList(storeManageDataList, req)
filePath, err := storeManageDataExport(finalStoreManageDataList, storeName)
if err != nil {
logger.Error("StoreManageDataExport err:", logger.Field("err", err))
return nil, err
}
resp.ExportUrl = filePath
} else {
// 根据页码和页面条数截取结果
startIndex := (req.PageIndex - 1) * req.PageSize
endIndex := startIndex + req.PageSize
if endIndex > len(finalStoreManageDataList) {
endIndex = len(finalStoreManageDataList)
}
resp.List = finalStoreManageDataList[startIndex:endIndex]
resp.Total = len(finalStoreManageDataList)
}
return resp, nil
}
2024-02-23 10:06:21 +00:00
// 查询门店经营数据为空的日期默认填充数据为0
func constructFinalStoreManageDataList(storeManageDataList []StoreManageData, req *ErpOrderStoreManageDataReq) []StoreManageData {
// Create a map to store data by date for easier processing
storeDataMap := make(map[string]StoreManageData)
for _, data := range storeManageDataList {
storeDataMap[data.Date] = data
}
// Construct the final response with consecutive dates and defaulting to 0 for missing data
var finalStoreManageDataList []StoreManageData
startDate, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err))
return storeManageDataList
}
endDate, err := time.Parse(QueryTimeFormat, req.EndTime)
if err != nil {
logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err))
return storeManageDataList
}
for d := startDate; d.Before(endDate) || d.Equal(endDate); 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)
}
return finalStoreManageDataList
}
// StoreManageDataExport 导出门店经营数据
func storeManageDataExport(list []StoreManageData, storeName string) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + storeName + "经营数据" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"时间", "销售额", "推广费", "销售毛利", "员工毛利", "销售数量"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Errorf("file set value err:", err)
}
}
var row []interface{}
nExcelStartRow := 0
for rowId := 0; rowId < len(list); rowId++ {
row = []interface{}{
list[rowId].Date,
list[rowId].TotalSalesAmount,
list[rowId].PromotionFee,
list[rowId].SalesProfit,
list[rowId].StaffProfit,
list[rowId].Count,
}
for j, _ := range row {
cell, _ := excelize.CoordinatesToCellName(1+j, nExcelStartRow+2)
err := file.SetCellValue(fSheet, cell, row[j])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
nExcelStartRow++
}
// 设置所有单元格的样式: 居中、加边框
style, _ := file.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},
"border":[{"type":"left","color":"000000","style":1},
{"type":"top","color":"000000","style":1},
{"type":"right","color":"000000","style":1},
{"type":"bottom","color":"000000","style":1}]}`)
//设置单元格高度
file.SetRowHeight("Sheet1", 1, 20)
// 设置单元格大小
file.SetColWidth("Sheet1", "A", "A", 18)
endRow := fmt.Sprintf("F"+"%d", nExcelStartRow+1)
// 应用样式到整个表格
_ = file.SetCellStyle("Sheet1", "A1", endRow, style)
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// retailMarginDataExport 导出商品零售毛利汇总数据
func retailMarginDataExport(req *ErpOrderRetailMarginResp) (string, error) {
file := excelize.NewFile()
streamWriter, err := file.NewStreamWriter("Sheet1")
if err != nil {
fmt.Println(err)
}
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "商品零售毛利汇总" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"店铺名称", "零售类型", "商品名称", "商品分类", "数量", "销售/退货金额", "销售成本", "销售毛利", "销售毛利率"}
cell, _ := excelize.CoordinatesToCellName(1, 1)
if err = streamWriter.SetRow(cell, title); err != nil {
fmt.Println(err)
}
var row []interface{}
nExcelStartRow := 0
for rowId := 0; rowId < len(req.List); rowId++ {
var saleType string
if req.List[rowId].RetailType == RetailTypeSale {
saleType = "零售销售"
} else if req.List[rowId].RetailType == RetailTypeRejected {
saleType = "零售退货"
} else {
logger.Error("订单类型异常")
return "", errors.New("RetailMarginDataExport, 订单类型异常:" + req.List[rowId].RetailType)
}
row = []interface{}{
req.List[rowId].StoreName,
saleType,
req.List[rowId].ErpCommodityName,
req.List[rowId].ErpCategoryName,
req.List[rowId].Count,
req.List[rowId].SalesAmount,
req.List[rowId].SalesCost,
req.List[rowId].SalesMargin,
req.List[rowId].GrossMargins,
}
cell, _ := excelize.CoordinatesToCellName(1, nExcelStartRow+2)
if err := streamWriter.SetRow(cell, row); err != nil {
fmt.Println(err)
}
nExcelStartRow++
}
totalData := "汇总 记录数:" + strconv.FormatInt(int64(req.TotalCount), 10)
end := []interface{}{totalData, "", "", "", req.TotalCount, req.TotalSalesAmount, req.TotalSalesCost,
req.TotalSalesMargin, req.TotalGrossMargins}
cell, _ = excelize.CoordinatesToCellName(1, nExcelStartRow+2)
if err := streamWriter.SetRow(cell, end); err != nil {
fmt.Println(err)
}
if err := streamWriter.Flush(); err != nil {
fmt.Println(err)
}
fmt.Println("save fileName:", config.ExportConfig.Path+fileName)
if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil {
fmt.Println(err)
}
return url + fileName, nil
}
// QueryRetailMargin 查询零售毛利汇总数据
func QueryRetailMargin(req *ErpOrderRetailMarginReq) (*ErpOrderRetailMarginResp, error) {
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.created_at>?", 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.created_at<?", endTime)
} else {
logger.Errorf("QueryRetailMargin time end parse err:", err.Error())
}
}
if showConfig.ShowAll == "OFF" {
qs = qs.Where("erp_order.invoice_code != ?", 0)
}
var result []struct {
ErpOrderCommodity
StoreID uint32
StoreName string
RetailType string
}
qs.Where("erp_order.pay_status = ?", HavePaid)
es := qs
// 添加排序规则
qs = qs.Order("erp_order.retail_type ASC, erp_order_commodity.erp_commodity_id ASC, erp_order.store_id ASC")
if req.IsExport == 1 { //导出excel
err := qs.Find(&result).Error
if err != nil {
logger.Errorf("QueryRetailMargin find err:", err.Error())
return nil, err
}
var data RetailMarginData
var list []RetailMarginData
for _, item := range result {
data.StoreId = item.StoreID
data.StoreName = item.StoreName
data.RetailType = item.RetailType
data.ErpCommodityId = item.ErpCommodityId
data.ErpCommodityName = item.ErpCommodityName
data.ErpCategoryId = item.ErpCategoryId
data.ErpCategoryName = item.ErpCategoryName
data.Count = item.Count
data.SalesAmount = item.ReceivedAmount
data.SalesCost = float64(item.WholesalePrice * item.Count)
data.SalesMargin = data.SalesAmount - data.SalesCost
data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount)
if data.RetailType == RetailTypeRejected {
data.SalesAmount = -data.SalesAmount
data.SalesCost = -data.SalesCost
data.SalesMargin = -data.SalesMargin
}
list = append(list, data)
resp.List = list
resp.TotalCount += data.Count
resp.TotalSalesAmount += data.SalesAmount
resp.TotalSalesCost += data.SalesCost
resp.TotalSalesMargin += data.SalesMargin
}
if resp.TotalSalesAmount != 0 {
resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount)
}
filePath, err := retailMarginDataExport(resp)
if err != nil {
logger.Error("StoreManageDataExport err:", logger.Field("err", err))
return nil, err
}
resp.ExportUrl = filePath
} else {
err := qs.Find(&result).Offset(page * req.PageSize).Limit(req.PageSize).Error
if err != nil {
logger.Errorf("QueryRetailMargin find err:", err.Error())
return nil, err
}
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Errorf("QueryRetailMargin count err:", err.Error())
return nil, err
}
var data RetailMarginData
var list []RetailMarginData
for _, item := range result {
data.StoreId = item.StoreID
data.StoreName = item.StoreName
data.RetailType = item.RetailType
data.ErpCommodityId = item.ErpCommodityId
data.ErpCommodityName = item.ErpCommodityName
data.ErpCategoryId = item.ErpCategoryId
data.ErpCategoryName = item.ErpCategoryName
data.Count = item.Count
data.SalesAmount = item.ReceivedAmount
data.SalesCost = float64(item.WholesalePrice * item.Count)
data.SalesMargin = data.SalesAmount - data.SalesCost
data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount)
if data.RetailType == RetailTypeRejected {
data.SalesAmount = -data.SalesAmount
data.SalesCost = -data.SalesCost
data.SalesMargin = -data.SalesMargin
}
list = append(list, data)
resp.TotalCount += data.Count
resp.TotalSalesAmount += data.SalesAmount
resp.TotalSalesCost += data.SalesCost
resp.TotalSalesMargin += data.SalesMargin
}
if resp.TotalSalesAmount != 0 {
resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount)
}
resp.List = list
resp.Total = int(count)
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) (*ErpOrderRetailDetailResp, error) {
resp := &ErpOrderRetailDetailResp{}
var err error
if (req.ErpCategoryId != 0 || req.ErpCommodityName != "") && req.BillSn == "" { // 商品分类or商品名称不为空且订单编号为空
// 联表查询
resp, err = queryRetailDetailByJoin(req)
} else {
// 普通单表查询,然后补充收款数据和商品数据
resp, err = queryRetailDetailCommon(req)
}
if err != nil {
logger.Error("queryRetailDetailCommon err")
return nil, err
}
return resp, nil
}
// 导出零售明细报表excel
func retailDetailExport(list []ErpOrder, sumData RetailDetailTotalData) (string, error) {
file := excelize.NewFile()
fSheet := "Sheet1"
url := ExportUrl
fileName := time.Now().Format(TimeFormat) + "零售明细" + ".xlsx"
fmt.Println("url fileName:", url+fileName)
title := []interface{}{"订单编号", "订单类型", "用户ID", "客户手机号", "审核时间", "店铺", "销售员", "商品分类", "商品名称",
"供应商", "是否串码", "商品串码", "是否赠送", "销售数量", "指导零售价", "零售价", "零售优惠", "会员优惠", "实际零售价/退货价",
"采购单价", "员工成本价", "销售毛利", "员工毛利", "订单总指导零售价", "订单总优惠", "订单实收", "【扫码付", "现金收款", "pos机收款",
"商场积分抵扣", "其他付款方式】", "订单总销售毛利", "订单总员工毛利", "销售毛利提成", "员工毛利提成", "销售员提成", "门店提成", "备注"}
for i, _ := range title {
cell, _ := excelize.CoordinatesToCellName(1+i, 1)
err := file.SetCellValue(fSheet, cell, title[i])
if err != nil {
logger.Error("file set value err:", logger.Field("err", err))
}
}
var row []interface{}
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)
}
// 先判断商品数量,确定要写几行数据
for rowId := 0; rowId < len(list[i].Commodities); rowId++ {
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
}
}
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,
list[i].Commodities[rowId].Amount,
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,
strSalesProfitPer, // 销售毛利提成
strStaffProfitPer, // 员工毛利提成
strSalesmanPer, // 销售员提成
list[i].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
}
// RetailDetailByJoin 联表查询扫描参数
type RetailDetailByJoin struct {
ErpOrderCommodity
ErpOrder
}
// 联表查询
func queryRetailDetailByJoin(req *ErpOrderRetailDetailReq) (*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")
if req.ErpCategoryId != 0 { // 商品分类
qs = qs.Where("erp_order_commodity.erp_category_id=?", req.ErpCategoryId)
}
if req.ErpCommodityName != "" { // 商品名称
qs = qs.Where("erp_order_commodity.erp_commodity_name like ?", "%"+req.ErpCommodityName+"%")
}
if req.RetailType != "" { // 销售类型
qs = qs.Where("erp_order.retail_type=?", req.RetailType)
}
if req.Uid != 0 { // 用户ID
qs = qs.Where("erp_order.uid=?", req.Uid)
}
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 req.Salesman != 0 { // 销售员
2024-02-23 10:06:21 +00:00
qs = qs.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"uid":%d}`, req.Salesman))
}
if req.StartTime != "" { // 审核开始时间
2024-02-23 10:06:21 +00:00
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("erp_order.audit_time > ?", parse)
}
if req.EndTime != "" { // 审核结束时间
2024-02-23 10:06:21 +00:00
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)
}
if showConfig.ShowAll == "OFF" {
qs = qs.Where("erp_order.invoice_code != ?", 0)
}
qs.Where("erp_order.pay_status = ?", HavePaid)
es := qs
var sumData RetailDetailTotalData
orderSumQs := qs
totalPerQs := qs
cashierQs := qs
err = orderSumQs.Debug().Select("SUM(erp_order_commodity.count) as count, " +
"SUM(erp_order_commodity.retail_price) as retail_price, " +
"SUM(erp_order_commodity.sale_price) as sale_price, " +
"SUM(erp_order_commodity.sale_discount) as sale_discount, " +
"SUM(erp_order_commodity.member_discount) as member_discount, " +
"SUM(erp_order_commodity.Amount) as Amount, " +
"SUM(erp_order_commodity.wholesale_price) as wholesale_price, " +
"(SUM(erp_order_commodity.wholesale_price) + SUM(erp_order_commodity.staff_cost_price)) as staff_price, " +
"SUM(erp_order_commodity.sales_profit) as sales_profit, " +
"SUM(erp_order_commodity.staff_profit) 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").
Scan(&sumData).Error
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return resp, err
}
var totalPerData TotalPerData
err = totalPerQs.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").
Scan(&totalPerData).Error
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return resp, err
}
var cashier TotalCashierData
err = cashierQs.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").
Scan(&cashier).Error
if err != nil {
logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
return resp, err
}
//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
sumData.TotalSalesProfit = 0 // 订单总销售毛利
sumData.TotalStaffProfit = 0 // 订单总员工毛利
sumData.TotalRetailPrice = 0 // 订单总指导零售价
sumData.TotalDiscount = 0 // 订单总优惠
sumData.TotalAmount = 0 // 订单实收金额
sumData.StorePer = 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)
fileUrl, err := retailDetailExport(orders, sumData)
if err != nil {
logger.Error("retailDetailExport err:", logger.Field("err", err))
return resp, err
}
resp.ExportUrl = fileUrl
} else {
err = qs.Order("erp_order.audit_time DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&result).Error
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
resp.SumData = sumData
}
return resp, nil
}
// 组合数据
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.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
}
// 订单商品数据
commodity.ErpOrderId = item.ErpOrderId
commodity.ErpCategoryId = item.ErpCategoryId
commodity.ErpCategoryName = item.ErpCategoryName
commodity.ErpCommodityId = item.ErpCommodityId
commodity.ErpCommodityName = item.ErpCommodityName
commodity.IMEIType = item.IMEIType
commodity.IMEI = item.IMEI
commodity.PresentType = item.PresentType
commodity.RetailPrice = item.RetailPrice
commodity.SalePrice = item.SalePrice
commodity.Count = item.Count
commodity.SaleDiscount = item.SaleDiscount
commodity.MemberDiscount = item.MemberDiscount
commodity.VmDiscount = item.VmDiscount
commodity.Amount = item.Amount
commodity.ReceivedAmount = item.ReceivedAmount
commodity.Remark = item.Remark
commodity.RejectedPrice = item.RejectedPrice
commodity.RejectedCount = item.RejectedCount
commodity.RejectedAmount = item.RejectedAmount
commodity.RejectedOrderCommodityId = item.RejectedOrderCommodityId
commodity.StaffCostPrice = item.StaffCostPrice
commodity.WholesalePrice = item.WholesalePrice
commodity.ErpSupplierId = item.ErpSupplierId
commodity.ErpSupplierName = item.ErpSupplierName
commodity.SalesProfit = item.SalesProfit
commodity.StaffProfit = item.StaffProfit
order.Commodities = append(order.Commodities, commodity)
orderIdMap[item.ErpOrderId] = order
}
for _, item := range orderIdMap {
orders = append(orders, item)
}
return orders
}
// 普通单表查询,然后补充收款数据和商品数据
func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*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")
if showConfig.ShowAll == "OFF" {
qs = qs.Where("invoice_code != ?", 0)
}
if req.BillSn != "" { // 订单编号
qs = qs.Where("bill_sn=?", req.BillSn)
} else {
if req.RetailType != "" { // 销售类型
qs = qs.Where("retail_type=?", req.RetailType)
}
if req.Uid != 0 { // 用户ID
2024-02-23 10:06:21 +00:00
qs = qs.Where("erp_order.uid=?", req.Uid)
}
if req.Tel != "" { // 用户手机号
qs = qs.Where("tel=?", req.Tel)
}
if req.StoreId != 0 { // 门店ID
qs = qs.Where("store_id=?", req.StoreId)
}
if req.Salesman != 0 { // 销售员
2024-02-23 10:06:21 +00:00
qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"uid":%d}`, req.Salesman))
}
if req.StartTime != "" { // 审核开始时间
2024-02-23 10:06:21 +00:00
parse, err := time.Parse(QueryTimeFormat, req.StartTime)
if err != nil {
logger.Errorf("err:", err)
}
qs = qs.Where("audit_time > ?", parse)
}
if req.EndTime != "" { // 审核结束时间
2024-02-23 10:06:21 +00:00
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)
}
}
qs.Where("erp_order.pay_status = ?", HavePaid)
es := qs
var sumData RetailDetailTotalData
orderSumQs := qs
totalPerQs := qs
cashierQs := qs
err = orderSumQs.Debug().Select("SUM(erp_order_commodity.count) as count, " +
"SUM(erp_order_commodity.retail_price) as retail_price, " +
"SUM(erp_order_commodity.sale_price) as sale_price, " +
"SUM(erp_order_commodity.sale_discount) as sale_discount, " +
"SUM(erp_order_commodity.member_discount) as member_discount, " +
"SUM(erp_order_commodity.Amount) as Amount, " +
"SUM(erp_order_commodity.wholesale_price) as wholesale_price, " +
"(SUM(erp_order_commodity.wholesale_price) + SUM(erp_order_commodity.staff_cost_price)) as staff_price, " +
"(SUM(erp_order_commodity.Amount) - SUM(erp_order_commodity.wholesale_price)) as sales_profit, " +
"(SUM(erp_order_commodity.Amount) - SUM(erp_order_commodity.wholesale_price) - SUM(erp_order_commodity.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 erp_order_commodity ON erp_order_commodity.erp_order_id = erp_order.id").
Scan(&sumData).Error
if err != nil {
logger.Error("query sum data err:", logger.Field("err", err))
return resp, err
}
var totalPerData TotalPerData
err = totalPerQs.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").
Scan(&totalPerData).Error
if err != nil {
logger.Error("query erp_order_sales sum data err:", logger.Field("err", err))
return resp, err
}
var cashier TotalCashierData
err = cashierQs.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").
Scan(&cashier).Error
if err != nil {
logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err))
return resp, err
}
sumData.TotalSalesProfitPer = totalPerData.TotalSalesProfitPer
sumData.TotalStaffProfitPer = totalPerData.TotalStaffProfitPer
sumData.SalesmanPer = totalPerData.SalesmanPer
sumData.ScanAmount = cashier.ScanAmount
sumData.CashAmount = cashier.CashAmount
sumData.PosAmount = cashier.PosAmount
sumData.StoreVmAmount = cashier.StoreVmAmount
sumData.OtherAmount = cashier.OtherAmount
if req.IsExport == 1 { // 导出excel
var orders []ErpOrder
err = qs.Order("id DESC").Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
erpOrderListSetCommodity(orders)
erpOrderListSetSalesman(orders)
fileUrl, err := retailDetailExport(orders, sumData)
if err != nil {
logger.Error("retailDetailExport err:", logger.Field("err", err))
return resp, err
}
resp.ExportUrl = fileUrl
} else {
var count int64
err = es.Count(&count).Error
if err != nil {
logger.Error("count err:", logger.Field("err", err))
return resp, err
}
var orders []ErpOrder
err = qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&orders).Error
if err != nil && err != RecordNotFound {
logger.Error("erp commodity list err:", logger.Field("err", err))
return resp, err
}
// 添加付款、销售员、商品信息
erpOrderListSetCommodity(orders)
erpOrderListSetCashier(orders)
erpOrderListSetSalesman(orders)
resp.List = orders
//跟之前保持一致
resp.Total = int(count)
resp.PageIndex = page + 1
resp.PageSize = req.PageSize
resp.SumData = sumData
}
return resp, nil
}
// QueryReceiptData 查询小票数据
func QueryReceiptData(req *ErpOrderDeleteReq) (*ErpOrderReceiptDataResp, error) {
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 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
}
order := orders[0]
resp := new(ErpOrderReceiptDataResp)
resp.StoreName = order.StoreName
resp.Barcode = order.BillSn
resp.OddNum = order.BillSn
resp.Time = Now()
resp.CollectS = order.MakerName
commodityMap := make(map[string]TableData, 0)
for i, item := range order.Commodities {
var tableData TableData
tableData.Name = item.ErpCommodityName
tableData.SL = item.Count
tableData.DJ = item.RetailPrice
tableData.JE = item.Count * item.RetailPrice
key := fmt.Sprintf("commodity_%d", i)
commodityMap[key] = tableData
resp.TotalAmount += item.SaleDiscount
resp.MembersAmount += item.MemberDiscount
resp.IntegrationAmount += item.VmDiscount
}
resp.ChandiseObj = commodityMap
resp.TotalRetailP = order.TotalRetailPrice
resp.TotalNum = 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
resp.StoreTel = storeInfo.Tel
resp.StoreAddress = storeInfo.Address
return resp, nil
}
// CreateErpOrder 创建零售订单
func CreateErpOrder(req *ErpOrderCreateReq, sysUser *SysUser) error {
// 校验订单数据
erpOrder, err := checkOrderData(req, sysUser)
if err != nil {
return err
}
begin := orm.Eloquent.Begin()
// 0-创建用户信息
userInfo, err := GetUserInfoByTel(req.Tel)
if err != nil {
logger.Error("checkOrderData GetUserInfoByTel err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
if userInfo.Uid == 0 {
user := UserInfo{
Uid: uint32(erpOrder.Uid),
Tel: req.Tel,
StoreId: uint64(req.StoreId),
UserType: 1, // 用户
OpenMemberLevel: 1, // 普通会员
MemberLevel: 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, sysUser *SysUser) 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, sysUser)
if err != nil {
return err
}
erpOrder.ID = orderInfo.ID
erpOrder.BillSn = orderInfo.BillSn // 编辑的订单单据号不能改变
begin := orm.Eloquent.Begin()
// 1-更新零售订单
err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID).Updates(erpOrder).Error
if err != nil {
begin.Rollback()
logger.Error("update erp_order err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 2-更新零售订单商品信息
err = updateCommodityData(begin, orderInfo.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_order_commodity err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 3-更新销售员信息记录
err = updateSalesData(begin, orderInfo.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_order_sales err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
// 4-更新支付方式记录
err = updatePayWayData(begin, orderInfo.ID, req)
if err != nil {
begin.Rollback()
logger.Error("update erp_order_pay_way err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
logger.Error("commit err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
return nil
}
// checkOrderData 校验订单数据
func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) {
jCashier, err := json.Marshal(req.Cashiers)
if err != nil {
logger.Error("cashiers marshal err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
// 通过手机号查询用户id如果没有则新建一个用户id
userInfo, err := GetUserInfoByTel(req.Tel)
if err != nil {
logger.Error("checkOrderData GetUserInfoByTel err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
var userUid uint32
if userInfo.Uid == 0 {
userUid = CreateUid() // 没有用户则新建
} else {
userUid = userInfo.Uid
}
erpOrder := &ErpOrder{
BillSn: NewErpBillSn(),
RetailType: req.RetailType,
Uid: int(userUid),
Tel: req.Tel,
StoreId: req.StoreId,
StoreName: req.StoreName,
MakerId: uint32(sysUser.UserId),
MakerName: sysUser.NickName,
MakerTime: time.Now(),
CashierList: string(jCashier),
MemberType: req.MemberType,
State: ErpOrderStateUnAudit,
PayStatus: NoCreatePayOrder,
IsPrint: NoPrint, // 未打印
PrintCount: 0, // 打印次数
TotalRetailPrice: req.TotalRetailPrice,
VmCount: req.VmAmount,
}
commodityMap := make(map[uint32]ErpStockCommodity)
imeiCommodityMap := make(map[string]ErpStockCommodity)
if req.RetailType == RetailTypeSale { // 零售订单,查商品表信息
commodityIds := make([]uint32, 0, len(req.ErpOrderCommodities)) // 非串码商品的商品id列表
imeiList := make([]string, 0, len(req.ErpOrderCommodities)) // 串码商品的串码列表
for i, _ := range req.ErpOrderCommodities {
if req.ErpOrderCommodities[i].IMEIType == 1 { // 非串码商品
commodityIds = append(commodityIds, req.ErpOrderCommodities[i].ErpCommodityId)
} else { // 串码商品
imeiList = append(imeiList, req.ErpOrderCommodities[i].IMEI)
}
}
// 商品的相关价格以库存表为准,商品表的价格除了最低零售价,其他只是参考
// 串码商品直接查询;非串码商品查询库存时间最久的商品
var commodities []ErpStockCommodity
if len(imeiList) != 0 {
err := orm.Eloquent.Table("erp_stock_commodity").Where("imei IN (?)", imeiList).
Find(&commodities).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
for i, _ := range commodities { // 串码
imeiCommodityMap[commodities[i].IMEI] = commodities[i]
}
}
if len(commodityIds) != 0 {
commodities = nil
err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id IN (?)", commodityIds).
Find(&commodities).Error
if err != nil {
logger.Error("get commodities err:", logger.Field("err", err))
return nil, errors.New("操作失败:" + err.Error())
}
for _, commodity := range commodities { // 非串码
v, ok := commodityMap[commodity.ErpCommodityId]
if !ok { // 没有则直接添加
commodityMap[commodity.ErpCommodityId] = commodity
} else {
// 已有则比较非串码的入库时间,添加入库时间最早的商品
if commodity.FirstStockTime.Before(v.FirstStockTime) {
commodityMap[commodity.ErpCommodityId] = commodity
}
}
}
}
// 更新用户信息表,添加首次零售订单时间
SetUserInfo(req.Tel)
}
var orderCommodityMap map[uint32]ErpOrderCommodity
if req.RetailType == RetailTypeRejected { // 零售退货订单,查零售商品表
ids := make([]uint32, 0, len(req.ErpOrderCommodities))
for i, _ := range req.ErpOrderCommodities {
ids = append(ids, req.ErpOrderCommodities[i].RejectedOrderCommodityId)
}
orderCommodityMap, err = GetErpOrderCommodityMap(ids)
if err != nil {
logger.Error("order commodity map err:", logger.Field("err", err))
return nil, err
}
}
// 校验商品相关金额是否符合要求
for i, item := range req.ErpOrderCommodities {
if req.RetailType == RetailTypeRejected { // 零售退货订单
if item.RejectedOrderCommodityId == 0 {
logger.Error("rejected_order_commodity_id is null")
return nil, errors.New("rejected_order_commodity_id is null")
}
v, ok := orderCommodityMap[req.ErpOrderCommodities[i].RejectedOrderCommodityId]
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
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 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].ReceivedAmount
erpOrder.TotalCount += req.ErpOrderCommodities[i].Count
// 销售毛利 // todo 待测试核实
salesProfit := v.ReceivedAmount - float64(v.WholesalePrice*v.Count)
if salesProfit < 0 {
logger.Error("rejected salesProfit less than 0")
return nil, errors.New("商品销售毛利小于0请检查")
}
// 员工毛利 // todo 待测试核实
StaffProfit := salesProfit - float64(v.StaffCostPrice*v.Count)
if StaffProfit < 0 {
logger.Error("rejected TotalStaffProfit less than 0")
return nil, errors.New("商品员工毛利小于0请检查")
}
req.ErpOrderCommodities[i].SalesProfit = salesProfit // 销售毛利
req.ErpOrderCommodities[i].StaffProfit = StaffProfit // 员工毛利
erpOrder.TotalSalesProfit += salesProfit
erpOrder.TotalStaffProfit += StaffProfit
} 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("遍历商品信息报错")
}
}
// 零售订单需校验商品是否有库存
if !CommodityIsHaveStock(req.ErpOrderCommodities[i], req.StoreId) {
logger.Error("商品" + "[" + v.ErpCommodityName + "]库存不足, 门店:" + req.StoreName)
return nil, errors.New("商品" + "[" + v.ErpCommodityName + "]库存不足")
}
req.ErpOrderCommodities[i].ID = 0
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].MemberDiscount = v.MemberDiscount // 会员优惠
req.ErpOrderCommodities[i].StaffCostPrice = v.StaffCostPrice // 员工成本价加价
req.ErpOrderCommodities[i].WholesalePrice = v.WholesalePrice // 指导采购价
if req.ErpOrderCommodities[i].PresentType == 2 && v.MinRetailPrice != 0 { // 赠送类型商品进行校验最低零售价为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("零售价不能低于最低零售价,请检查")
}
// 更新订单表总金额和数量
erpOrder.TotalAmount += req.ErpOrderCommodities[i].ReceivedAmount
erpOrder.TotalCount += req.ErpOrderCommodities[i].Count
// 销售毛利
salesProfit := req.ErpOrderCommodities[i].ReceivedAmount -
float64(req.ErpOrderCommodities[i].WholesalePrice*req.ErpOrderCommodities[i].Count)
if salesProfit < 0 {
logger.Error("salesProfit less than 0")
return nil, errors.New("商品销售毛利小于0请检查")
}
// 员工毛利
StaffProfit := salesProfit - float64(req.ErpOrderCommodities[i].StaffCostPrice*req.ErpOrderCommodities[i].Count)
if StaffProfit < 0 {
logger.Error("TotalStaffProfit less than 0")
return nil, errors.New("商品员工毛利小于0请检查")
}
req.ErpOrderCommodities[i].SalesProfit = salesProfit // 销售毛利
req.ErpOrderCommodities[i].StaffProfit = StaffProfit // 员工毛利
erpOrder.TotalSalesProfit += salesProfit
erpOrder.TotalStaffProfit += StaffProfit
}
}
// 添加销售员相关信息
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
// 订单总优惠
erpOrder.TotalDiscount = erpOrder.TotalRetailPrice - erpOrder.TotalAmount
return erpOrder, 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())
}
var newCommodities []ErpOrderCommodity
var deletedCommodities []ErpOrderCommodity
var matchingCommodities []ErpOrderCommodity
// 找到新增的商品
for i, reqCommodity := range req.ErpOrderCommodities {
// 订单商品表信息添加零售订单id
req.ErpOrderCommodities[i].ErpOrderId = orderId
var found bool
for _, dbCommodity := range commodities {
if reqCommodity.ErpCommodityId == dbCommodity.ErpCommodityId {
found = true
break
}
}
if !found {
newCommodities = append(newCommodities, reqCommodity)
}
}
// 找到删除的商品
for _, dbCommodity := range commodities {
var found bool
for _, reqCommodity := range req.ErpOrderCommodities {
if reqCommodity.ErpCommodityId == dbCommodity.ErpCommodityId {
found = true
// 找到匹配的商品,加入匹配列表
matchingCommodities = append(matchingCommodities, dbCommodity)
break
}
}
if !found {
deletedCommodities = append(deletedCommodities, dbCommodity)
}
}
// 2-更新商品订单信息-更新
for _, commodity := range matchingCommodities {
if err = gdb.Model(&ErpOrderCommodity{}).Where("id = ?", commodity.ID).Updates(commodity).Error; err != nil {
logger.Error("更新商品订单信息-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 2-更新商品订单信息-新增
if len(newCommodities) != 0 {
err = gdb.Create(&newCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
//2-更新商品订单信息-删除
if len(deletedCommodities) != 0 {
err = gdb.Delete(&deletedCommodities).Error
if err != nil {
logger.Error("更新商品订单信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}
// updateSalesData 更新订单销售员信息
func updateSalesData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
// 查询现有的零售订单销售员信息
var orderSales []ErpOrderSales
err := orm.Eloquent.Table("erp_order_sales").Where("erp_order_id = ?", orderId).Find(&orderSales).Error
if err != nil {
logger.Error("query erp_order_sales err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
var newOrderSales []ErpOrderSales
var deletedOrderSales []ErpOrderSales
var matchingOrderSales []ErpOrderSales
// 找到新增的商品
for _, reqSales := range req.Salesman {
var found bool
for _, dbSales := range orderSales {
if reqSales.Uid == dbSales.Uid {
found = true
break
}
}
if !found {
newOrderSales = append(newOrderSales, reqSales)
}
}
// 找到删除的商品
for _, dbSales := range orderSales {
var found bool
for _, reqSales := range req.Salesman {
if reqSales.Uid == dbSales.Uid {
found = true
// 找到匹配的商品,加入匹配列表
matchingOrderSales = append(matchingOrderSales, dbSales)
break
}
}
if !found {
deletedOrderSales = append(deletedOrderSales, dbSales)
}
}
// 更新
for _, orderSaleInfo := range matchingOrderSales {
if err = gdb.Model(&ErpOrderSales{}).Where("id = ?", orderSaleInfo.ID).Updates(orderSaleInfo).Error; err != nil {
logger.Error("更新订单销售员信息-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 新增
if len(newOrderSales) != 0 {
err = gdb.Create(&newOrderSales).Error
if err != nil {
logger.Error("更新订单销售员信息-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
// 删除
if len(deletedOrderSales) != 0 {
err = gdb.Delete(&deletedOrderSales).Error
if err != nil {
logger.Error("更新订单销售员信息-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}
// updatePayWayData 更新零售订单支付方式记录表
func updatePayWayData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error {
// 查询现有的零售订单销售员信息
var orderPayWay []ErpOrderPayWay
err := orm.Eloquent.Table("erp_order_pay_way").Where("erp_order_id = ?", orderId).Find(&orderPayWay).Error
if err != nil {
logger.Error("query erp_order_sales err:", logger.Field("err", err))
return errors.New("操作失败:" + err.Error())
}
var newOrderPayWay []ErpOrderPayWay
var deletedOrderPayWay []ErpOrderPayWay
var matchingOrderPayWay []ErpOrderPayWay
// 找到新增的商品
for _, reqPayWay := range req.Cashiers {
var found bool
for _, dbPayWay := range orderPayWay {
if reqPayWay.CashierId == dbPayWay.CashierId {
found = true
break
}
}
if !found {
payWay := ErpOrderPayWay{
ErpOrderId: orderId,
CashierId: reqPayWay.CashierId,
Name: reqPayWay.Name,
Amount: reqPayWay.Amount,
}
newOrderPayWay = append(newOrderPayWay, payWay)
}
}
// 找到删除的商品
for _, dbPayWay := range orderPayWay {
var found bool
for _, reqPayWay := range req.Cashiers {
if reqPayWay.CashierId == dbPayWay.CashierId {
found = true
// 找到匹配的商品,加入匹配列表
matchingOrderPayWay = append(matchingOrderPayWay, dbPayWay)
break
}
}
if !found {
deletedOrderPayWay = append(deletedOrderPayWay, dbPayWay)
}
}
// 更新
for _, orderPayWayInfo := range matchingOrderPayWay {
if err = gdb.Model(&ErpOrderPayWay{}).Where("id = ?", orderPayWayInfo.ID).Updates(orderPayWayInfo).Error; err != nil {
logger.Error("更新零售订单支付方式-更新 error")
return errors.New("操作失败:" + err.Error())
}
}
// 新增
if len(newOrderPayWay) != 0 {
err = gdb.Create(&newOrderPayWay).Error
if err != nil {
logger.Error("更新零售订单支付方式-新增 error")
return errors.New("操作失败:" + err.Error())
}
}
// 删除
if len(deletedOrderPayWay) != 0 {
err = gdb.Delete(&deletedOrderPayWay).Error
if err != nil {
logger.Error("更新零售订单支付方式-删除 error")
return errors.New("操作失败:" + err.Error())
}
}
return nil
}