import request from '@/utils/request' import { saveDepartmentSubmissionDraft, submitDepartmentSubmission } from '@/api/budget/departmentSubmission' import { getDepartmentSubmissions, reviewDepartmentSubmission, saveDepartmentAllocations, saveLeadDepartmentSummaryDraft, submitLeadDepartmentSummaryByPackage } from '@/api/budget/leadDepartment' import { batchReviewBudgetSubmissions, getBudgetReviewDetail, getBudgetReviews, reviewBudgetSubmission } from '@/api/budget/budgetReview' jest.mock('@/utils/request', () => jest.fn(config => Promise.resolve(config))) describe('budget submission API contract', () => { beforeEach(() => request.mockClear()) it('separates department draft and submit endpoints', async() => { const data = { implementationSchedule: '实施安排', implementationScheduleDetail: { currentYearAmount: '0.0001', currentYearMonth1: '0.0001' }, economicItems: [{ categoryId: 10, amount: '0.0001', calculationBasis: '依据', fileIds: [2] }] } await saveDepartmentSubmissionDraft(31, data) await submitDepartmentSubmission(31, data) expect(request.mock.calls[0][0].url).toBe('/api/admin/budget-decompositions/31/save-draft') expect(request.mock.calls[1][0].url).toBe('/api/admin/budget-decompositions/31/submit') expect(request.mock.calls[0][0].data.economic_items[0]).toEqual({ category_id: 10, amount: '0.0001', calculation_basis: '依据', file_ids: [2] }) expect(request.mock.calls[0][0].data.implementation_schedule_detail.current_year_month_1).toBe('0.0001') }) it('uses the independent lead summary and allocation endpoints', async() => { const allocation = { budget_submission: { application_basis: '依据', application_purpose: '目的', application_reason: '理由', project_content: '内容' }, department_allocations: [] } const summary = { applicationBasis: '依据', economicSummary: [{ categoryId: 10, totalAmount: '0.0001', fileIds: [2] }] } await saveDepartmentAllocations(12, allocation) await saveLeadDepartmentSummaryDraft(12, summary) await submitLeadDepartmentSummaryByPackage(12, summary) expect(request.mock.calls[0][0].data.application_basis).toBe('依据') expect(request.mock.calls[1][0].data.economic_summary[0]).toEqual(expect.objectContaining({ category_id: 10, total_amount: '0.0001', file_ids: [2] })) expect(request.mock.calls[2][0].url).toBe('/api/admin/lead-department-summary/12/submit') }) it('uses approval_notes for department and leader review requests', async() => { const review = { action: 'return', approval_notes: '补充材料' } await getDepartmentSubmissions({ package_id: 12 }) await reviewDepartmentSubmission(7, review) await reviewBudgetSubmission(8, review) await batchReviewBudgetSubmissions({ ids: [8, 9], ...review }) expect(request.mock.calls).toEqual([ [{ url: '/api/admin/department-submissions', method: 'get', params: { package_id: 12 }}], [{ url: '/api/admin/department-submissions/7/review', method: 'post', data: review }], [{ url: '/api/admin/budget-reviews/8/review', method: 'post', data: review }], [{ url: '/api/admin/budget-reviews/batch-review', method: 'post', data: { ids: [8, 9], ...review }}] ]) }) it('uses submission ids for leader review list and detail', async() => { await getBudgetReviews({ year_id: 3, page: 2, page_size: 15 }) await getBudgetReviewDetail(8) expect(request.mock.calls).toEqual([ [{ url: '/api/admin/budget-reviews', method: 'get', params: { year_id: 3, page: 2, page_size: 15 }}], [{ url: '/api/admin/budget-reviews/8', method: 'get' }] ]) }) it('maps leader review detail response fields to the page model', async() => { request.mockResolvedValueOnce({ submission: { id: 8, total_amount: '0.0001' }, department_summary: [{ id: 31, department_name: '执行科室', allocated_amount: '0.0001', submission_date: '2026-07-26 10:00:00' }] }) const result = await getBudgetReviewDetail(8) expect(result.departmentSummary[0]).toEqual(expect.objectContaining({ departmentName: '执行科室', allocatedAmount: '0.0001', submissionDate: '2026-07-26 10:00:00' })) }) })