mcpField
E
education-cloud-academic-calendar-generate

education-cloud-academic-calendar-generate

github.com/forcedotcom生产力1.1k119 次安装1 天前更新
代码仓库

关于 education-cloud-academic-calendar-generate

此 Agent skill 根据日历文档或自然语言信息,为 Education Cloud 组织生成学年、学期和学期分段记录。它会校验日期、检查重复项,并在创建记录前要求确认。

主要功能

  1. 01解析文档或自然语言中的日历日期
  2. 02生成学年、学期和分段记录
  3. 03校验日期范围与层级关系
  4. 04检查重复学期并请求确认

适用场景

  1. 01为学期制或季度制整理学年日历
  2. 02从日历文档提取学期与注册日期
  3. 03创建并关联学年、学期和分段记录

MCP 相关

该 skill 通过 Salesforce REST API 操作 Education Cloud 记录,并要求先检查可用的 API 传输方式。它不要求或使用 MCP 服务的特定功能。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/forcedotcom/sf-skills --skill education-cloud-academic-calendar-generate

安装后在 Claude Code 中输入/education-cloud-academic-calendar-generate确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
quarter-calendar.json
sample-output.md
semester-calendar.json
references/
calendar-systems.md
date-validation.md
foundation_prerequisites.md
scripts/
validate_calendar_dates.py

详细介绍

Education Cloud 学术日历生成

为 Education Cloud 组织构建基础学术日历基础设施,从文档或自然语言中解析日历数据,并生成经过验证的 Academic Year、Academic Term 和 Academic Session 记录,确保日期范围和机构关联正确。

范围

  • 范围内:Academic Year 记录、Academic Term 记录(学期制/季度制/三学期制)、Academic Session 记录(学期细分)、注册窗口、加退课截止日期、日期验证
  • 范围外:课程排课(交由课程开设技能处理)、单个课程班级的日期、助学金截止日期、考试安排、机构层级设置(目前没有专门处理此事的技能 — 请手动设置 Accounts/校区)

执行模型

所有 Salesforce 操作都使用相对路径 REST 调用。不要使用 CLI 或 shell 命令访问 Salesforce(sf、sfdx、curl);执行环境可能不提供这些命令。这不适用于技能自带的本地验证脚本(scripts/validate_calendar_dates.py,见第 4 步)——该脚本在本地运行,且不会访问组织。

  • 记录 CRUD:sObject REST — POST /services/data/<ver>/sobjects/<Object>、GET /services/data/<ver>/sobjects/<Object>/<Id>、PATCH /services/data/<ver>/sobjects/<Object>/<Id>
  • 架构检查:sObject describe — GET /services/data/<ver>/sobjects/<Object>/describe(写入前确认对象和字段 API 名称存在)。
  • SOQL /query 可路由:GET /services/data/<ver>/query,将 SOQL 作为结构化的 queryParams: {"q": "..."} 传入,不要将其内联到 URL 中作为 ?q=... — 实测已确认:通过 headless-360 分发时,内联 ?q= 会返回 404(ROUTE_NOT_FOUND/NOT_FOUND),而使用 queryParams 可稳定返回 200。可用它扫描现有学期/学期时段,或使用创建时捕获的运行时 Id 查找记录,并通过直接调用 GET .../sobjects/<Object>/<Id> 读取记录 — 两种方式均有效。
  • 所有 Id 都是运行时变量,从创建响应的 body.id 中捕获 — 绝不要硬编码 Salesforce Id 字面值。
  • 动态解析 API 版本 — 参见下文“执行传输”。不要硬编码版本。

必需输入

继续操作前,收集或推断以下信息:

  • 日历体系:Semester(秋季/春季/夏季)、Quarter(秋季/冬季/春季/夏季)或 Trimester
  • 学年跨度:整个学年的开始和结束日期
  • 学期日期:每个学期的上课开始/结束日期、注册开放日期、加退课截止日期
  • 学期时段细分:学期内的任何子时段(例如,夏季第 1 学期时段和第 2 学期时段)

如果用户提供日历文档(PDF、CSV、电子表格),请解析并提取所有日期。如果用户提供自然语言描述,请先询问具体日期再继续。

注意:AcademicYear、AcademicTerm 和 AcademicSession 均没有 Account 引用字段 — 日历记录不会关联到 Business Account。关联关系仅限 Year → Term(AcademicYearId)和 Term → Session(AcademicTermId)。

