mh_server/controller/mall.go
2022-11-26 16:52:05 +08:00

764 lines
19 KiB
Go

package controller
import (
"errors"
"github.com/codinl/go-logger"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
"mh-server/lib/auth"
"mh-server/lib/status"
"mh-server/lib/utils"
"mh-server/lib/wxpay"
"mh-server/model"
"time"
)
func MallGoodsList(c *gin.Context) {
req := model.GoodsListReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
list, total, err := req.GoodsList()
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
ret := map[string]interface{}{
"list": list,
"cur_page": req.PageIdx,
"total_page": total,
}
RespOK(c, ret)
return
}
func MallGoodsDetail(c *gin.Context) {
req := model.GoodsDetailReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
detail, err := req.GoodsDetail()
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, detail)
return
}
func MallOrderCreate(c *gin.Context) {
req := struct {
GoodsId uint32 `json:"goods_id" binding:"required"` // 商品id
GoodsAttributeId uint32 `json:"goods_attribute_id" binding:"required"` // 规格id
GoodsAttributeComboId uint32 `json:"goods_attribute_combo_id" binding:"required"` // 套餐id
Quantity uint32 `json:"quantity" binding:"required"` // 购买数量
//PayType uint32 `json:"pay_type" binding:"required"` // 支付方式
AddressId uint32 `json:"address_id" binding:"required"` // 收货地址
DeliveryExtraInfo string `json:"delivery_extra_info"` // 收货备注
}{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
user := model.GetUserByUid(uc.Uid)
err := user.SetVm()
if err != nil {
log.Error().Msgf("set vm err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
// 商品是否存在
var goods model.Goods
err = model.NewGoodsQuerySet(model.DB).GoodsIdEq(req.GoodsId).One(&goods)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.BadRequest, nil)
return
}
// 商品在售状态
if goods.SaleStatus != model.SaleStatusYes {
logger.Error("err:", err)
RespJson(c, status.GoodsNotSale, nil)
return
}
var attribute model.GoodsAttribute
err = model.NewGoodsAttributeQuerySet(model.DB).IDEq(req.GoodsAttributeId).One(&attribute)
if err != nil {
log.Error().Msgf("attribute err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
// 库存不足
//if goods.Stock < req.Quantity {
if attribute.Stock < req.Quantity {
logger.Error("err:", err)
RespJson(c, status.OrderStockOut, nil)
return
}
// 检测收货地址是否正确
count, _ := model.NewUserAddressQuerySet(model.DB).UidEq(uc.Uid).IDEq(req.AddressId).Count()
if count != 1 {
logger.Error("err:", err)
RespJson(c, status.BadRequest, "收货地址错误")
return
}
//// 计算总金额
//amount := uint32(0)
//if req.PayType == model.PayTypeRm {
// amount = req.Quantity * goods.PriceRm
//} else if req.PayType == model.PayTypeVm {
// amount = req.Quantity * goods.PriceVm
//}
discount, err := goods.GetUserDiscount(user)
if err != nil {
log.Error().Msgf("combo err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
var combo model.GoodsAttributeCombo
err = model.NewGoodsAttributeComboQuerySet(model.DB).IDEq(req.GoodsAttributeComboId).One(&combo)
if err != nil {
log.Error().Msgf("combo err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
totalVm := combo.PriceVm * req.Quantity
totalRm := (combo.PriceRm*req.Quantity*discount + 5) / model.Rmb
if combo.PriceVm > 0 && user.UserVm.Vm < totalVm {
log.Error().Msgf("vm not enough")
RespJson(c, status.UserVmNotEnough, nil)
return
}
// 开启事务
tx := model.TransactionBegin()
// 订单创建逻辑
order := model.GoodsOrder{
OrderId: model.CreateGoodsOrderId(),
SerialNo: model.CreateGoodsOrderSerialNo(),
Uid: uc.Uid,
GoodsId: req.GoodsId,
Rm: totalRm,
Vm: totalVm,
Quantity: req.Quantity,
//PayType: req.PayType,
PayStatus: model.PayStatusInit,
AddressId: req.AddressId,
DeliveryExtraInfo: req.DeliveryExtraInfo,
DeliveryFee: goods.DeliveryFee,
DeliveryStatus: model.DeliveryStatusUnDeliver,
GoodsAttributeId: req.GoodsAttributeId,
GoodsAttributeComboId: req.GoodsAttributeComboId,
Discount: discount,
State: model.GoodsOrderStateUnPay,
}
// 减少库存
// 确认下是在支付后减少,还是下单后
//if req.PayType == model.PayTypeVm {
//var userVm model.UserVm
//err = model.NewUserVmQuerySet(model.DB).UidEq(uc.Uid).One(&userVm)
//if err != nil {
// tx.Rollback()
// logger.Error("err:", err)
// RespJson(c, status.InternalServerError, nil)
// return
//}
//if userVm.Vm < amount {
// tx.Rollback()
// logger.Error("err:", err)
// RespJson(c, status.UserVmNotEnough, nil)
// return
//}
//err := model.OrderDeductionUserVm(uc.Uid, int(userVm.Vm), int(amount)*-1, tx)
//if err != nil {
// tx.Rollback()
// logger.Error("err:", err)
// RespJson(c, status.InternalServerError, nil)
// return
//}
//}
//if goods.DeliveryFee == 0 {
if combo.PriceRm == 0 {
order.PayTime = time.Now()
order.PayStatus = model.PayStatusOK
order.State = model.GoodsOrderStateOnDeliver
err = order.Create(tx)
if err != nil {
logger.Error("err:", err)
tx.Rollback()
RespJson(c, status.InternalServerError, nil)
return
}
err = model.OrderUpdateGoodsStock(req.GoodsAttributeId, order.Quantity, tx)
if err != nil {
tx.Rollback()
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
err = model.UserVmUpdate(order.Uid, int(order.Vm)*-1, model.VmEventBuyGoods, "购买商品积分抵扣")
if err != nil {
tx.Rollback()
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
err = tx.Commit().Error
if err != nil {
tx.Rollback()
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
sub := model.DeliverTaskSub{
Uid: order.Uid,
UserAddressId: order.AddressId,
OrderType: 2,
OrderId: order.OrderId,
StoreId: 13,
}
err = sub.Add()
if err != nil {
logger.Error("deliver task sub add err:", err)
}
ret := map[string]interface{}{
"order_id": order.ID,
"order": order,
}
RespOK(c, ret)
return
}
err = order.Create(tx)
if err != nil {
logger.Error("err:", err)
tx.Rollback()
RespJson(c, status.InternalServerError, nil)
return
}
err = tx.Commit().Error
if err != nil {
tx.Rollback()
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
//var user model.User
//err = model.NewUserQuerySet(model.DB).UidEq(uint32(order.Uid)).One(&user)
//if err != nil {
// logger.Error("Order err:", err)
// RespJson(c, status.InternalServerError, nil)
// return
//}
configInfo, err := model.PayConfigInfo()
if err != nil {
logger.Error(err)
RespJson(c, status.InternalServerError, nil)
return
}
//webPay, err := wxpay.WebPay(order.SerialNo, order.Rm, user.WxOpenID, "N",
// wxpay.WxPayBuyGoods, configInfo.NotifyUrl)
//if err != nil {
// logger.Error(errors.New("WebPay err"))
// RespJson(c, status.InternalServerError, nil)
// return
//}
err = model.UserOpenMemberRecord{Uid: uc.Uid, OpenNo: order.SerialNo, OrderId: order.OrderId, OrderType: 6, Attach: wxpay.WxPayBuyGoods}.Insert()
if err != nil {
logger.Error(errors.New("WebPay err"))
RespJson(c, status.InternalServerError, nil)
return
}
webPay, err := wxpay.HmJsPayUnifiedOrder(order.SerialNo, order.Rm, user.WxOpenID, configInfo.NotifyUrl)
if err != nil {
logger.Error(errors.New("WebPay err"))
RespJson(c, status.InternalServerError, nil)
return
}
ret := map[string]interface{}{
"web_pay": webPay,
"order_id": order.ID,
"order": order,
}
RespOK(c, ret)
//RespOK(c, order)
return
}
// 订单支付
// 暂时只支持积分支付, 以后再考虑人民币支付
func MallOrderPay(c *gin.Context) {
req := struct {
OrderId uint32 `json:"order_id" binding:"required"`
}{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
// 订单是否存在
var order model.GoodsOrder
err := model.NewGoodsOrderQuerySet(model.DB).
OrderIdEq(req.OrderId).
UidEq(uc.Uid).
One(&order)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.BadRequest, nil)
return
}
// 订单状态不可以支付
if order.PayStatus != model.PayStatusInit {
logger.Error("err:", err)
RespJson(c, status.BadRequest, nil)
return
}
tx := model.TransactionBegin()
// 减少库存
// 确认下是在支付后减少,还是下单后?
// 减少用户积分
// 更新支付状态
err = model.NewGoodsOrderQuerySet(tx).
OrderIdEq(req.OrderId).
VersionIdEq(order.VersionId).
GetUpdater().
SetPayStatus(model.PayStatusOK).
SetVersionId(order.VersionId + 1).
Update()
if err != nil {
logger.Error("err:", err)
tx.Rollback()
RespJson(c, status.BadRequest, nil)
return
}
tx.Commit()
RespOK(c, nil)
return
}
func MallOrderList(c *gin.Context) {
req := model.GoodsOrderListReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
list, total, err := req.OrderList(uc.Uid)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
ret := map[string]interface{}{
"list": list,
"cur_page": req.PageIdx,
"total_page": total,
}
RespOK(c, ret)
return
}
func MallOrderDetail(c *gin.Context) {
req := model.GoodsOrderDetailReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
detail, err := req.OrderDetail(uc.Uid)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, detail)
return
}
func MallOrderRefund(c *gin.Context) {
req := struct {
GoodsOrderId uint32 `json:"goods_order_id"`
RefundReason string `json:"refund_reason"`
}{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
//model.GoodsOrder{}
var goodsOrder model.GoodsOrder
err := model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).One(&goodsOrder)
if err != nil {
log.Error().Msgf("goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
if goodsOrder.CreatedAt.AddDate(0, 0, 15).Before(utils.Now()) ||
(!goodsOrder.ReceivedTime.IsZero() && goodsOrder.ReceivedTime.AddDate(0, 0, 7).Before(utils.Now())) {
log.Error().Msg("goods order refund exceed the time limit")
RespJson(c, status.InternalServerError, nil)
return
}
if goodsOrder.State != model.GoodsOrderStateDelivered &&
goodsOrder.State != model.GoodsOrderStateReceived &&
goodsOrder.State != model.GoodsOrderStateRefundedCancel {
log.Error().Msg("goods order state err")
RespJson(c, status.OrderDelivered, nil)
return
}
store, err := model.GetStore(goodsOrder.DeliverStoreId)
if err != nil {
log.Error().Msgf("get store err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
goodsOrder.DeliverStore = store
err = model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).GetUpdater().
SetRefundReason(req.RefundReason).SetState(model.GoodsOrderStateOnRefund).Update()
if err != nil {
log.Error().Msgf("update goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, goodsOrder)
return
}
func MallOrderRefundCancel(c *gin.Context) {
req := struct {
GoodsOrderId uint32 `json:"goods_order_id"`
}{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
var goodsOrder model.GoodsOrder
err := model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).One(&goodsOrder)
if err != nil {
log.Error().Msgf("goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
if goodsOrder.State != model.GoodsOrderStateOnRefund {
log.Error().Msgf("state err")
RespJson(c, status.StateNotCancel, nil)
return
}
err = model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).GetUpdater().
SetState(model.GoodsOrderStateRefundedCancel).Update()
if err != nil {
log.Error().Msgf("update goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, nil)
return
}
func MallOrderRefundSend(c *gin.Context) {
req := struct {
GoodsOrderId uint32 `json:"goods_order_id"`
RefundExpressCompany string `json:"refund_express_company"` // 退货物流公司
RefundExpressCompanyNo string `json:"refund_express_company_no"` // 退货物流公司编号
RefundExpressNo string `json:"refund_express_no"` // 退货物流单号
}{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
var goodsOrder model.GoodsOrder
err := model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).One(&goodsOrder)
if err != nil {
log.Error().Msgf("goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
if goodsOrder.State != model.GoodsOrderStateOnRefund {
log.Error().Msgf("state err")
RespJson(c, status.StateNotCancel, nil)
return
}
err = model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).GetUpdater().
SetRefundExpressNo(req.RefundExpressNo).
SetRefundExpressCompany(req.RefundExpressCompany).
SetRefundExpressCompanyNo(req.RefundExpressCompanyNo).Update()
if err != nil {
log.Error().Msgf("update goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, nil)
return
}
func MallOrderCancel(c *gin.Context) {
req := struct {
GoodsOrderId uint32 `json:"goods_order_id"`
}{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
var goodsOrder model.GoodsOrder
err := model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).One(&goodsOrder)
if err != nil {
log.Error().Msgf("goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
if goodsOrder.State != model.GoodsOrderStateOnDeliver {
log.Error().Msg("goods order state err")
RespJson(c, status.OrderDelivered, nil)
return
}
if goodsOrder.PayStatus != 2 {
log.Error().Msg("not pay")
RespJson(c, status.InternalServerError, nil)
return
}
if goodsOrder.Rm != 0 {
outTradeNo, err := model.GetWxPayExpressFeeRefundRecord(goodsOrder.OrderId)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
//m.OpenNo = model.GetOrderSn()
memberRecord := &model.UserOpenMemberRecord{OpenNo: model.GetOrderSn(), OrderType: 7, GoodsOrder: &goodsOrder}
err = memberRecord.MallGoodsOrderRefund(outTradeNo)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
}
//tx := model.DB.Begin()
err = model.NewGoodsOrderQuerySet(model.DB).OrderIdEq(req.GoodsOrderId).GetUpdater().
SetState(model.GoodsOrderStateCancel).Update()
if err != nil {
//tx.Rollback()
log.Error().Msgf("update goods order err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
//err = tx.Commit().Error
//if err != nil {
// tx.Rollback()
// log.Error().Msgf("commit err:%#v", err)
// RespJson(c, status.InternalServerError, nil)
// return
//}
if goodsOrder.Vm != 0 {
err = model.UserVmUpdate(goodsOrder.Uid, int(goodsOrder.Vm), model.VmEventBuyGoods, "购买商品积分抵扣取消")
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
}
model.UpdateDeliverTaskSubStateCancel(goodsOrder.OrderId)
RespOK(c, "")
return
}
func MallUserVmRecord(c *gin.Context) {
req := model.MallUserVmRecordReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
list, total, err := req.UserVmRecordList(uc.Uid)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
ret := map[string]interface{}{
"list": list,
"cur_page": req.PageIdx,
"total_page": total,
}
RespOK(c, ret)
return
}
func MallGoodsOrderConfirmReceipt(c *gin.Context) {
req := model.MallGoodsOrderConfirmReceiptReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
uc := auth.GetCurrentUser(c)
if uc == nil {
RespJson(c, status.Unauthorized, nil)
return
}
err := req.MallGoodsOrderConfirmReceipt(uc.Uid)
if err != nil {
logger.Error("err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, nil)
return
}
func MallGoodsSpec(c *gin.Context) {
req := model.MallGoodsSpecReq{}
if err := c.ShouldBindJSON(&req); err != nil {
logger.Error(err)
RespJson(c, status.BadRequest, nil)
return
}
err := req.Spec()
if err != nil {
logger.Error("err:", err)
if err.Error() == "not_found" {
RespJson(c, status.OrderStockOut, nil)
return
}
RespJson(c, status.InternalServerError, nil)
return
}
RespOK(c, req.GoodsAttribute)
return
}
func MallGoodsCatList(c *gin.Context) {
var goodsCats []model.GoodsCat
err := model.DB.Table("goods_cat").Where("level=?", 1).Where("state=2").
Order("sort DESC").Find(&goodsCats).Error
if err != nil {
logger.Error("goods cat list err:", err)
RespJson(c, status.InternalServerError, nil)
return
}
pids := make([]uint32, 0)
for i, _ := range goodsCats {
pids = append(pids, goodsCats[i].ID)
}
var subCat []model.GoodsCat
err = model.DB.Table("goods_cat").Where("pid in (?)", pids).Where("state=2").
Order("sort DESC").Find(&subCat).Error
if err != nil {
logger.Errorf("pCat err:%#v", err)
RespJson(c, status.InternalServerError, nil)
return
}
pCatMap := make(map[uint32][]model.GoodsCat, 0)
for i, _ := range subCat {
pCatMap[subCat[i].Pid] = append(pCatMap[subCat[i].Pid], subCat[i])
}
for i, _ := range goodsCats {
v, ok := pCatMap[goodsCats[i].ID]
if ok {
goodsCats[i].SubCats = v
}
}
RespOK(c, goodsCats)
return
}