feat: replace desktop membership with permanent point wallet

This commit is contained in:
2026-09-22 11:43:04 +08:00
parent 2f82b9f79c
commit a1cce428af
24 changed files with 1343 additions and 1707 deletions

View File

@@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest';
import { projectBillingSummary, projectPointHistory, projectRechargeOrder } from '@electron/api/routes/works-billing';
import server from '../fixtures/permanent-points-server.json';
// Captured from works-square-server permanent-points API using FastAPI TestClient,
// an isolated SQLite database and a fake payment provider. All identities are synthetic.
// Covers the real API's serialized decimals, timestamps, optional fields and order envelopes.
describe('Works Square permanent-points API compatibility', () => {
it('projects old accounts at zero and genuinely registered youth at 100, without a client gift', () => {
expect(projectBillingSummary(server.before).own_points.total_remaining).toBe('0.00');
const youth = projectBillingSummary(server.youth);
expect(youth.own_points.total_remaining).toBe('100.00');
expect(youth.can_recharge).toBe(false);
});
it('recovers the same payment payload from creation, listing and individual lookup', () => {
const created = projectRechargeOrder(server.created.order, server.created.provider_payload);
expect(created.status).toBe('pending');
expect(created.qr_payload).toBe('weixin://wxpay/contract-fixture');
expect(projectRechargeOrder(server.pending)).toEqual(created);
expect(projectRechargeOrder(server.orders.items[0])).toEqual(created);
});
it('accepts the family payer’s own exact wallet even when sharing is enabled', () => {
const payer = projectBillingSummary(server.family_payer);
expect(payer.points).toMatchObject({ family_shared: true, entitlement_source: 'self', shared_available: null, total_remaining: '500.00' });
expect(payer.can_recharge).toBe(true);
});
it('honors frozen price after repricing and projects the sole confirmed credit', () => {
expect(projectBillingSummary(server.repriced).recharge_products[0].amount_cents).toBe(2000);
const paid = projectRechargeOrder(server.paid);
expect(paid).toMatchObject({ status: 'succeeded', amount_cents: 1000, point_amount: '500.00', qr_payload: null });
expect(projectBillingSummary(server.after).own_points.total_remaining).toBe('500.00');
const history = projectPointHistory(server.history);
expect(history.items).toHaveLength(1);
expect(history.items[0]).toMatchObject({ kind: 'credit', status: 'credited', points: '500.00' });
});
});