除非另有说明,否则使用以下默认值:

  • 日历体系:Semester(秋季、春季、夏季)
  • 学年命名:“Academic Year YYYY-YYYY” 格式
  • 注册窗口:在学期开始前 3-4 个月开放
  • 加退课截止日期:学期开始后 2 周

执行传输

  1. 解析 API 版本:通过 headless-360 调度调用 GET /services/data/(未指定版本)。响应是一个端点路径映射,这些路径已解析为组织当前支持的最高版本(例如 "limits": "/services/data/v69.0/limits"),而不是包含 version 字段的数组。从任意返回路径中提取版本(正则表达式 v\d+\.\d+),并将其用作下文所有调用的 <ver>。
  2. 探测传输健康状态:通过 headless-360 调度调用 GET /services/data/<ver>/limits。返回 2xx → 所有调用都通过它路由。若缺失/返回 4xx/5xx → 使用相同的读取操作探测其他可用传输方式(其他 Salesforce MCP、已认证的 sf CLI、自定义 MCP),并使用第一个健康的传输方式,同时告知用户。没有健康的传输方式 → 停止,请用户连接一个;绝不捏造。

工作流

所有步骤都必须按顺序执行。若遇到阻碍,请停止并询问缺失的上下文。

  1. 验证基础前提——遵循 references/foundation_prerequisites.md:组织版本、Lightning Experience、Education Cloud 许可证、当前运行用户的 EDU 访问权限、Education Cloud Foundation 已启用(若未启用,先确认再启用以自行修复)。在所有检查通过之前,不要继续执行步骤 1。

  2. 确认校历制度

    • 询问用户:采用学期制、季度制还是三学期制?
    • 根据制度类型确定预期的学期名称
  3. 收集校历数据

    • 如果用户提供文档(PDF、CSV、电子表格):解析并提取年份、学期和课程时段日期
    • 如果用户用自然语言提供信息:从描述中提取日期
    • 如果信息不足:询问具体日期(学期开始/结束日期、注册窗口、截止日期)
  4. 验证对象和字段架构

    • 写入之前,确认组织中存在你将设置的每个对象和字段: GET /services/data/<ver>/sobjects/AcademicYear/describe、.../AcademicTerm/describe、.../AcademicSession/describe
    • 读取 fields 数组;将计划使用的字段 API 名称(Name、AcademicYearId、StartDate、EndDate、RegistrationOpenDate、RegistrationCloseDate、Season、AcademicTermId、ClassStartDate、ClassEndDate、AddDropDeadline)与其进行匹配。
    • 注意,选项列表字段 Season(AcademicTerm.Season,取值为 Fall/Spring/Summer/Winter):只发送该字段 picklistValues 中存在的值。AcademicSession.Type 是另一个选项列表字段(Semester/Trimester/Quarter 等),此工作流不会用到——不要将它与 Season 混淆。
    • 如果字段不存在:立即停止——不要使用未经验证的字段名称执行 POST;向用户报告不匹配情况。
  5. 验证日期范围

    • 将收集到的年份/学期/课程时段数据整理为 scripts/validate_calendar_dates.py 顶部所述的 JSON 格式,然后运行一次:
      python3 scripts/validate_calendar_dates.py <<'EOF'
      {"academicYear": {...}, "terms": [...], "sessions": [...]}
      EOF
      
    • 该脚本会检查学期结束日期是否晚于开始日期、学年是否涵盖所有学期、注册开放日期是否早于学期开始日期、选课增退截止日期是否在学期范围内、课程时段是否包含在其所属学期内,并计算每个学期的 RegistrationCloseDate。
    • 如果 valid 为 false:停止,向用户报告 errors 中的每条内容,并要求提供更正后的日期。不要继续执行步骤 5。
    • warnings(例如有意设置的课程时段重叠)不会阻止流程——在步骤 6 中将每条警告告知用户以便确认。
    • 保留 computedRegistrationCloseDates 供后续使用——步骤 8 将使用它,而不是重新计算。
  6. 检测重复学期

    • AcademicTerm 的 Name 未设置唯一约束,因此插入重复名称不会报错。创建前,扫描列表以查找名称匹配的现有学期:使用 GET /services/data/<ver>/query,并设置 queryParams: {"q": "SELECT Id, Name, StartDate, EndDate FROM AcademicTerm WHERE Name = 'Fall 2025'"} — 通过 queryParams 传递 SOQL,不要将其内联到 URL 的 ?q= 中(内联会返回 404)— 或者,如果用户在本次会话中之前已为今年创建过日历,则重用当时记录的 Id,而不是重新创建。
    • 如果发现重复名称,请比较日期,并询问用户是更新现有记录还是跳过。
    • 如果重复项检查读取本身失败(非 2xx、传输错误):停止 — 不要继续创建学期。向用户报告失败,并询问如何继续;不要在未告知的情况下创建可能重复的记录。
  7. 展示拟创建的日历结构并确认

    • 展示将要创建内容的摘要:学年名称和日期,然后列出每个学期的名称/日期/注册时间窗口/计算出的 RegistrationCloseDate,再按所属学期分组列出每个课期的名称和日期。已填好的示例见 examples/sample-output.md。
    • 对于步骤 4 中的每条课期重叠警告:说明重叠时段,并询问用户是否确认这是有意安排的。
    • 询问用户:“我应该创建所有这些记录吗?”
    • 等待用户确认后,再继续步骤 7
  8. 创建 Academic Year 记录

    • 用户在步骤 6 确认后,插入 Academic Year:
      POST /services/data/<ver>/sobjects/AcademicYear
      {"Name": "Academic Year 2025-2026"}
      
    • 从响应的 body.id 中获取 academicYearId,用于关联学期
    • 报告:“已创建 Academic Year:Academic Year 2025-2026”
  9. 创建 Academic Term 记录

    • 对每个学期(Fall、Spring、Summer 或对应的 Quarter),插入记录,并将 AcademicYearId 设置为步骤 7 中的 academicYearId:
      POST /services/data/<ver>/sobjects/AcademicTerm
      {"Name": "Fall 2025", "Season": "Fall", "StartDate": "2025-08-18", "EndDate": "2025-12-12",
       "AcademicYearId": "<academicYearId>",
       "RegistrationOpenDate": "2025-04-01", "RegistrationCloseDate": "2025-08-17"}
      
      • RegistrationCloseDate 取自步骤 4 的 computedRegistrationCloseDates[<term name>] — 不要手动重新计算。
      • Season 是受限选项列表:Fall、Spring、Summer、Winter。AcademicTerm 没有 add/drop 字段 — add/drop 截止日期仅属于 AcademicSession。
    • 从响应的 body.id 中获取每个 termId,用于关联课期
    • 报告进度:“已创建 3 个学期:Fall 2025、Spring 2026、Summer 2026”
  10. 创建 Academic Session 记录

    • 对每个课期细分(例如 Summer Session 1、Summer Session 2),插入记录,并将 AcademicTermId 设置为步骤 8 中所属学期的 termId:
      POST /services/data/<ver>/sobjects/AcademicSession
      {"Name": "Summer Session 1", "ClassStartDate": "2026-05-26", "ClassEndDate": "2026-07-03",
       "AddDropDeadline": "2026-06-11", "AcademicTermId": "<termId>"}
      
    • 报告进度:“已创建 2 个课期:Summer Session 1、Summer Session 2”
  11. 生成完成摘要

    • 展示最终摘要:已创建的 Academic Year 及其日期、每个已创建 Term 的日期范围,以及按所属 Term 分组的每个已创建 Session,并附上一行说明 Year → Term → Session 的关联关系。已填好的示例见 examples/sample-output.md。
    • 如果存在课期重叠(根据步骤 4 的警告),注明重叠时段以及已确认这是有意安排的。
    • 如果有学期因重复而跳过,列出这些学期及原因

