fix(simulations): déplacer incrément simulations_used après correction réussie (Option B)

This commit is contained in:
Hermann_Kitio 2026-04-21 02:01:13 +03:00
parent 1a5b79807e
commit ecb478e10c
3 changed files with 23 additions and 27 deletions

View file

@ -55,15 +55,6 @@ function mockInsert(returnData: { id: string; tache: string; mode: string; creat
} as any) } as any)
} }
/** Mock from('profiles').update(...).eq(...) */
function mockUpdate() {
vi.mocked(supabase.from).mockReturnValueOnce({
update: vi.fn(() => ({
eq: vi.fn(() => ({ data: null, error: null })),
})),
} as any)
}
/** Mock from('productions').select(...).eq(...).single() pour getById */ /** Mock from('productions').select(...).eq(...).single() pour getById */
function mockProductionSelect(data: unknown, error: unknown = null) { function mockProductionSelect(data: unknown, error: unknown = null) {
vi.mocked(supabase.from).mockReturnValueOnce({ vi.mocked(supabase.from).mockReturnValueOnce({
@ -123,12 +114,11 @@ describe('POST /simulations', () => {
vi.clearAllMocks() vi.clearAllMocks()
}) })
it('free + 4 simulations utilisées → création OK, simulations_used incrémenté', async () => { it('free + 4 simulations utilisées → création OK, pas d\'incrément (il a lieu après correction)', async () => {
const profile = buildProfile({ plan: 'free', simulations_used: 4 }) const profile = buildProfile({ plan: 'free', simulations_used: 4 })
mockAuth(profile) mockAuth(profile)
mockInsert({ id: 'prod-1', tache: 'EE_T1', mode: 'entrainement', created_at: '2024-01-01T00:00:00Z' }) mockInsert({ id: 'prod-1', tache: 'EE_T1', mode: 'entrainement', created_at: '2024-01-01T00:00:00Z' })
mockSujets([MOCK_SUJET_EE_T1]) mockSujets([MOCK_SUJET_EE_T1])
mockUpdate()
const app = createApp() const app = createApp()
const res = await app.request('/simulations', { const res = await app.request('/simulations', {
@ -143,10 +133,9 @@ describe('POST /simulations', () => {
expect(body.tache).toBe('EE_T1') expect(body.tache).toBe('EE_T1')
expect(body.mode).toBe('entrainement') expect(body.mode).toBe('entrainement')
expect(body.sujet).toEqual(MOCK_SUJET_EE_T1) expect(body.sujet).toEqual(MOCK_SUJET_EE_T1)
// 4 appels from : profiles (auth) + productions (insert) + sujets (select) + profiles (update) // 3 appels from : profiles (auth) + productions (insert) + sujets (select)
expect(vi.mocked(supabase.from).mock.calls).toHaveLength(4) expect(vi.mocked(supabase.from).mock.calls).toHaveLength(3)
expect(vi.mocked(supabase.from).mock.calls[2][0]).toBe('sujets') expect(vi.mocked(supabase.from).mock.calls[2][0]).toBe('sujets')
expect(vi.mocked(supabase.from).mock.calls[3][0]).toBe('profiles')
}) })
it('free + 5 simulations utilisées → QUOTA_REACHED', async () => { it('free + 5 simulations utilisées → QUOTA_REACHED', async () => {

View file

@ -1,5 +1,6 @@
import { supabase } from '../lib/supabase.js' import { supabase } from '../lib/supabase.js'
import { correctEE as deepseekCorrectEE, correctEO as deepseekCorrectEO } from '../lib/deepseek.js' import { correctEE as deepseekCorrectEE, correctEO as deepseekCorrectEO } from '../lib/deepseek.js'
import { PLANS, type Plan } from '../lib/access.js'
import type { EERapport, EORapport } from '../lib/deepseek.js' import type { EERapport, EORapport } from '../lib/deepseek.js'
import type { AuthProfile } from '../middleware/auth.js' import type { AuthProfile } from '../middleware/auth.js'
@ -73,7 +74,15 @@ export async function correctEE(
} }
} }
// 4. Retourner le rapport complet enrichi avec simulation_id // 4. Incrémenter simulations_used si le plan a une limite (non bloquant).
if (PLANS[profile.plan as Plan].simulations_lifetime !== null) {
await supabase
.from('profiles')
.update({ simulations_used: profile.simulations_used + 1 })
.eq('id', profile.id)
}
// 5. Retourner le rapport complet enrichi avec simulation_id
return { data: { ...rapport, simulation_id: simulationId } } return { data: { ...rapport, simulation_id: simulationId } }
} }
@ -141,6 +150,14 @@ export async function correctEO(
} }
} }
// 4. Retourner le rapport complet enrichi avec simulation_id // 4. Incrémenter simulations_used si le plan a une limite (non bloquant).
if (PLANS[profile.plan as Plan].simulations_lifetime !== null) {
await supabase
.from('profiles')
.update({ simulations_used: profile.simulations_used + 1 })
.eq('id', profile.id)
}
// 5. Retourner le rapport complet enrichi avec simulation_id
return { data: { ...rapport, simulation_id: simulationId } } return { data: { ...rapport, simulation_id: simulationId } }
} }

View file

@ -1,6 +1,5 @@
import { supabase } from '../lib/supabase.js' import { supabase } from '../lib/supabase.js'
import { canUserSimulate, getPlanPermissions } from '../lib/access.js' import { canUserSimulate } from '../lib/access.js'
import type { Plan } from '../lib/access.js'
import type { EERapport } from '../lib/deepseek.js' import type { EERapport } from '../lib/deepseek.js'
import type { AuthProfile } from '../middleware/auth.js' import type { AuthProfile } from '../middleware/auth.js'
@ -114,15 +113,6 @@ export async function create(
} }
} }
// 4. Incrémenter simulations_used si le plan a une limite (via access.ts — Règle D)
const perms = getPlanPermissions(profile.plan as Plan)
if (perms.simulations_lifetime !== null) {
await supabase
.from('profiles')
.update({ simulations_used: profile.simulations_used + 1 })
.eq('id', profile.id)
}
return { return {
data: { data: {
id: data.id, id: data.id,