feat: fix stock check and add admin order status update
This commit is contained in:
@@ -278,11 +278,13 @@ func (h *OrderHandler) Create(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var inventory models.Inventory
|
var inventory models.Inventory
|
||||||
if err := utils.DB.Where("product_id = ?", cart.ProductID).First(&inventory).Error; err == nil {
|
if err := utils.DB.Where("product_id = ?", cart.ProductID).First(&inventory).Error; err != nil {
|
||||||
if inventory.Quantity < cart.Quantity {
|
c.JSON(http.StatusBadRequest, gin.H{"error": "No inventory record for " + cart.Product.Name})
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient stock for " + cart.Product.Name})
|
return
|
||||||
return
|
}
|
||||||
}
|
if inventory.Quantity < cart.Quantity {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Insufficient stock for " + cart.Product.Name + ". Available: " + strconv.Itoa(inventory.Quantity)})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
subtotal += cart.Product.Price * float64(cart.Quantity)
|
subtotal += cart.Product.Price * float64(cart.Quantity)
|
||||||
@@ -723,3 +725,52 @@ func (h *OrderHandler) ConfirmReceipt(c *gin.Context) {
|
|||||||
utils.DB.Model(&order).Update("status", models.OrderStatusCompleted)
|
utils.DB.Model(&order).Update("status", models.OrderStatusCompleted)
|
||||||
c.JSON(http.StatusOK, gin.H{"message": "Order confirmed successfully"})
|
c.JSON(http.StatusOK, gin.H{"message": "Order confirmed successfully"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *OrderHandler) AdminUpdateStatus(c *gin.Context) {
|
||||||
|
id, _ := strconv.Atoi(c.Param("id"))
|
||||||
|
|
||||||
|
var order models.Order
|
||||||
|
if err := utils.DB.First(&order, id).Error; err != nil {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
Status string `json:"status" binding:"required"`
|
||||||
|
TrackingNumber string `json:"tracking_number"`
|
||||||
|
}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
validStatuses := []string{
|
||||||
|
models.OrderStatusPendingPayment,
|
||||||
|
models.OrderStatusPendingConfirm,
|
||||||
|
models.OrderStatusPendingShip,
|
||||||
|
models.OrderStatusShipped,
|
||||||
|
models.OrderStatusCompleted,
|
||||||
|
models.OrderStatusRefunding,
|
||||||
|
models.OrderStatusRefunded,
|
||||||
|
models.OrderStatusCancelled,
|
||||||
|
}
|
||||||
|
valid := false
|
||||||
|
for _, s := range validStatuses {
|
||||||
|
if s == req.Status {
|
||||||
|
valid = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid status"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updates := map[string]interface{}{"status": req.Status}
|
||||||
|
if req.TrackingNumber != "" {
|
||||||
|
updates["tracking_number"] = req.TrackingNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.DB.Model(&order).Updates(updates)
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Order status updated successfully"})
|
||||||
|
}
|
||||||
|
|||||||
@@ -188,9 +188,10 @@ func SetupRoutes(r *gin.Engine) {
|
|||||||
adminOrders := admin.Group("/orders")
|
adminOrders := admin.Group("/orders")
|
||||||
{
|
{
|
||||||
adminOrders.GET("", orderHandler.AdminList)
|
adminOrders.GET("", orderHandler.AdminList)
|
||||||
adminOrders.GET("/:id", orderHandler.AdminGetByID)
|
adminOrders.GET("/:id", orderHandler.AdminGetByID)
|
||||||
adminOrders.GET("/export", orderHandler.Export)
|
adminOrders.GET("/export", orderHandler.Export)
|
||||||
adminOrders.PUT("/:id/refund", orderHandler.ProcessRefund)
|
adminOrders.PUT("/:id/refund", orderHandler.ProcessRefund)
|
||||||
|
adminOrders.PUT("/:id/status", orderHandler.AdminUpdateStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
adminLotteries := admin.Group("/lotteries")
|
adminLotteries := admin.Group("/lotteries")
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ export const adminApi = {
|
|||||||
getOrderById: (id: number) => api.get(`/admin/orders/${id}`),
|
getOrderById: (id: number) => api.get(`/admin/orders/${id}`),
|
||||||
exportOrders: () => api.get('/admin/orders/export'),
|
exportOrders: () => api.get('/admin/orders/export'),
|
||||||
processRefund: (id: number, data: any) => api.put(`/admin/orders/${id}/refund`, data),
|
processRefund: (id: number, data: any) => api.put(`/admin/orders/${id}/refund`, data),
|
||||||
|
updateOrderStatus: (id: number, data: any) => api.put(`/admin/orders/${id}/status`, data),
|
||||||
|
|
||||||
getSuppliers: () => api.get('/admin/suppliers'),
|
getSuppliers: () => api.get('/admin/suppliers'),
|
||||||
createSupplier: (data: any) => api.post('/admin/suppliers', data),
|
createSupplier: (data: any) => api.post('/admin/suppliers', data),
|
||||||
|
|||||||
@@ -48,13 +48,33 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<span class="label">状态:</span>
|
<span class="label">状态:</span>
|
||||||
<span class="value"><el-tag>{{ statusText(currentOrder.status) }}</el-tag></span>
|
<span class="value">
|
||||||
|
<el-select v-model="editStatus" size="small" style="width: 120px">
|
||||||
|
<el-option label="待支付" value="pending_payment" />
|
||||||
|
<el-option label="待确认" value="pending_confirm" />
|
||||||
|
<el-option label="待发货" value="pending_ship" />
|
||||||
|
<el-option label="已发货" value="shipped" />
|
||||||
|
<el-option label="已完成" value="completed" />
|
||||||
|
<el-option label="退款中" value="refunding" />
|
||||||
|
<el-option label="已退款" value="refunded" />
|
||||||
|
<el-option label="已取消" value="cancelled" />
|
||||||
|
</el-select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<span class="label">快递单号:</span>
|
||||||
|
<span class="value">
|
||||||
|
<el-input v-model="editTrackingNumber" size="small" style="width: 200px" placeholder="输入快递单号" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail-item">
|
<div class="detail-item">
|
||||||
<span class="label">创建时间:</span>
|
<span class="label">创建时间:</span>
|
||||||
<span class="value">{{ formatDate(currentOrder.created_at) }}</span>
|
<span class="value">{{ formatDate(currentOrder.created_at) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="margin-top: 12px">
|
||||||
|
<el-button type="primary" size="small" @click="saveStatus">保存修改</el-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="detail-section" v-if="currentOrder.shipping_address">
|
<div class="detail-section" v-if="currentOrder.shipping_address">
|
||||||
@@ -170,6 +190,8 @@ const paginatedOrders = computed(() => {
|
|||||||
|
|
||||||
const detailVisible = ref(false)
|
const detailVisible = ref(false)
|
||||||
const currentOrder = ref<any>(null)
|
const currentOrder = ref<any>(null)
|
||||||
|
const editStatus = ref('')
|
||||||
|
const editTrackingNumber = ref('')
|
||||||
|
|
||||||
const statusMap: Record<string, string> = {
|
const statusMap: Record<string, string> = {
|
||||||
pending_payment: '待支付', pending_confirm: '待确认', pending_ship: '待发货',
|
pending_payment: '待支付', pending_confirm: '待确认', pending_ship: '待发货',
|
||||||
@@ -201,12 +223,30 @@ async function viewDetail(row: any) {
|
|||||||
try {
|
try {
|
||||||
const res: any = await adminApi.getOrderById(row.id)
|
const res: any = await adminApi.getOrderById(row.id)
|
||||||
currentOrder.value = res.data
|
currentOrder.value = res.data
|
||||||
|
editStatus.value = res.data.status
|
||||||
|
editTrackingNumber.value = res.data.tracking_number || ''
|
||||||
detailVisible.value = true
|
detailVisible.value = true
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error('获取订单详情失败')
|
ElMessage.error('获取订单详情失败')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveStatus() {
|
||||||
|
if (!currentOrder.value) return
|
||||||
|
try {
|
||||||
|
await adminApi.updateOrderStatus(currentOrder.value.id, {
|
||||||
|
status: editStatus.value,
|
||||||
|
tracking_number: editTrackingNumber.value
|
||||||
|
})
|
||||||
|
ElMessage.success('订单状态已更新')
|
||||||
|
const res: any = await adminApi.getOrderById(currentOrder.value.id)
|
||||||
|
currentOrder.value = res.data
|
||||||
|
await fetchOrders()
|
||||||
|
} catch {
|
||||||
|
ElMessage.error('更新失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function processRefund(id: number, status: string) {
|
async function processRefund(id: number, status: string) {
|
||||||
await adminApi.processRefund(id, { status })
|
await adminApi.processRefund(id, { status })
|
||||||
ElMessage.success('已处理')
|
ElMessage.success('已处理')
|
||||||
|
|||||||
Reference in New Issue
Block a user