按需验证

第 10 步之后随时可用,不是必需的工作流步骤——仅在用户要求抽查记录或查看日历范围时使用。

  • 特定记录(例如,“显示我 2025 年秋季学期的信息”):通过已捕获的 Id 冷读记录 — GET /services/data/<ver>/sobjects/AcademicTerm/<termId>(返回所有字段;不要使用 ?fields= 选择器)— 或者,如果未捕获 Id,则通过名称查找:GET /services/data/<ver>/query,并使用 queryParams: {"q": "SELECT Id FROM AcademicTerm WHERE Name = 'Fall 2025'"}(通过 queryParams 传入 SOQL,不要将其内联为 URL 中的 ?q= — 内联会导致 404)。以表格形式显示所有字段值,并包含父级层次结构。
  • 日历视图(例如,“显示 2026 年夏季学期的所有日期”):通过已捕获的 Id 冷读学期及其每个子课期 — GET /services/data/<ver>/sobjects/AcademicTerm/<termId> 和 GET /services/data/<ver>/sobjects/AcademicSession/<sessionId> — 并以表格显示(记录类型、名称、开始日期、结束日期、时长、注册开放时间、注册截止时间、选课增退截止时间)。如适用,计算并显示重叠时段。请参阅 examples/sample-output.md 查看已填写的示例。

