prepare('SELECT * FROM ' . tn('products') . ' WHERE id IN (' . $ph . ') AND status = 1'); $stmt->execute($ids); foreach ($stmt->fetchAll() as $p) { $qty = (int) $cart[$p['id']]; if ($qty > $p['stock']) $qty = $p['stock']; $pointsSub = (!empty($p['points_price']) ? (int)$p['points_price'] * $qty : 0); $items[] = ['p' => $p, 'qty' => $qty, 'points_sub' => $pointsSub]; } } // 积分支付可用性:仅当订单内所有商品都设置了积分价 $pointsElg = !empty($items); $pointsTotal = 0; foreach ($items as $it) { $pp = (int) ($it['p']['points_price'] ?? 0); if ($pp <= 0) { $pointsElg = false; break; } $pointsTotal += $pp * $it['qty']; } if ($pointsTotal <= 0) { $pointsElg = false; } $userPoints = 0; if (isLoggedIn()) { $userPoints = getUserPoints($user['id']); } $err = ''; if (empty($items)) { redirect('cart.php'); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { verifyCsrf(); $contact = trim($_POST['contact'] ?? ''); $contactEmail = trim($_POST['contact_email'] ?? ''); $address = trim($_POST['address'] ?? ''); $note = trim($_POST['note'] ?? ''); if ($contact === '') $err = '请填写联系人'; elseif ($address === '') $err = '请填写收货地址'; elseif ($contactEmail === '') $contactEmail = $user['email']; // 留空则使用账号邮箱 elseif (!filter_var($contactEmail, FILTER_VALIDATE_EMAIL)) $err = '联系邮箱格式不正确'; if ($err === '') { $payType = ($pointsElg && ($_POST['pay_type'] ?? '') === 'points') ? 'points' : 'direct'; if ($payType === 'points') { if ($userPoints < $pointsTotal) { $err = '积分不足,当前 ' . $userPoints . ' 分,本单需 ' . $pointsTotal . ' 分'; } } } if ($err === '') { $pdo = db(); try { $pdo->beginTransaction(); // 二次校验库存 foreach ($items as $it) { $chk = $pdo->prepare('SELECT stock FROM ' . tn('products') . ' WHERE id = ? FOR UPDATE'); $chk->execute([$it['p']['id']]); $row = $chk->fetch(); if (!$row || $row['stock'] < $it['qty']) { throw new Exception('「' . $it['p']['name'] . '」库存不足,请返回购物车调整'); } } // 计算本单周期(取商品中最大的周期天数)与到期时间 $maxPeriod = 0; foreach ($items as $it) { $maxPeriod = max($maxPeriod, (int) ($it['p']['period_days'] ?? 0)); } $expiresAt = $maxPeriod > 0 ? date('Y-m-d H:i:s', strtotime("+$maxPeriod days")) : null; // 本商城不收取现金,现金合计固定记 0;积分支付时抵扣并记流水 $orderTotal = 0; $pointsUsed = 0; if ($payType === 'points') { $pointsUsed = $pointsTotal; $pdo->prepare('UPDATE ' . tn('users') . ' SET points = points - ? WHERE id = ? AND points >= ?') ->execute([$pointsUsed, $user['id'], $pointsUsed]); $bal = getUserPoints($user['id']); $pdo->prepare('INSERT INTO ' . tn('points_log') . ' (user_id,type,amount,balance,remark,created_at) VALUES (?,?,?,?,?,NOW())') ->execute([$user['id'], 'purchase', -$pointsUsed, $bal, '积分兑换:' . $orderNo]); } // 生成订单号 $orderNo = 'FNW' . date('Ymd') . strtoupper(substr(md5(uniqid($user['id'], true)), 0, 10)); $pdo->prepare('INSERT INTO ' . tn('orders') . ' (order_no,user_id,total,status,contact,contact_email,address,note,period_days,expires_at,pay_type,points_used,created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,NOW())') ->execute([$orderNo, $user['id'], $orderTotal, 'paid', $contact, $contactEmail, $address, $note, $maxPeriod, $expiresAt, $payType, $pointsUsed]); $orderId = $pdo->lastInsertId(); foreach ($items as $it) { // 商城已取消现金支付,价格字段保留为 0 供历史兼容 $pdo->prepare('INSERT INTO ' . tn('order_items') . ' (order_id,product_id,name,price,qty,subtotal,period_days) VALUES (?,?,?,?,?,?,?)') ->execute([$orderId, $it['p']['id'], $it['p']['name'], 0, $it['qty'], 0, (int) ($it['p']['period_days'] ?? 0)]); $pdo->prepare('UPDATE ' . tn('products') . ' SET stock = stock - ? WHERE id = ?') ->execute([$it['qty'], $it['p']['id']]); } $pdo->commit(); $_SESSION['cart'] = []; redirect('myorders.php?paid=' . urlencode($orderNo)); } catch (Exception $e) { $pdo->rollBack(); $err = $e->getMessage(); } } } require 'includes/header.php'; ?>

订单结算

商品清单

× 0 ? (int)$it['points_sub'] . ' 积分' : '直接下单' ?>

收货信息

支付方式

积分支付( 积分)当前积分

下单后如有积分价格要求,用积分支付;无积分价格,直接支付即可(发工单即代表您已同意资源领取/续期规定)。