2.1 版本文件
This commit is contained in:
+153
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
// 结算下单:登录后填写收货信息,生成订单并扣减库存
|
||||
require __DIR__ . '/includes/init.php';
|
||||
requireLogin('checkout.php');
|
||||
$pageTitle = '结算';
|
||||
$user = currentUser();
|
||||
|
||||
$cart = $_SESSION['cart'] ?? [];
|
||||
$items = [];
|
||||
$total = 0;
|
||||
if (!empty($cart)) {
|
||||
$ids = array_keys($cart);
|
||||
$ph = implode(',', array_fill(0, count($ids), '?'));
|
||||
$stmt = db()->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';
|
||||
?>
|
||||
<section class="section">
|
||||
<h2 class="sec-title"><i class="fas fa-credit-card"></i> 订单结算</h2>
|
||||
<div class="checkout">
|
||||
<div class="co-items">
|
||||
<h3>商品清单</h3>
|
||||
<?php foreach ($items as $it): ?>
|
||||
<div class="co-row">
|
||||
<span><?= h($it['p']['name']) ?> × <?= $it['qty'] ?></span>
|
||||
<span><?= $it['points_sub'] > 0 ? (int)$it['points_sub'] . ' 积分' : '直接下单' ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<form method="post" action="" class="co-form">
|
||||
<?= csrfField() ?>
|
||||
<h3>收货信息</h3>
|
||||
<?php if ($err): ?><p class="form-err"><?= h($err) ?></p><?php endif; ?>
|
||||
<label>联系人<input type="text" name="contact" value="<?= h($_POST['contact'] ?? $user['username']) ?>" required></label>
|
||||
<label>联系邮箱<input type="email" name="contact_email" value="<?= h($_POST['contact_email'] ?? $user['email']) ?>" placeholder="用于接收订单/发货通知" required></label>
|
||||
<label>收货地址<input type="text" name="address" value="<?= h($_POST['address'] ?? '') ?>" required></label>
|
||||
<label>备注<input type="text" name="note" value="<?= h($_POST['note'] ?? '') ?>" placeholder="选填"></label>
|
||||
<?php if ($pointsElg): ?>
|
||||
<div class="co-pay">
|
||||
<h3>支付方式</h3>
|
||||
<input type="hidden" name="pay_type" value="points">
|
||||
<p class="pay-opt"><i class="fas fa-coins"></i> 积分支付(<?= $pointsTotal ?> 积分)<span class="muted" style="margin-left:10px;font-size:.85em;">当前积分 <?= (int)$userPoints ?></span></p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<input type="hidden" name="pay_type" value="direct">
|
||||
<?php endif; ?>
|
||||
<p class="co-tip">下单后如有积分价格要求,用积分支付;无积分价格,直接支付即可(发工单即代表您已同意资源领取/续期规定)。</p>
|
||||
<button type="submit" class="btn btn-primary" style="width:100%;">提交订单</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
<?php require 'includes/footer.php'; ?>
|
||||
Reference in New Issue
Block a user