规则 / 约束

约束原因
写入前通过 describe 验证对象和字段 API 名称避免因字段未验证而导致 POST 失败;Season 选项列表值必须与 AcademicTerm.Season 的 picklistValues 匹配
学期结束日期必须晚于开始日期平台验证会拒绝无效的日期范围
注册窗口必须在学期开始前开放学生不能在课程开始后注册
选课增退截止日期(位于 AcademicSession 上)必须晚于或等于学期开始日期课程开始前的截止日期在逻辑上无效;AcademicTerm 没有选课增退字段
学年必须涵盖其所有子学期学期日期超出学年范围会导致报告问题
同一学期内的课期允许重叠夏季课期的常见安排(例如,课期 1:5 月至 7 月,课期 2:6 月至 8 月)
学期名称应符合日历系统惯例学期制使用秋季 / 春季 / 夏季,季度制使用秋季 / 冬季 / 春季 / 夏季
动态解析 API 版本,不要硬编码组织的最高 API 版本会随时间变化;过时的硬编码版本会与组织当前版本脱节
创建前通过 SOQL /query 检查是否存在重复学期,并通过 queryParams 传入 q,不要将其内联在 URL 中/query 可通过 headless-360 路由,但仅支持使用 queryParams — 内联 ?q= 会导致 404(已通过实时测试确认);学期 Name 没有唯一性约束,因此插入时不会因重复而报错;重复检查读取失败时必须阻止创建,不得跳过

注意事项

问题解决方法
用户提供相对日期(“下一个秋季学期”)插入前转换为绝对日期(例如,“下一个秋季学期” → “2026 年秋季学期”,并填写具体日期)
重叠课期被标记为错误向用户确认 — 许多院校会有意安排课期重叠(例如,夏季课期 1 和 2 重叠 1 周)
存在日期不同的重复学期询问用户是更新现有记录还是跳过 — 未经确认不得自动更新
注册窗口在学期开始之后这是无效的 — 请用户提供正确的注册开放日期
学年结束日期早于最后一个学期的结束日期延长学年以涵盖所有学期,或调整学期日期
输入包含学期级别的选课增退日期,但没有课期细分AcademicTerm 没有选课增退字段 — 向用户说明学期级别与课期级别的字段归属,或建议为每个学期创建一个课期以记录该日期;绝不能将其写入 AcademicTerm,也绝不能悄悄忽略
用户提供三段式年份范围(2025-2026-2027)向用户澄清 — 学年恰好跨度为 2 年(例如,2025-2026)
课期没有父级学期每个课期都必须关联一个学期 — 如果用户提供课期日期但未指定学期,请询问该课期属于哪个学期

输出预期

交付内容:

  • Academic Year 记录:覆盖所有学期的单条年份记录(例如:“Academic Year 2025-2026”)
  • Academic Term 记录:每年 3-4 条学期记录(学期制为秋季、春季、夏季;季度制为秋季、冬季、春季、夏季)
  • Academic Session 记录:0-N 条课程阶段记录(学期制系统通常有 2 条夏季课程阶段记录)
  • 汇总报告:列出所有已创建记录的表格,包含名称、日期和关联关系

学期通过 AcademicYearId 关联到上级 Academic Year;课程阶段通过 AcademicTermId 关联到上级学期。这些对象没有 Account 引用字段。


跨技能集成

需求委派给
机构层级(Accounts、校区)暂无专用技能 — 手动设置
课程排期和开课信息课程开课信息生成技能

参考文件索引

文件阅读时机
references/foundation_prerequisites.md步骤 0 — 组织版本、Lightning Experience、EDU 许可证、权限集分配、启用 Education Cloud Foundation;每次单独调用时,都应在步骤 1 之前运行
references/calendar-systems.md用户的日历系统不明确或不标准时
references/date-validation.md验证复杂日期重叠或多课程阶段学期时
examples/semester-calendar.json验证学期制系统的输出结构
examples/quarter-calendar.json验证季度制系统的输出结构
examples/sample-output.md查看拟议结构展示、完成摘要和日历视图表格的完整示例
scripts/validate_calendar_dates.py在步骤 4 中调用,以验证日期范围并确定性地计算 RegistrationCloseDate

评论

支持 Markdown