mh_server/model/mall.go

1298 lines
39 KiB
Go
Raw Permalink 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 model
import (
"encoding/json"
"errors"
"fmt"
"github.com/codinl/go-logger"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/rs/zerolog/log"
"mh-server/lib/utils"
"net/url"
"sort"
"strconv"
"strings"
"time"
)
const (
SaleStatusUnknown = iota
SaleStatusYes
SaleStatusNo
)
const (
PayTypeUnknown = iota
PayTypeRm // 人民币
PayTypeVm // 积分
)
const (
PayStatusUnknown = iota
PayStatusInit
PayStatusOK
PayStatusFail
)
const (
DeliveryStatusUnknown = iota
DeliveryStatusUnDeliver // 1-待发货
DeliveryStatusDelivered // 2-已发货
DeliveryStatusHarvestGoods // 3-已收货
)
const (
Rmb = 100
)
const (
AccountForDw = 2 // 迪为账户
)
// 商品
// gen:qs
//
//go:generate goqueryset -in mall.go
type Goods struct {
Model
GoodsId uint32 `json:"goods_id" gorm:"unique_index"`
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // ERP商品id
SerialNo string `json:"serial_no" gorm:"unique_index"` // 序列号
CatId uint32 `json:"cat_id" gorm:"index"` // 分类
Name string `json:"name"` // 名称
Title string `json:"title"` // 标题
MainImage string `json:"main_image"` // 主图
Images string `json:"images"` // 图片列表,用,隔开
Detail string `json:"detail" gorm:"type:text;"` // 详情, 富文本
SoldCount uint32 `json:"sold_count"` // 已销售数量
SaleStatus uint32 `json:"sale_status"` // 在售状态 1-在售 2-下架
CatSort uint32 `json:"cat_sort"` // 分类排序
Sort uint32 `json:"sort"` // 商品排序
SpecList string `json:"spec_list" gorm:"type:text;"` // 属性json数据
DiscountList string `json:"discount_list" gorm:"type:text;"` // 折扣
SpecIndex string `json:"spec_index" gorm:"index"` // 1_3
PriceVm uint32 `json:"price_vm"` // 积分价格
PriceRm uint32 `json:"price_rm"` // 人民币价格
PriceOriginal uint32 `json:"price_original"` // 市场价
DeliveryFee uint32 `json:"delivery_fee"` // 邮费
DealType uint32 `json:"deal_type"` // 1-积分兑换 2-购买 3-抵扣
VersionId uint64 `json:"version_id"` // 乐观锁
ShowDiscount int8 `json:"show_discount"` //
GoodsAccountNum uint32 `json:"goods_account_num"` // 收款账户编号
ErpStock uint32 `json:"erp_stock" gorm:"-"` // erp库存
CurrentStoreErpStock uint32 `json:"current_store_erp_stock" gorm:"-"` // 当前门店的erp库存
GoodsCat *GoodsCat `json:"goods_cat" gorm:"-"`
GoodsDiscount *GoodsDiscount `json:"goods_discount" gorm:"-"`
Attributes []GoodsAttribute `json:"attributes" gorm:"-"`
Combo *GoodsAttributeCombo `json:"combo" gorm:"-"`
}
// gen:qs
type GoodsCat struct {
Model
Name string `json:"name"` // 名称
Priority string `json:"priority"` // 分类
State uint32 `json:"state"` // 1-未使用 2-使用
Level uint32 `json:"level"` // 分类层级
Pid uint32 `json:"pid" gorm:"index"`
Sort uint32 `json:"sort"`
SubCats []GoodsCat `json:"sub_cats" gorm:"-"` // 子列表
}
type GoodsDiscount struct {
Gold uint32 `json:"gold"` // 黄金折扣
Platinum uint32 `json:"platinum"` // 白金折扣
BlackGold uint32 `json:"black_gold"` // 黑金折扣
}
// gen:qs
type GoodsAttribute struct {
Model
GoodsId uint32 `json:"goods_id" gorm:"index"`
SerialNo string `json:"serial_no" gorm:"index"` // 序列号
CatId uint32 `json:"cat_id" gorm:"index"` // 分类
Name string `json:"name"` // 名称
Title string `json:"title"` // 标题
MainImage string `json:"main_image"` // 主图
Stock uint32 `json:"stock"` // 库存
SoldCount uint32 `json:"sold_count"` // 已销售数量
PriceRm uint32 `json:"price_rm"` // 人民币价格
PriceOriginal uint32 `json:"price_original"` // 市场价
SpecValueList string `json:"spec_value_list" gorm:"type:text;"` // 属性json数据
SpecValueIndex string `json:"spec_value_index" gorm:"index"` // 1_3_5
DealType uint32 `json:"deal_type"` // 1-积分兑换 2-购买 3-抵扣
SpecValues []*SpecValue `json:"spec_values" gorm:"-"`
Goods *Goods `json:"goods" gorm:"-"`
Combos []GoodsAttributeCombo `json:"combos" gorm:"-"`
Combo *GoodsAttributeCombo `json:"combo" gorm:"-"`
// goods_attribute
}
// gen:qs
type GoodsAttributeCombo struct {
Model
GoodsAttributeId uint32 `json:"goods_attribute_id" gorm:"index"`
GoodsId uint32 `json:"goods_id" gorm:"index"`
SerialNo string `json:"serial_no" gorm:"index"` // 序列号
CatId uint32 `json:"cat_id" gorm:"index"` // 分类
Name string `json:"name"` // 名称
Title string `json:"title"` // 标题
MainImage string `json:"main_image"` // 主图
ComboName string `json:"combo_name"` // 名称
PriceVm uint32 `json:"price_vm"` // 积分价格
PriceRm uint32 `json:"price_rm"` // 人民币价格
}
//type GoodsSpec struct {
// Model
//}
// gen:qs
type Spec struct {
Model
DisplayName string `json:"display_name" gorm:"unique_index"`
Name string `json:"name"`
State uint32 `json:"state"` // 1-未使用 2-使用
Sort uint32 `json:"sort"`
Values []SpecValue `json:"values" gorm:"-"`
}
// gen:qs
type SpecValue struct {
Model
SpecId uint32 `json:"spec_id" gorm:"index"`
SpecDisplayName string `json:"spec_display_name"`
SpecName string `json:"spec_name"`
DisplayValue string `json:"display_value" gorm:"unique_index"`
State uint32 `json:"state"` // 1-未使用 2-使用
Value string `json:"value"`
SpecSort uint32 `json:"spec_sort"`
Sort uint32 `json:"sort"`
}
func CreateGoodsSerialNo() string {
for {
serialNo := utils.GenSerialNo()
if count, err := NewGoodsQuerySet(DB).SerialNoEq(serialNo).Count(); err == nil && count > 0 {
continue
}
return serialNo
}
}
func CreateGoodsId() uint32 {
for {
orderId := utils.GenUid()
if count, err := NewGoodsQuerySet(DB).GoodsIdEq(orderId).Count(); err == nil && count > 0 {
continue
}
return orderId
}
}
type GoodsListReq struct {
CatId uint32 `json:"cat_id"`
NearestStoreId uint32 `json:"nearest_store_id"` // 用户选择的门店ID
PageIdx int `json:"page_idx"`
PageSize int `json:"page_size"`
}
type GoodsListResp struct {
List []Goods `json:"list"`
CurPage int `json:"cur_page"`
TotalPage int `json:"total_page"`
}
func (m *GoodsListReq) GoodsList() ([]Goods, int, error) {
page := m.PageIdx - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
fmt.Println("CatId:", m.CatId)
var goodsList []Goods
qs := NewGoodsQuerySet(DB).SaleStatusEq(1)
if m.CatId != 0 {
//cat, err := GetGoodsCat(m.CatId)
//if err != nil {
// log.Error().Msgf("cat err:%#v", err)
// return nil, 0, err
//}
var goodsCats []GoodsCat
err := NewGoodsCatQuerySet(DB).PidEq(m.CatId).All(&goodsCats)
if err != nil {
log.Error().Msgf("goods cat err:%#v", err)
return nil, 0, err
}
ids := []uint32{m.CatId}
if len(goodsCats) > 0 {
for i, _ := range goodsCats {
ids = append(ids, goodsCats[i].ID)
}
}
qs = qs.CatIdIn(ids...)
}
count, err := qs.Count()
if err != nil {
logger.Error("err:", err)
return nil, 0, err
}
totalPage := count/m.PageSize + 1
err = qs.OrderDescByCatSort().OrderDescBySort().Offset(page * m.PageSize).Limit(m.PageSize).All(&goodsList)
if err != nil {
logger.Error("err:", err)
return nil, 0, err
}
// 处理ERP库存批量查询
erpIDs := make([]uint32, 0)
for _, g := range goodsList {
if g.ErpCommodityId != 0 {
erpIDs = append(erpIDs, g.ErpCommodityId)
}
}
type ErpStockData struct {
ErpCommodityId uint32
Stock uint32
}
if len(erpIDs) > 0 {
var stocks []ErpStockData
db := DB.Table("erp_stock_commodity").
Select("erp_commodity_id, SUM(count) AS stock").
Where("state = ?", 1).
Group("erp_commodity_id")
// 根据数量区分使用 = 或 IN
if len(erpIDs) == 1 {
db = db.Where("erp_commodity_id = ?", erpIDs[0])
} else {
db = db.Where("erp_commodity_id IN ?", erpIDs)
}
if err := db.Find(&stocks).Error; err != nil {
logger.Error("err:", err)
return nil, 0, err
}
// 构建映射
stockMap := make(map[uint32]uint32, len(stocks))
for _, s := range stocks {
stockMap[s.ErpCommodityId] = s.Stock
}
// 给商品赋值库存
for i := range goodsList {
if goodsList[i].ErpCommodityId != 0 {
goodsList[i].ErpStock = stockMap[goodsList[i].ErpCommodityId]
}
}
}
// 当前门店库存
if m.NearestStoreId != 0 {
var storeStocks []ErpStockData
dbStore := DB.Table("erp_stock_commodity").
Select("erp_commodity_id, SUM(count) AS stock").
Where("state = ? AND store_id = ?", 1, m.NearestStoreId).
Group("erp_commodity_id")
if len(erpIDs) == 1 {
dbStore = dbStore.Where("erp_commodity_id = ?", erpIDs[0])
} else {
dbStore = dbStore.Where("erp_commodity_id IN ?", erpIDs)
}
if err := dbStore.Find(&storeStocks).Error; err != nil {
logger.Error("err:", err)
return nil, 0, err
}
storeStockMap := make(map[uint32]uint32, len(storeStocks))
for _, s := range storeStocks {
storeStockMap[s.ErpCommodityId] = s.Stock
}
for i := range goodsList {
if goodsList[i].ErpCommodityId != 0 {
goodsList[i].CurrentStoreErpStock = storeStockMap[goodsList[i].ErpCommodityId]
}
}
}
return goodsList, totalPage, nil
}
type GoodsDetailReq struct {
GoodsId uint32 `json:"goods_id"`
}
func (m *GoodsDetailReq) GoodsDetail() (*Goods, error) {
var goods Goods
err := NewGoodsQuerySet(DB).GoodsIdEq(m.GoodsId).One(&goods)
if err != nil {
logger.Error("err:", err)
return nil, err
}
var goodsAttributes []GoodsAttribute
err = DB.Table("goods_attribute").
Where("goods_id=?", m.GoodsId).
Order("sort DESC").
Find(&goodsAttributes).Error
if err != nil {
log.Error().Msgf("goods attribute err:%#v", err)
return &goods, err
}
if goods.DiscountList != "" {
discount := new(GoodsDiscount)
err = json.Unmarshal([]byte(goods.DiscountList), discount)
if err != nil {
log.Error().Msgf("goods discount err:%#v", err)
return &goods, err
}
goods.GoodsDiscount = discount
}
cat, err := GetGoodsCat(goods.CatId)
if err != nil {
log.Error().Msgf("goods cat err:%#v", err)
}
goods.GoodsCat = cat
GoodsAttributeListSetSpecValues(goodsAttributes)
GoodsAttributeListSetCombos(goodsAttributes)
goods.Attributes = goodsAttributes
return &goods, nil
}
// 商品分类
// gen:qs
type GoodsCategory struct {
Model
CatId uint32 `json:"cat_id"`
ParentCatId uint32 `json:"parent_cat_id"`
Name string `json:"name"`
Sort uint32 `json:"sort"` // 排序
Level uint32 `json:"level"`
State uint32 `json:"state"`
}
const (
GoodsOrderStateUnPay = "un_pay" // 待付款
GoodsOrderStateOnDeliver = "on_deliver" // 待发货
GoodsOrderStateDelivered = "delivered" // 已发货
GoodsOrderStateReceived = "received" // 已收货
GoodsOrderStateCancel = "cancel" // 已取消
GoodsOrderStateOnRefund = "on_refund" // 退货中
GoodsOrderStateRefunded = "refunded" // 已退货
GoodsOrderStateRefundedCancel = "refunded_cancel" // 退货取消
)
// 商品订单
// gen:qs
type GoodsOrder struct {
Model
OrderId uint32 `json:"order_id" gorm:"unique_index"` // 订单 id
NearestStoreId uint32 `json:"nearest_store_id"` // 定位最近的门店id
NearestStoreName string `json:"nearest_store_name"` // 定位最近的门店名称
SerialNo string `json:"serial_no" gorm:"unique_index"` // 序列号
Uid uint32 `json:"uid" gorm:"index"` // 用户id
Amount uint32 `json:"amount"` // 订单金额
Quantity uint32 `json:"quantity"` // 购买商品的数量
TotalDiscount float64 `json:"total_discount"` // 订单总优惠
PayType uint32 `json:"pay_type"` // 支付方式 1-rm 2-vm
PayTime time.Time `json:"pay_time"` // 支付时间
PayStatus uint32 `json:"pay_status"` // 支付状态 1-待支付 2-已支付 3-失败
State string `json:"state"` //
AddressId uint32 `json:"address_id"` // 收货地址
DeliveryExtraInfo string `json:"delivery_extra_info"` // 物流备注
DeliveryFee uint32 `json:"delivery_fee"` // 物流费用
DeliveryTrackingNo string `json:"delivery_tracking_no"` // 物流单号
DeliveryCompany string `json:"delivery_company"` // 物流公司
DeliveryCompanyNo string `json:"delivery_company_no"` // 物流公司编号
DeliveryStatus uint32 `json:"delivery_status"` // 物流状态 1-待发货 2-已发货 3-已收货
Rm uint32 `json:"rm"` // 人民币
Vm uint32 `json:"vm"` // 积分
DeliverStoreId uint32 `json:"deliver_store_id"` // 发货门店
DeliverTime time.Time `json:"deliver_time"` // 发货时间
RefundExpressCompany string `json:"refund_express_company"` // 退货物流公司
RefundExpressCompanyNo string `json:"refund_express_company_no"` // 退货物流公司编号
RefundExpressNo string `json:"refund_express_no"` // 退货物流单号
RefundReason string `json:"refund_reason" gorm:"type:text;"` // 退货原因
ReceivedTime time.Time `json:"received_time"` // 签收时间
VersionId uint64 `json:"version_id"` // 乐观锁
GoodsOrderCommodities []GoodsOrderCommodity `json:"goods_order_commodities" gorm:"-"` // 商城订单商品信息
DeliverStore *Store `json:"deliver_store" gorm:"-"`
UserAddress *UserAddress `json:"user_address" gorm:"-"`
// 以下字段是冗余,暂时用不上
GoodsId uint32 `json:"goods_id" gorm:"index"` // 商品id
Discount uint32 `json:"discount"` // 折扣
GoodsAttributeId uint32 `json:"goods_attribute_id"` //
GoodsAttributeComboId uint32 `json:"goods_attribute_combo_id"` //
CouponCode string `json:"coupon_code"` //
CouponName string `json:"coupon_name"` // 优惠券名称
CouponDiscount uint32 `json:"coupon_discount"` // 优惠券抵扣
}
// 商城订单商品表
// gen:qs
type GoodsOrderCommodity struct {
Model
GoodsOrderId uint32 `json:"goods_order_id" gorm:"index"` // 商品订单id
GoodsId uint32 `json:"goods_id"` // 商品id
ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // ERP商品id
Quantity uint32 `json:"quantity"` // 销售数量
PriceRm uint32 `json:"price_rm"` // 价格:人民币
PriceVm uint32 `json:"price_vm"` // 价格:积分
Discount uint32 `json:"discount"` // 折扣
GoodsAttributeId uint32 `json:"goods_attribute_id"` //
GoodsAttributeComboId uint32 `json:"goods_attribute_combo_id"` //
CouponID uint32 `json:"coupon_id"` // 优惠券ID
CouponCode string `json:"coupon_code"` // 优惠券券码
CouponName string `json:"coupon_name"` // 优惠券名称
CouponDiscount uint32 `json:"coupon_discount"` // 优惠券抵扣
Goods *Goods `json:"goods" gorm:"-"`
GoodsAttribute *GoodsAttribute `json:"goods_attribute" gorm:"-"`
}
func CreateGoodsOrderSerialNo() string {
for {
serialNo := utils.GenSerialNo()
if count, err := NewGoodsOrderQuerySet(DB).SerialNoEq(serialNo).Count(); err == nil && count > 0 {
continue
}
return serialNo
}
}
func CreateGoodsOrderId() uint32 {
for {
orderId := utils.GenUid()
if count, err := NewGoodsOrderQuerySet(DB).OrderIdEq(orderId).Count(); err == nil && count > 0 {
continue
}
return orderId
}
}
type GoodsOrderListReq struct {
PageIdx int `json:"page_idx"`
PageSize int `json:"page_size"`
State string `json:"state"`
//DeliveryStatus uint32 `json:"delivery_status"` // 物流状态 1-待发货 2-已发货 3-已收货
}
func (m *GoodsOrderListReq) OrderList(uid uint32) ([]GoodsOrder, int, error) {
page := m.PageIdx - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
var list []GoodsOrder
qs := NewGoodsOrderQuerySet(DB).PayStatusEq(PayStatusOK).UidEq(uid)
//if uid != 0 {
// qs = qs.UidEq(uid)
//}
//if m.DeliveryStatus != 0 {
// qs = qs.DeliveryStatusEq(m.DeliveryStatus)
//}
if m.State != "" {
qs = qs.StateEq(m.State)
}
count, err := qs.Count()
if err != nil {
logger.Error("err:", err)
return nil, 0, err
}
totalPage := count/m.PageSize + 1
// 查询订单
err = qs.OrderDescByID().Offset(page * m.PageSize).Limit(m.PageSize).All(&list)
if err != nil {
logger.Error("err:", err)
return nil, 0, err
}
// 关联查询订单商品
if err = SetGoodsOrderCommoditiesWithAddress(list); err != nil {
logger.Error("set commodities err:", err)
return nil, 0, err
}
return list, totalPage, nil
}
func SetGoodsOrderCommoditiesWithAddress(orders []GoodsOrder) error {
if len(orders) == 0 {
return nil
}
// 收集订单ID、收货地址ID
orderIds := make([]uint32, 0, len(orders))
addressIds := make([]uint32, 0)
for _, o := range orders {
orderIds = append(orderIds, o.OrderId)
if o.AddressId > 0 {
addressIds = append(addressIds, o.AddressId)
}
}
// 查出所有订单商品
var commodities []GoodsOrderCommodity
if err := DB.Model(&GoodsOrderCommodity{}).
Where("goods_order_id IN (?)", orderIds).
Find(&commodities).Error; err != nil {
return err
}
// 批量查商品、属性
goodsIds := make([]uint32, 0)
attributeIds := make([]uint32, 0)
for _, c := range commodities {
if c.GoodsId > 0 {
goodsIds = append(goodsIds, c.GoodsId)
}
if c.GoodsAttributeId > 0 {
attributeIds = append(attributeIds, c.GoodsAttributeId)
}
}
goodsMap := GetGoodsMapByIds(goodsIds)
attributeMap, err := GetGoodsAttributeMap(attributeIds)
if err != nil {
log.Error().Msgf("attribute map err:%#v", err)
return err
}
// 填充商品和属性
for i := range commodities {
if g, ok := goodsMap[commodities[i].GoodsId]; ok {
commodities[i].Goods = &g
}
if a, ok := attributeMap[commodities[i].GoodsAttributeId]; ok {
commodities[i].GoodsAttribute = &a
}
}
// 按订单分组
orderMap := make(map[uint32][]GoodsOrderCommodity)
for _, c := range commodities {
orderMap[c.GoodsOrderId] = append(orderMap[c.GoodsOrderId], c)
}
// 批量查收货地址
addressMap := make(map[uint32]UserAddress)
if len(addressIds) > 0 {
var addresses []UserAddress
if err := DB.Unscoped().
Model(&UserAddress{}).
Where("id IN (?)", addressIds).
Find(&addresses).Error; err != nil {
return err
}
for _, addr := range addresses {
addressMap[addr.ID] = addr
}
}
// 塞回订单
for i := range orders {
if list, ok := orderMap[orders[i].OrderId]; ok {
orders[i].GoodsOrderCommodities = list
}
if addr, ok := addressMap[orders[i].AddressId]; ok {
orders[i].UserAddress = &addr
}
}
return nil
}
type GoodsOrderDetailReq struct {
OrderId uint32 `json:"order_id"`
}
func (m *GoodsOrderDetailReq) OrderDetail(uid uint32) (*GoodsOrder, error) {
var order GoodsOrder
qs := NewGoodsOrderQuerySet(DB).OrderIdEq(m.OrderId).UidEq(uid)
// 查订单主表
err := qs.One(&order)
if err != nil && err != RecordNotFound {
logger.Error("err:", err)
return nil, err
}
// 用统一的函数,填充商品和收货地址
if err := SetGoodsOrderCommoditiesWithAddress([]GoodsOrder{order}); err != nil {
logger.Error("set commodities/address err:", err)
return nil, err
}
// 每个商品做附加处理
for i := range order.GoodsOrderCommodities {
commodity := &order.GoodsOrderCommodities[i]
if commodity.Goods != nil && commodity.Goods.DiscountList != "" {
discount := new(GoodsDiscount)
err = json.Unmarshal([]byte(commodity.Goods.DiscountList), discount)
if err != nil {
log.Error().Msgf("goods discount err:%#v", err)
return nil, err
}
commodity.Goods.GoodsDiscount = discount
}
// 属性规格 & 组合
if commodity.GoodsAttribute != nil {
attributes := []GoodsAttribute{*commodity.GoodsAttribute}
GoodsAttributeListSetSpecValues(attributes)
combo, err := GetCombo(commodity.GoodsAttributeComboId)
if err != nil {
log.Error().Msgf("goods attribute combo err:%#v", err)
return nil, err
}
if len(attributes) > 0 {
attributes[0].Combo = combo
}
commodity.Goods.Attributes = attributes
}
}
// 发货门店
store, err := GetStore(order.DeliverStoreId)
if err != nil {
logger.Error("store err:", err)
}
order.DeliverStore = store
return &order, nil
}
func OrderDeductionUserVm(uid uint32, userVmAmount, vm int, gdb *gorm.DB) error {
sql := fmt.Sprintf("UPDATE user_vm SET vm = vm+? WHERE uid=? ")
err := gdb.Exec(sql, vm, uid).Error
if err != nil {
logger.Error("err:", err)
return err
}
vmRecord := &UserVmRecord{
Uid: uid,
BeforeVm: uint32(userVmAmount),
AfterVm: uint32(int(userVmAmount) + vm),
Alter: vm,
Event: "exchange_goods",
Describe: "兑换礼品",
}
err = gdb.Create(vmRecord).Error
if err != nil {
logger.Error("err:", err)
return err
}
return nil
}
func OrderUpdateGoodsStock(attributeId, count uint32, gdb *gorm.DB) error {
sql := fmt.Sprintf("UPDATE goods_attribute SET stock=stock-%d,sold_count=sold_count+%d WHERE id=%d ",
count, count, attributeId)
err := gdb.Exec(sql).Error
if err != nil {
logger.Error("err:", err)
return err
}
return nil
}
func GetGoodsMapByIds(ids []uint32) map[uint32]Goods {
goodsMap := make(map[uint32]Goods, 0)
if len(ids) == 0 {
return goodsMap
}
var goodsList []Goods
err := NewGoodsQuerySet(DB).GoodsIdIn(ids...).All(&goodsList)
if err != nil {
logger.Error("err:", err)
return goodsMap
}
for i, _ := range goodsList {
goodsMap[goodsList[i].GoodsId] = goodsList[i]
}
return goodsMap
}
func GetGoodsAttributeMap(ids []uint32) (map[uint32]GoodsAttribute, error) {
attributeMap := make(map[uint32]GoodsAttribute, 0)
if len(ids) == 0 {
return attributeMap, nil
}
var attributes []GoodsAttribute
err := NewGoodsAttributeQuerySet(DB).IDIn(ids...).All(&attributes)
if err != nil {
log.Error().Msgf("goods attribute err:%#v", err)
return attributeMap, err
}
for i, _ := range attributes {
attributeMap[attributes[i].ID] = attributes[i]
}
return attributeMap, nil
}
type MallUserVmRecordReq struct {
PageIdx int `json:"page_idx"`
PageSize int `json:"page_size"`
VmType uint32 `json:"vm_type"` // 默认0-正常查询1-查询7天内即将过期积分
//Uid uint32 `json:"uid"`
}
type MallUserVmRecordResp struct {
List []UserVmRecord `json:"list"`
CurPage int `json:"cur_page"`
TotalPage int `json:"total_page"`
}
func (m *MallUserVmRecordReq) UserVmRecordList(uid uint32) ([]UserVmRecord, int, error) {
page := m.PageIdx - 1
if page < 0 {
page = 0
}
if m.PageSize == 0 {
m.PageSize = 10
}
var list []UserVmRecord
qs := NewUserVmRecordQuerySet(DB)
if uid != 0 {
qs = qs.UidEq(uid)
}
if m.VmType != 0 {
now := time.Now()
year, month, day := now.Date()
startTime := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
endTime := time.Date(year, month, day, 23, 59, 59, 0, time.UTC).AddDate(0, 0, 7)
qs = qs.ExpiryDateAtGte(startTime)
qs = qs.ExpiryDateLte(endTime)
qs = qs.AlterGt(0)
qs = qs.AlterNeUsedVm()
}
count, err := qs.Count()
if err != nil {
logger.Error("err:", err)
return nil, 0, err
}
totalPage := count/m.PageSize + 1
err = qs.OrderDescByID().Offset(page * m.PageSize).Limit(m.PageSize).All(&list)
if err != nil && err != RecordNotFound {
logger.Error("err:", err)
return nil, 0, err
}
for i, _ := range list {
list[i].ExpiryVm = list[i].Alter - list[i].UsedVm
}
return list, totalPage, nil
}
type MallGoodsOrderConfirmReceiptReq struct {
OrderId uint32 `json:"order_id"`
}
func (m *MallGoodsOrderConfirmReceiptReq) MallGoodsOrderConfirmReceipt(uid uint32) error {
_, err := NewGoodsOrderQuerySet(DB).OrderIdEq(m.OrderId).UidEq(uid).GetUpdater().
SetState(GoodsOrderStateReceived).UpdateNum()
if err != nil {
logger.Error("err:", err)
return err
}
return nil
}
type MallGoodsSpecReq struct {
GoodsId uint32 `json:"goods_id"` // 商品id
SpecValueIndex string `json:"spec_value_index"` // 1,3,5
GoodsAttribute *GoodsAttribute
}
func (r *MallGoodsSpecReq) Spec() error {
//GoodsAttribute{}
indexSort, err := IndexSortString(r.SpecValueIndex)
if err != nil {
log.Error().Msgf("index sort:%#v", err)
return err
}
r.SpecValueIndex = indexSort
err = NewGoodsAttributeQuerySet(DB).GoodsIdEq(r.GoodsId).SpecValueIndexEq(r.SpecValueIndex).One(r.GoodsAttribute)
if err != nil && err != RecordNotFound {
log.Error().Msgf("goods attribute err:%#v", err)
return err
}
if err == RecordNotFound {
log.Error().Msg("goods attribute not found")
return errors.New("not_found")
}
var combos []GoodsAttributeCombo
err = NewGoodsAttributeComboQuerySet(DB).GoodsAttributeIdEq(r.GoodsAttribute.ID).All(&combos)
if err != nil {
log.Error().Msgf("goods attribute combo err:%#v", err)
return err
}
return nil
}
func IndexSortString(n string) (string, error) {
numStrings := strings.Split(n, ",")
nums := make([]int, 0, len(numStrings))
for i, _ := range numStrings {
num, err := strconv.Atoi(numStrings[i])
if err != nil {
logger.Error("num err:", err)
return "", err
}
nums = append(nums, num)
}
ns := ""
sort.Ints(nums)
for i, _ := range nums {
ns += fmt.Sprintf("%d,", nums[i])
}
return ns[:len(ns)-1], nil
}
func GetGoods(id uint32) (Goods, error) {
var goods Goods
err := NewGoodsQuerySet(DB).GoodsIdEq(id).One(&goods)
if err != nil {
log.Error().Msgf("get goods err:%#v", err)
return goods, err
}
return goods, err
}
func GetGoodsCat(id uint32) (*GoodsCat, error) {
var cat GoodsCat
err := DB.Table("goods_cat").Where("id=?", id).Find(&cat).Error
if err != nil {
log.Error().Msgf("goods cat err:%#v", err)
return &cat, err
}
if cat.Pid != 0 {
var pCat GoodsCat
err := DB.Table("goods_cat").Where("id=?", cat.Pid).Find(&pCat).Error
if err != nil {
log.Error().Msgf("goods cat err:%#v", err)
return &cat, err
}
pCat.SubCats = []GoodsCat{cat}
return &pCat, nil
}
return &cat, nil
}
func (g *Goods) SetDiscount() error {
discount := new(GoodsDiscount)
err := json.Unmarshal([]byte(g.DiscountList), discount)
if err != nil {
log.Error().Msgf("set goods discount:%#v", err)
return err
}
g.GoodsDiscount = discount
return nil
}
func (g *Goods) GetUserDiscount(u *User) (uint32, error) {
if g.GoodsDiscount == nil {
err := g.SetDiscount()
if err != nil {
log.Error().Msgf("set discount err:%#v", err)
return 100, err
}
}
switch u.MemberLevel {
case MemberLevelGold:
return g.GoodsDiscount.Gold, nil
case MemberLevelPlatinum:
return g.GoodsDiscount.Platinum, nil
case MemberLevelBlackGold:
return g.GoodsDiscount.BlackGold, nil
}
//return 100, errors.New("member level err")
return 100, nil
}
func GoodsAttributeListSetSpecValues(attributes []GoodsAttribute) {
for i, _ := range attributes {
err := json.Unmarshal([]byte(attributes[i].SpecValueList), &attributes[i].SpecValues)
if err != nil {
log.Error().Msgf("spec value err:%#v", err)
continue
}
}
}
func GoodsAttributeListSetCombos(attributes []GoodsAttribute) {
ids := make([]uint32, 0)
for i, _ := range attributes {
ids = append(ids, attributes[i].ID)
}
comboMap := GetGoodsAttributeComboMap(ids)
for i, _ := range attributes {
v, ok := comboMap[attributes[i].ID]
if ok {
attributes[i].Combos = v
}
}
}
func GetGoodsAttributeComboMap(attributeIds []uint32) map[uint32][]GoodsAttributeCombo {
attributeMap := make(map[uint32][]GoodsAttributeCombo, 0)
if len(attributeIds) == 0 {
return attributeMap
}
var combos []GoodsAttributeCombo
err := DB.Table("goods_attribute_combo").Where("goods_attribute_id in (?)", attributeIds).
Find(&combos).Error
if err != nil {
log.Error().Msgf("goods attribute combo err:%#v", err)
return attributeMap
}
for i, _ := range combos {
attributeMap[combos[i].GoodsAttributeId] =
append(attributeMap[combos[i].GoodsAttributeId], combos[i])
}
return attributeMap
}
func GetCombo(id uint32) (*GoodsAttributeCombo, error) {
var combo GoodsAttributeCombo
err := NewGoodsAttributeComboQuerySet(DB).IDEq(id).One(&combo)
if err != nil {
log.Error().Msgf("goods attribute combo err:%#v", err)
return &combo, err
}
return &combo, nil
}
func GetStore(id uint32) (*Store, error) {
var store Store
err := NewStoreQuerySet(DB).IDEq(id).One(&store)
if err != nil {
log.Error().Msgf("store err:%#v", err)
return nil, err
}
return &store, nil
}
// 发货
const (
DeliverTaskStateOnDeliver = "on_deliver" // 待发货
DeliverTaskStateDelivered = "delivered" // 已发货
DeliverTaskStateCancel = "cancel" // 已取消
DeliverTaskStateComplete = "complete" // 已完成
)
// gen:qs
type DeliverTask struct {
Model
Uid uint32 `json:"uid" gorm:"index"`
UserAddressId uint32 `json:"user_address_id" gorm:"index"` // 用户地址
State string `json:"state"` // 状态
OrderType uint32 `json:"order_type"` // 1-借卡 2-商城购买 3-收回卡
StoreId uint32 `json:"store_id"` //
DeliverTime time.Time `json:"deliver_time"` // 发货时间
DeliverStoreId uint32 `json:"deliver_store_id" gorm:"index"` // 发货门店
// deliver_task
}
// gen:qs
type DeliverTaskSub struct {
Model
Uid uint32 `json:"uid"`
DeliverTaskId uint32 `json:"deliver_task_id" gorm:"index"`
UserAddressId uint32 `json:"user_address_id" gorm:"index"` // 用户地址
State string `json:"state"` // 状态
OrderType uint32 `json:"order_type"` // 1-借卡 2-商城购买 3-收回卡
OrderId uint32 `json:"order_id" gorm:"index"` // 订单id
StoreId uint32 `json:"store_id"` //
GoodsOrder *GoodsOrder `json:"goods_order" gorm:"-"`
Order *Order `json:"order" gorm:"-"`
ShareCardRetrieve *ShareCardRetrieve `json:"share_card_retrieve" gorm:"-"`
// deliver_task_sub
}
func (m *DeliverTaskSub) Add() error {
//exist, err := QueryRecordExist(
// fmt.Sprintf("SELECT * FROM deliver_task WHERE user_address_id = %d AND state='%s'",
// m.UserAddressId, DeliverTaskStateOnDeliver))
//if err != nil {
// log.Error().Msgf("deliver_task exist err:%#v", err)
// return err
//}
//var deliver DeliverTask
//if exist {
// err = NewDeliverTaskQuerySet(DB).UserAddressIdEq(m.UserAddressId).
// StateEq(DeliverTaskStateOnDeliver).One(&deliver)
// if err != nil {
// log.Error().Msgf("deliver err:%#v", err)
// return err
// }
// m.DeliverTaskId = deliver.ID
// m.State = DeliverTaskStateOnDeliver
//
// err = DB.Create(m).Error
// if err != nil {
// log.Error().Msgf("create deliver task sub err:%#v", err)
// return err
// }
// return nil
//}
//var deliver DeliverTask
//err := NewDeliverTaskQuerySet(DB).UserAddressIdEq(m.UserAddressId).
// StateEq(DeliverTaskStateOnDeliver).OrderTypeEq(1).One(&deliver)
//if err != nil && err != RecordNotFound {
// log.Error().Msgf("deliver err:%#v", err)
// return err
//}
//
//if err == RecordNotFound || (deliver.StoreId != 0 && deliver.StoreId != m.StoreId) {
//
// begin := DB.Begin()
// deliver = DeliverTask{
// Uid: m.Uid,
// UserAddressId: m.UserAddressId,
// State: DeliverTaskStateOnDeliver,
// StoreId: m.StoreId,
// }
// err = begin.Create(&deliver).Error
// if err != nil {
// begin.Rollback()
// log.Error().Msgf("create deliver task err:%#v", err)
// return err
// }
//
// m.DeliverTaskId = deliver.ID
// m.State = DeliverTaskStateOnDeliver
// err = begin.Create(m).Error
// if err != nil {
// begin.Rollback()
// log.Error().Msgf("create deliver task sub err:%#v", err)
// return err
// }
// err = begin.Commit().Error
// if err != nil {
// begin.Rollback()
// log.Error().Msgf("commit deliver task sub err:%#v", err)
// return err
// }
// return nil
//}
//
//m.DeliverTaskId = deliver.ID
//m.State = DeliverTaskStateOnDeliver
//
//err = DB.Create(m).Error
//if err != nil {
// log.Error().Msgf("create deliver task sub err:%#v", err)
// return err
//}
//if deliver.StoreId == 0 {
// err = NewDeliverTaskQuerySet(DB).IDEq(deliver.ID).GetUpdater().SetStoreId(m.StoreId).Update()
// if err != nil {
// logger.Error("deliver task err:", err)
// }
//}
var deliver DeliverTask
err := NewDeliverTaskQuerySet(DB).UserAddressIdEq(m.UserAddressId).
StateEq(DeliverTaskStateOnDeliver).OrderTypeEq(m.OrderType).StoreIdEq(m.StoreId).One(&deliver)
if err != nil && err != RecordNotFound {
log.Error().Msgf("deliver err:%#v", err)
return err
}
if err == RecordNotFound {
begin := DB.Begin()
deliver = DeliverTask{
Uid: m.Uid,
UserAddressId: m.UserAddressId,
State: DeliverTaskStateOnDeliver,
StoreId: m.StoreId,
OrderType: m.OrderType,
}
err = begin.Create(&deliver).Error
if err != nil {
begin.Rollback()
log.Error().Msgf("create deliver task err:%#v", err)
return err
}
m.DeliverTaskId = deliver.ID
m.State = DeliverTaskStateOnDeliver
//m.OrderType = deliver.OrderType
err = begin.Create(m).Error
if err != nil {
begin.Rollback()
log.Error().Msgf("create deliver task sub err:%#v", err)
return err
}
err = begin.Commit().Error
if err != nil {
begin.Rollback()
log.Error().Msgf("commit deliver task sub err:%#v", err)
return err
}
return nil
}
m.DeliverTaskId = deliver.ID
m.State = DeliverTaskStateOnDeliver
err = DB.Create(m).Error
if err != nil {
log.Error().Msgf("create deliver task sub err:%#v", err)
return err
}
//if deliver.StoreId == 0 {
// err = NewDeliverTaskQuerySet(DB).IDEq(deliver.ID).GetUpdater().SetStoreId(m.StoreId).Update()
// if err != nil {
// logger.Error("deliver task err:", err)
// }
//}
return nil
}
func UpdateDeliverTaskSubStateCancel(orderId uint32) {
var sub DeliverTaskSub
err := DB.Table("deliver_task_sub").Where("order_id=?", orderId).Find(&sub).Error
if err != nil {
log.Error().Msgf("deliver task sub err:%#v", err)
return
}
//begin := DB.Begin()
err = DB.Table("deliver_task_sub").Where("order_id=?", orderId).
Update("state", DeliverTaskStateCancel).Error
if err != nil {
//begin.Rollback()
log.Error().Msgf("deliver task sub err:%#v", err)
return
}
exist, err := QueryRecordExist(
fmt.Sprintf("SELECT * FROM deliver_task_sub WHERE deliver_task_id=%d AND state='%s'",
sub.DeliverTaskId, DeliverTaskStateOnDeliver))
if err != nil {
//begin.Rollback()
logger.Error("deliver task sub exist err:", err)
return
}
if !exist {
err := DB.Table("deliver_task").Where("id=?", sub.DeliverTaskId).
Update("state", DeliverTaskStateCancel).Error
if err != nil {
//begin.Rollback()
log.Error().Msgf("deliver task sub err:%#v", err)
return
}
}
//err = begin.Commit().Error
//if err != nil {
// logger.Error("commit err:", err)
//}
}
func ParaToSubstance(c *gin.Context, sign string) (string, error) {
urlString := c.Request.URL.String()
urlPara, err := url.QueryUnescape(urlString)
if err != nil {
return "", errors.New("url query unescape err")
}
if !strings.Contains(urlPara, "/api/v1/wxpay/notice?") {
return "", errors.New("url err")
}
para := strings.Replace(urlPara, "/api/v1/wxpay/notice?", "", -1)
//fmt.Println("para--", para)
conspire := strings.Split(para, "&")
signConspire := make([]string, 0, len(conspire))
for i, _ := range conspire {
if !strings.Contains(conspire[i], "sign=") {
//fmt.Println("conspire---------", conspire[i])
signConspire = append(signConspire, conspire[i])
}
}
sort.Strings(signConspire)
//signDataJson2, _ := json.MarshalIndent(&signData, "", " ")
//fmt.Println("signDataJson2", string(signDataJson2))
signStr := strings.Join(signConspire, "&")
//signStr = signStr + "&key=" + payKey
logger.Info("签字符串1 :", signStr)
return signStr, nil
}
func GetGoodsFirstSkuCombo(goodsId []uint32) []GoodsAttributeCombo {
var list []GoodsAttributeCombo
//查询每个商品按sort字端排序的最大的一个sku的价格
err := DB.
Raw(`
SELECT b.*
FROM (SELECT id
FROM goods_attribute d
INNER JOIN (SELECT goods_id, MAX(sort) AS max_sort FROM goods_attribute GROUP BY goods_id) c
ON c.goods_id = d.goods_id AND c.max_sort = d.sort) AS a
INNER JOIN goods_attribute_combo b ON a.id = b.goods_attribute_id
WHERE b.goods_id IN (?)
GROUP BY b.goods_id
`, goodsId).
Scan(&list).
Error
if err != nil {
logger.Error("get goods first sku failed", err)
return nil
}
return list
}