## ADDED Requirements ### Requirement: Bulk Purchase Creation Form The admin frontend SHALL provide a bulk purchase form that binds one uploaded batch to one shop and one payment method. #### Scenario: Select batch purchase inputs - **GIVEN** 用户打开批量订购入口 - **WHEN** 用户填写批量订购表单 - **THEN** 页面 MUST require a target shop, one payment method, and an Excel file - **AND** 页面 MUST NOT provide a way to mix payment methods within the same batch #### Scenario: Show voucher upload for offline payment - **GIVEN** 用户选择线下支付 - **WHEN** 页面渲染批量订购表单 - **THEN** 页面 MUST show the batch voucher upload control - **AND** 页面 MUST require a completed voucher upload before task creation #### Scenario: Hide voucher upload for wallet payment - **GIVEN** 用户选择代理钱包支付 - **WHEN** 页面渲染或提交批量订购表单 - **THEN** 页面 MUST NOT submit a voucher file - **AND** 页面 MUST clear or ignore a voucher selected before switching to wallet payment ### Requirement: Bulk Purchase File Upload And Creation The admin frontend SHALL create a bulk purchase task through `POST /api/admin/bulk-purchases` using multipart form data. #### Scenario: Create bulk purchase task - **GIVEN** 用户已选择代理商、支付方式并完成文件上传 - **WHEN** 用户确认创建批量订购任务 - **THEN** 系统 MUST submit multipart fields `shop_id`, `payment_method`, `file`, and `request_id` - **AND** 系统 MUST submit `voucher_file` when the payment method is offline - **AND** 系统 MUST save the returned `task_id` and `task_no` #### Scenario: Prevent creation during upload - **GIVEN** Excel 文件或线下支付凭证仍在上传 - **WHEN** 用户点击创建任务 - **THEN** 页面 MUST prevent task creation - **AND** 页面 MUST show the upload-in-progress state until all required uploads finish #### Scenario: Download static template - **GIVEN** 用户打开批量订购表单 - **WHEN** 用户点击模板下载 - **THEN** 页面 MUST download the packaged frontend static Excel template - **AND** 页面 MUST NOT require a template-generation API request ### Requirement: Bulk Purchase Task Summary And Status The admin frontend SHALL display the server-provided bulk purchase task summary and use the shared five-state async task semantics. #### Scenario: Display task summary - **GIVEN** 批量订购任务创建成功或详情接口返回任务 - **WHEN** 页面展示任务详情 - **THEN** 页面 MUST display task ID or task number, status, total count, success count, failed count, and returned amount summaries - **AND** 页面 MUST use server-provided values without recalculating amounts or counts from the uploaded file #### Scenario: Treat partial success as terminal completion - **GIVEN** 任务已处理完成且同时存在成功行和失败行 - **WHEN** 页面展示任务状态 - **THEN** 页面 MUST display the task as a completed terminal task - **AND** 页面 MUST display success and failed counts separately - **AND** 页面 MUST NOT introduce a separate partial-success status #### Scenario: Handle wallet insufficiency without rollback - **GIVEN** 代理钱包余额不足导致部分或后续行无法创建订单 - **WHEN** 页面展示任务结果 - **THEN** 页面 MUST show the affected rows as failed with their returned reasons - **AND** 页面 MUST preserve and display rows that were already successful - **AND** 页面 MUST NOT attempt a frontend rollback ### Requirement: Bulk Purchase Task Recovery And Polling The admin frontend SHALL recover a bulk purchase task by `task_id` and poll its summary while it is active. #### Scenario: Query task summary - **GIVEN** 用户需要加载批量订购任务 - **WHEN** 页面查询任务摘要 - **THEN** 系统 MUST call `GET /api/admin/bulk-purchases/{task_id}` - **AND** 页面 MUST update the task summary from the response #### Scenario: Recover task after refresh - **GIVEN** 页面存在已保存的 active `task_id` - **WHEN** 用户刷新页面或重新进入批量订购任务页 - **THEN** 页面 MUST query the existing task by `task_id` - **AND** 页面 MUST NOT create another bulk purchase task #### Scenario: Stop polling at terminal state - **GIVEN** 批量订购任务状态为已完成、已失败或已取消 - **WHEN** 页面收到任务摘要 - **THEN** 页面 MUST stop automatic polling - **AND** 页面 MUST retain the terminal summary and failure counts for viewing ### Requirement: Bulk Purchase Item Results The admin frontend SHALL provide paginated and status-filterable row results for a bulk purchase task. #### Scenario: Query item results - **GIVEN** 用户打开批量订购任务结果 - **WHEN** 页面加载逐行结果 - **THEN** 系统 MUST call `GET /api/admin/bulk-purchases/{task_id}/items` - **AND** 系统 MUST support `page`, `size`, and optional `status` query parameters #### Scenario: Display failed item details - **GIVEN** 逐行结果接口返回失败行 - **WHEN** 页面渲染结果表格 - **THEN** 页面 MUST display row number, asset identifier, package code, and safe error reason - **AND** 页面 MUST NOT expose raw backend stack traces or technical error details ### Requirement: Bulk Purchase Permissions The admin frontend SHALL gate bulk purchase creation, task viewing, item-result viewing, and template download with explicit permissions. #### Scenario: Hide unauthorized bulk purchase operations - **GIVEN** 当前用户缺少某项批量订购权限 - **WHEN** 页面渲染对应入口或操作 - **THEN** 页面 MUST NOT display or enable that operation - **AND** direct API failure MUST NOT be treated as permission to continue