mh_goadmin_server/app/admin/models/erp_order.go
chenlin c1abef7dd5 1.新增接口:查询收款状态;
2.新增接口:查询门店经营数据;
3.新增接口:查询商品零售毛利汇总;
4.修改河马付密钥读取路径;
5.优化零售订单库存更新逻辑;
2023-12-27 19:23:03 +08:00

1419 lines
49 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package models
import (
"encoding/json"
"errors"
"fmt"
"github.com/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
}