From 07ee98f83858ffdc93e44283f597bcacaaad9739 Mon Sep 17 00:00:00 2001 From: yuming Date: Sat, 15 Aug 2026 17:40:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20consume=20=E7=BC=BA?= =?UTF-8?q?=E8=A1=8C=E4=B8=8D=E5=BB=BA=E8=A1=8C=E5=AF=BC=E8=87=B4=20sentTo?= =?UTF-8?q?tal=20=E4=B8=A2=E5=A4=B1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/quota.js | 11 ++++++++--- server/test/quota.test.js | 12 ++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/server/src/quota.js b/server/src/quota.js index cf5ca42..5e30778 100644 --- a/server/src/quota.js +++ b/server/src/quota.js @@ -38,12 +38,17 @@ function grant(openid, count = 1) { return getBalance(openid) } +// 消费:即便该 openid 从未 grant 过也要建行,否则 sentTotal 会静默丢失 +// (新建行 balance 直接落 0,等价于「从 0 扣减再取 MAX(0, ...)」) function consume(openid, count = 1) { const n = _normalize(count) db.prepare(` - UPDATE subscribe_quota - SET balance = MAX(0, balance - @n), sentTotal = sentTotal + @n, updateTime = @now - WHERE openid = @openid + INSERT INTO subscribe_quota (openid, balance, grantedTotal, sentTotal, updateTime) + VALUES (@openid, 0, 0, @n, @now) + ON CONFLICT(openid) DO UPDATE SET + balance = MAX(0, balance - @n), + sentTotal = sentTotal + @n, + updateTime = @now `).run({ openid, n, now: Date.now() }) return getBalance(openid) } diff --git a/server/test/quota.test.js b/server/test/quota.test.js index 8ab39a1..9a78d55 100644 --- a/server/test/quota.test.js +++ b/server/test/quota.test.js @@ -4,6 +4,7 @@ const { useTempDb } = require('./helper') useTempDb() // 必须在 require quota/db 之前 const quota = require('../src/quota') +const db = require('../src/db') test('未记录过的用户余额为 0', () => { assert.strictEqual(quota.getBalance('u_new'), 0) @@ -49,3 +50,14 @@ test('各用户额度互不影响', () => { assert.strictEqual(quota.getBalance('a'), 3) assert.strictEqual(quota.getBalance('b'), 1) }) + +test('consume 对从未 grant 过的 openid 也要建行,不丢失 sentTotal', () => { + quota.consume('u6', 3) + // 仅断言 getBalance 为 0 不足以证明建行了(缺行时本来就返回 0), + // 必须直接查表,确认行确实被创建且 sentTotal 记录了这次消费 + assert.strictEqual(quota.getBalance('u6'), 0) + const row = db.prepare('SELECT * FROM subscribe_quota WHERE openid = ?').get('u6') + assert.ok(row, 'u6 对应的记录行应当被创建') + assert.strictEqual(row.balance, 0) + assert.strictEqual(row.sentTotal, 3) +})