1419 lines
49 KiB
Go
1419 lines
49 KiB
Go
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/config"
|
||
"gorm.io/gorm"
|
||
"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"
|
||
)
|
||
|
||
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数据
|
||
Salesman1 uint32 `json:"salesman_1"` // 销售员一用户ID
|
||
SalesmanName1 string `json:"salesman_Name1"` // 销售员一用户姓名
|
||
Salesman2 uint32 `json:"salesman_2"` // 销售员二用户ID
|
||
SalesmanName2 string `json:"salesman_Name2"` // 销售员二用户姓名
|
||
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"` // 订单商品数量
|
||
SalesProfit float64 `json:"sales_profit"` // 销售毛利
|
||
StaffProfit float64 `json:"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 uint32 `json:"invoice_code"` // 发票代码
|
||
InvoiceNumber uint32 `json:"invoice_number"` // 发票编码
|
||
RejectedTotalAmount float64 `json:"rejected_total_amount" gorm:"-"` // 订单总退货金额
|
||
RejectedTotalCount uint32 `json:"rejected_total_count" gorm:"-"` // 订单总退货数量
|
||
Commodities []ErpOrderCommodity `json:"commodities" gorm:"-"` // 零售订单商品信息
|
||
Cashiers []ErpOrderCashier `json:"cashiers" gorm:"-"` // 收付款方式
|
||
}
|
||
|
||
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"` // 商品名称
|
||
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"` // 实际零售价
|
||
TotalAmount float64 `json:"total_amount"` // 商品实收金额
|
||
Remark string `json:"remark"` // 备注
|
||
Tel string `json:"tel" gorm:"index"` // 手机号
|
||
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"` // 指导采购价
|
||
}
|
||
|
||
type ErpOrderCashier struct {
|
||
CashierId uint32 `json:"cashier_id"` // 收付款方式id
|
||
Name string `json:"name"` // 收付款方式名称
|
||
Amount float64 `json:"amount"` // 金额
|
||
}
|
||
|
||
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"` // 支付状态
|
||
}
|
||
|
||
type ErpOrderCreateReq struct {
|
||
BillSn string `json:"bill_sn"` // 单据编号
|
||
StoreId uint32 `json:"store_id" binding:"required"` // 门店id
|
||
StoreName string `json:"store_name"` // 门店名称
|
||
Salesman1 uint32 `json:"salesman_1" binding:"required"` // 销售员一
|
||
Salesman2 uint32 `json:"salesman_2"` // 销售员二
|
||
RetailType string `json:"retail_type" binding:"required"` // 销售类型:sale 零售销售; rejected 零售退货
|
||
Tel string `json:"tel"` // 会员手机号
|
||
MemberType string `json:"member_type"` // 会员类型:general 普通; member 会员
|
||
TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价
|
||
TotalAmount float64 `json:"total_amount"` // 订单实收金额
|
||
TotalCount uint32 `json:"total_count"` // 订单商品数量
|
||
VmAmount uint32 `json:"vm_count"` // 使用会员积分
|
||
Cashiers []ErpOrderCashier `json:"cashiers" binding:"required"` // 收付款方式
|
||
ErpOrderCommodities []ErpOrderCommodity `json:"erp_order_commodities" binding:"required"` // 零售订单商品信息
|
||
}
|
||
|
||
type ErpOrderListReq struct {
|
||
BillSn string `json:"bill_sn"` // 单据编号
|
||
RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货
|
||
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"` // 页面条数
|
||
IsExport uint32 `json:"is_export"` // 1-导出
|
||
}
|
||
|
||
type ErpOrderListResp struct {
|
||
List []ErpOrder `json:"list"`
|
||
Total int `json:"total"` // 总条数
|
||
PageIndex int `json:"pageIndex"` // 页码
|
||
PageSize int `json:"pageSize"` // 每页展示条数
|
||
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"` // 销售毛利率:销售毛利/销售/退货金额
|
||
}
|
||
|
||
func (m *ErpOrderListReq) List() (*ErpOrderListResp, error) {
|
||
resp := &ErpOrderListResp{
|
||
PageIndex: m.PageIndex,
|
||
PageSize: m.PageSize,
|
||
}
|
||
page := m.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if m.PageSize == 0 {
|
||
m.PageSize = 10
|
||
}
|
||
qs := orm.Eloquent.Table("erp_order")
|
||
if m.BillSn != "" {
|
||
qs = qs.Where("bill_sn=?", m.BillSn)
|
||
} else {
|
||
if m.RetailType != "" {
|
||
qs = qs.Where("retail_type=?", m.RetailType)
|
||
}
|
||
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("salesman1 = ? or salesman2 = ?", m.Salesman, 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(DateTimeFormat, m.StartTime)
|
||
if err != nil {
|
||
logger.Errorf("err:", err)
|
||
}
|
||
qs = qs.Where("created_at > ?", parse)
|
||
}
|
||
if m.EndTime != "" {
|
||
parse, err := time.Parse(DateTimeFormat, 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
|
||
if m.IsExport == 1 {
|
||
err = qs.Order("id DESC").Find(&orders).Error
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("dailys err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
|
||
//listExport, err := ErpOrderListExport(orders)
|
||
//if err != nil {
|
||
// logger.Error("list export err:", err)
|
||
//}
|
||
//resp.ExportUrl = listExport
|
||
} else {
|
||
resp.Total = int(count)/m.PageSize + 1
|
||
|
||
err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error
|
||
if err != nil && err != RecordNotFound {
|
||
logger.Error("erp commodity list err:", logger.Field("err", err))
|
||
return resp, err
|
||
}
|
||
ErpOrderListSetCashier(orders)
|
||
|
||
resp.List = orders
|
||
|
||
//跟之前保持一致
|
||
resp.Total = int(count)
|
||
resp.PageIndex = page + 1
|
||
resp.PageSize = m.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("订单类型错误")
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
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 NewErpPurchaseSn() string {
|
||
nowTime := time.Now()
|
||
rand.Seed(nowTime.UnixNano())
|
||
max := 1
|
||
for {
|
||
if max > 5 {
|
||
logger.Error("create sn err")
|
||
return ""
|
||
}
|
||
random := rand.Int31n(9999) + 1000
|
||
sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random)
|
||
exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_order WHERE serial_number='%s'", sn))
|
||
if err != nil {
|
||
logger.Error("exist sn err")
|
||
}
|
||
if !exist {
|
||
return sn
|
||
}
|
||
|
||
max++
|
||
}
|
||
}
|
||
|
||
func 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("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].ID] = 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.IsZero() {
|
||
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))
|
||
}
|
||
}
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
// updateErpStockCommodity 更新库存订单表
|
||
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 erp_store_id = ? and state = ? and IMEIType = ",
|
||
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) {
|
||
resp := &ErpOrderStoreManageDataResp{
|
||
PageIndex: req.PageIndex,
|
||
PageSize: req.PageSize,
|
||
}
|
||
page := req.PageIndex - 1
|
||
if page < 0 {
|
||
page = 0
|
||
}
|
||
if req.PageSize == 0 {
|
||
req.PageSize = 10
|
||
}
|
||
var storeManageDataList []StoreManageData
|
||
|
||
// 构建查询条件
|
||
qs := orm.Eloquent.Model(&ErpOrder{})
|
||
if req.StoreId != 0 {
|
||
qs = qs.Where("store_id = ?", req.StoreId)
|
||
}
|
||
if req.StartTime != "" && req.EndTime != "" {
|
||
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 AND maker_time != '0000-00-00 00:00:00'")
|
||
es := qs
|
||
|
||
// 获取总条数
|
||
err := es.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(sales_profit) AS sales_profit, SUM(staff_profit) AS staff_profit, SUM(total_count) AS count").
|
||
Group("date").
|
||
Find(&storeManageDataList).Error
|
||
if err != nil {
|
||
logger.Error("QueryStoreManageData count err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
resp.Total = len(storeManageDataList)
|
||
storeManageDataList = nil
|
||
|
||
if req.IsExport == 1 { //导出excel
|
||
// 查询数据
|
||
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(sales_profit) AS sales_profit, SUM(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
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
filePath, err := StoreManageDataExport(storeManageDataList, storeName)
|
||
if err != nil {
|
||
logger.Error("StoreManageDataExport err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
resp.ExportUrl = filePath
|
||
} else {
|
||
// 查询数据
|
||
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(sales_profit) AS sales_profit, SUM(staff_profit) AS staff_profit, SUM(total_count) AS count").
|
||
Group("date").
|
||
Order("date DESC").
|
||
Offset(page * req.PageSize).
|
||
Limit(req.PageSize).
|
||
Find(&storeManageDataList).Error
|
||
if err != nil {
|
||
logger.Error("QueryStoreManageData err:", logger.Field("err", err))
|
||
return nil, err
|
||
}
|
||
|
||
resp.List = storeManageDataList
|
||
resp.PageIndex = req.PageIndex
|
||
resp.PageSize = req.PageSize
|
||
}
|
||
|
||
return resp, nil
|
||
}
|
||
|
||
// StoreManageDataExport 导出门店经营数据
|
||
func StoreManageDataExport(list []StoreManageData, storeName string) (string, error) {
|
||
file := excelize.NewFile()
|
||
streamWriter, err := file.NewStreamWriter("Sheet1")
|
||
if err != nil {
|
||
fmt.Println(err)
|
||
}
|
||
|
||
url := ExportUrl
|
||
fileName := time.Now().Format(TimeFormat) + storeName + "经营数据" + ".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(list); rowId++ {
|
||
row = []interface{}{
|
||
list[rowId].Date,
|
||
list[rowId].TotalSalesAmount,
|
||
list[rowId].PromotionFee,
|
||
list[rowId].SalesProfit,
|
||
list[rowId].StaffProfit,
|
||
list[rowId].Count,
|
||
}
|
||
|
||
cell, _ := excelize.CoordinatesToCellName(1, nExcelStartRow+2)
|
||
if err := streamWriter.SetRow(cell, row); err != nil {
|
||
fmt.Println(err)
|
||
}
|
||
nExcelStartRow++
|
||
|
||
}
|
||
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
|
||
}
|
||
|
||
// RetailMarginDataExport 导出商品零售毛利汇总数据
|
||
func RetailMarginDataExport(req *ErpOrderRetailMarginResp, storeName string) (string, error) {
|
||
file := excelize.NewFile()
|
||
streamWriter, err := file.NewStreamWriter("Sheet1")
|
||
if err != nil {
|
||
fmt.Println(err)
|
||
}
|
||
|
||
url := ExportUrl
|
||
fileName := time.Now().Format(TimeFormat) + storeName + "商品零售毛利汇总" + ".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{}{
|
||
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) {
|
||
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 req.StoreId != 0 {
|
||
qs.Where("erp_order.store_id = ?", req.StoreId)
|
||
}
|
||
if req.RetailType != "" {
|
||
qs.Where("erp_order.retail_type = ?", req.RetailType)
|
||
}
|
||
if req.ErpCommodityName != "" {
|
||
qs.Where("erp_order_commodity.erp_commodity_name like" + "%" + req.ErpCommodityName + "%")
|
||
}
|
||
if req.ErpCategoryId != 0 {
|
||
qs.Where("erp_order_commodity.erp_category_id = ?", 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())
|
||
}
|
||
}
|
||
|
||
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
|
||
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
|
||
}
|
||
|
||
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.TotalAmount
|
||
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, storeName)
|
||
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.TotalAmount
|
||
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
|
||
}
|