from __future__ import annotations

from pathlib import Path

from openpyxl import Workbook
from openpyxl.styles import Alignment, Font, PatternFill
from openpyxl.utils import get_column_letter


ROOT = Path(__file__).resolve().parents[1]
OUTPUT = ROOT / "SaaS_订阅邀请登录_测试功能点.xlsx"


COLUMNS = [
    "功能点编号",
    "一级模块",
    "二级功能点",
    "角色/入口",
    "前置条件",
    "操作/触发",
    "核心校验点",
    "优先级",
    "自动化建议",
    "备注/需求依据",
]


ROWS = [
    ("SUB-FP-001", "SaaS-admin 产品管理", "产品列表搜索", "SaaS-admin / 产品管理-产品列表", "存在不同产品、业务类型、状态、创建时间数据", "按产品编码精确搜索、产品名称模糊搜索、业务类型多选、状态多选、创建时间范围搜索", "未输入条件默认全部；编码精确匹配；名称支持前中后模糊；多选条件组合过滤正确", "P0", "可自动化", "5.2 产品列表"),
    ("SUB-FP-002", "SaaS-admin 产品管理", "产品列表字段展示", "SaaS-admin / 产品管理-产品列表", "存在产品数据", "进入产品列表", "展示产品编号、名称、开通方式、提供方类型、状态、描述、版本数量、订阅租户数、创建/更新时间", "P1", "可自动化", "5.2 产品列表字段"),
    ("SUB-FP-003", "SaaS-admin 产品管理", "新增产品基础信息校验", "SaaS-admin / 添加产品", "管理员进入添加产品页", "填写产品名称、提供方类型、Logo、描述、支付方式、允许购买商户类型、自动续费/续费提醒", "必填校验；产品名唯一且不超过20字；描述不超过200字；Logo仅支持JPG/PNG；续费提醒字段按到期提醒联动显示", "P0", "可自动化", "5.2.1.1 产品基础信息字段"),
    ("SUB-FP-004", "SaaS-admin 产品管理", "产品保存草稿/下一步", "SaaS-admin / 添加产品", "产品基础信息填写中", "点击取消、保存草稿、下一步", "取消有确认；保存草稿保留数据；下一步校验必填后进入订阅版本配置", "P1", "可自动化", "5.2.1.1 操作按钮"),
    ("SUB-FP-005", "订阅版本配置", "新增订阅版本字段校验", "SaaS-admin / 产品版本配置", "产品基础信息已填写", "新增版本并填写版本名称、图标、描述、开通方式、基准月价、成员限制、试用天数、订阅时长、应用配置", "版本名称产品内唯一；基准月价为数字；成员限制最大999999；试用天数0表示不支持试用；至少一个订阅时长；至少一个应用", "P0", "可自动化", "5.2.1.2 订阅版本配置"),
    ("SUB-FP-006", "订阅版本配置", "订阅时长和折扣价格计算", "SaaS-admin / 版本配置-订阅时长列表", "版本已填写基准月价", "新增/删除订阅时长，填写折扣", "实际价格=基准月价*时长*折扣并保留两位小数；删除时至少保留一个订阅时长，否则提示“请最少保留一个订阅时长”", "P0", "可自动化", "5.2.1.2 订阅时长与折扣"),
    ("SUB-FP-007", "订阅版本配置", "应用配置选择", "SaaS-admin / 版本配置-应用配置", "应用管理中存在应用数据", "按应用名称/编码模糊搜索并添加到已选应用，删除已选应用", "可选应用来源正确；搜索过滤正确；添加后进入已选；删除后移出；发布前至少保留一个应用", "P0", "可自动化", "5.2.1.2 应用配置"),
    ("SUB-FP-008", "订阅版本配置", "版本卡片操作", "SaaS-admin / 版本卡片列表", "产品下存在多个版本", "编辑、删除、复制、启用/禁用、拖拽排序版本", "版本卡片显示名称、基准月价、成员限制；复制生成副本；排序影响官网展示顺序；启禁用影响新客购买入口", "P1", "部分自动化", "5.2.1.2 版本列表+卡片"),
    ("SUB-FP-009", "产品发布状态机", "新建产品发布/上架", "SaaS-admin / 创建或编辑产品页", "产品基础信息完整，至少1个启用且配置完整的版本", "点击发布/上架并确认", "校验基础信息、启用版本、价格、成员、存储、试用天数、订阅期限、应用；订阅开通产品还需支付方式和官网展示信息；成功后状态为已上架", "P0", "可自动化", "3.1、5.2.1.3、5.2.2"),
    ("SUB-FP-010", "产品发布状态机", "已上架产品下架", "SaaS-admin / 产品列表或详情", "产品状态为已上架", "点击下架并确认风险提示", "状态变为已下架；官网订阅页不再展示；存量订阅权益不受影响直到到期；后台仍可查询", "P0", "可自动化", "5.1、5.2.2"),
    ("SUB-FP-011", "产品发布状态机", "已下架产品重新上架", "SaaS-admin / 产品列表或详情", "产品状态为已下架", "点击上架", "同发布校验；配置缺失时提示补全；成功后状态变为已上架并按开通方式恢复生效", "P0", "可自动化", "5.2.2"),
    ("SUB-FP-012", "产品发布状态机", "购买链路中产品下架校验", "官网购买/支付链路", "用户已进入购买流程，管理员可能下架产品", "确认页、提交订单、支付前、支付回调各节点校验产品状态", "未支付前产品下架则提示“该产品已下架，暂不支持购买，请返回重新选择”；已支付成功但回调发现下架仍按订单快照开通", "P0", "需联调/可接口自动化", "5.1 正在购买时下架"),
    ("SUB-FP-013", "产品编辑/删除", "编辑产品", "SaaS-admin / 产品编辑页", "产品存在且允许编辑", "修改产品基础字段并保存", "字段校验同新增；保存成功后进入详情并回显；产品名称/支付方式变更需通知用户；历史订单和订阅快照不自动变更", "P1", "可自动化", "5.2.3 编辑产品"),
    ("SUB-FP-014", "产品编辑/删除", "删除产品", "SaaS-admin / 产品列表或详情", "产品存在", "点击删除", "有订阅记录时提示“产品已有订阅记录，不允许删除，请下架产品”；无订阅记录可逻辑删除", "P0", "可自动化", "5.2.4 删除产品"),
    ("SUB-FP-015", "功能对比配置", "配置版本功能对比表", "SaaS-admin / 功能对比配置", "产品存在多个版本或应用权益", "配置官网订阅与定价页版本对比内容", "配置后前端产品-版本功能对比展示正确", "P1", "部分自动化", "5.2.6 功能对比配置"),
    ("SUB-FP-016", "版本管理", "已上架版本编辑权益影响", "SaaS-admin / 版本管理", "产品版本存在，可能已有老客户订阅", "增加应用、删除应用、修改价格/成员等配置并保存", "增加应用时老客户自动免费获得；删除应用时老客户保留原应用直到到期；涨价/降价不影响老客户历史价格；系统提示内容正确", "P0", "需数据准备/可自动化", "5.2.7 版本管理"),
    ("SUB-FP-017", "版本管理", "删除订阅版本", "SaaS-admin / 版本管理", "产品下存在版本", "点击删除版本并确认", "删除版本解除方案与产品关联；历史订购客户不受影响；若产品只有一个版本不允许删除", "P0", "可自动化", "5.2.1.3、5.2.8"),
    ("SUB-FP-018", "版本管理", "启用/禁用订阅版本", "SaaS-admin / 版本管理", "版本存在", "点击启用或禁用并确认", "状态变更成功；禁用版本不出现在客户产品订阅页；现有订阅者服务不受影响直到到期；后台仍可查询", "P0", "可自动化", "5.2.9"),
    ("SUB-FP-019", "到期提醒", "订阅到期短信提醒", "系统定时任务/短信通知", "产品配置到期提醒规则，订阅即将到期或已到期", "触发到期前、到期当天提醒", "按配置时间点发送到SAAS用户主账号手机号；短信模板变量产品名称、用户姓名、套餐名称、日期、短链接正确", "P1", "接口/任务自动化", "5.2.10 到期提醒"),
    ("SUB-FP-020", "到期提醒", "续费成功确认通知", "支付回调/续费成功后", "用户续费成功", "触发续费成功通知", "短信包含产品名、套餐名称、新到期日；订阅有效期已延长", "P1", "接口自动化", "5.2.10 到期提醒"),
    ("SUB-FP-021", "订阅订单", "订阅订单列表查询与导出", "SaaS-admin / 产品管理-订阅订单", "存在官网购买、免费试用、指定开通、默认开通订单", "进入列表、筛选、导出、查看详情", "默认按订单创建时间近3个月降序；导出字段包含支付单号、支付方式、支付状态、开通用户等；详情展示订单完整信息及支付流水", "P0", "可自动化", "5.3 订阅订单列表"),
    ("SUB-FP-022", "订阅订单", "支付状态流转", "SaaS-admin / 订阅订单", "订单存在不同支付状态", "创建待支付订单、支付成功、超时/取消/关闭、支付失败", "支付状态支持无需支付、待支付、已支付、已取消/已关闭、支付失败；待支付1小时关单；待支付不产生有效订阅", "P0", "接口/时间模拟自动化", "5.3 订阅订单列表"),
    ("SUB-FP-023", "订阅订单", "订阅状态判断", "SaaS-admin / 订阅订单", "存在试用、生效、即将到期、过期订阅", "查看订阅状态", "免费试用/试用中、生效中、即将到期并展示剩余天数、已过期、未生效状态判断正确", "P0", "可自动化", "5.3 订阅订单列表"),
    ("SUB-FP-024", "产品日志", "产品变更日志查询", "SaaS-admin / 产品日志", "存在产品新增、更新、新增版本日志", "按产品名称、操作人、提交类型、提交时间搜索", "搜索过滤正确；列表展示产品名称、版本号、包含应用、产品ID、操作人、提交类型、提交时间", "P1", "可自动化", "5.4 产品日志"),
    ("SUB-FP-025", "官网订阅购买", "官网价格页展示", "官网 / SaaS价格页", "存在已上架且开通方式为订阅开通的产品", "进入官网价格页", "仅展示已上架且订阅开通产品；展示产品Tab、版本图标/名称/描述、订阅时长、价格、折扣标识、到期时间、支付方式、订阅提示、服务协议", "P0", "可自动化", "6 官网订阅购买流程"),
    ("SUB-FP-026", "官网订阅购买", "立即购买前置校验", "官网 / 立即购买", "用户选择订阅产品", "未登录点击购买；未选择订阅服务/时长/支付方式/服务协议；配置被后台变更", "未登录跳转登录且成功后回到购买上下文；缺失项提示“请选择XXXX”；产品内容变更提示“产品内容已更新，请刷新重试”", "P0", "可自动化", "6 立即购买按钮"),
    ("SUB-FP-027", "官网订阅购买", "付费购买支付流程", "官网 / 支付页", "用户已通过购买校验，产品价格大于0", "选择微信扫码或支付宝扫码支付，确认支付结果", "校验成功跳转支付页；支付结果确认弹窗行为正确；支付成功后开通订阅并更新人数上限、应用权益、订阅到期时间", "P0", "需支付沙箱/可半自动", "3.2、6 支付流程"),
    ("SUB-FP-028", "官网订阅购买", "0元产品直接开通", "官网 / 立即购买", "产品实际价格为0", "点击立即购买并通过校验", "不拉起支付，直接进入开通成功页；产生无需支付订单和有效订阅", "P0", "可自动化", "6 立即购买按钮"),
    ("SUB-FP-029", "免费试用", "申请免费试用", "官网 / 免费试用", "产品配置免费试用天数>=1", "点击免费试用", "未登录先登录；校验账号/租户试用资格；符合规则开通试用订阅并按试用版本限制权益", "P0", "可自动化", "3.3、6 免费试用流程"),
    ("SUB-FP-030", "免费试用", "试用转付费与到期限制", "官网/企业管理 / 订阅管理", "租户处于试用期或试用已到期", "试用期内购买付费套餐；试用到期未付费继续访问系统", "试用期内可转付费；到期未付费按到期规则限制使用", "P0", "需时间模拟/可自动化", "3.3、6 免费试用流程"),
    ("SUB-FP-031", "购买身份校验", "主账号与商户认证校验", "官网 / 点击购买", "存在主账号、子账号、已认证/未认证商户", "不同身份点击购买", "必须为主账号且完成商户认证；不满足时阻止购买并提示", "P0", "可自动化", "6 身份校验"),
    ("SUB-FP-032", "订阅周期", "自然月到期时间计算", "订阅开通/续费", "存在月付、季付、年付订阅", "在不同日期开通订阅", "月付顺延1个自然月，季付3个月，年付12个月；目标月份不存在对应日期时取目标月份最后一天；闰年2月29日处理正确", "P0", "接口/单元自动化", "3.4 订阅周期"),
    ("SUB-FP-033", "订阅升级/调整", "同一产品仅一个生效版本", "后台调整订阅/用户升级订阅", "同一商户已有某产品基础版生效", "升级购买企业版或管理员手动调整版本", "同一商户同一产品同一时间只允许一个生效版本；升级后当前生效版本立即切换到新版本", "P0", "接口/业务自动化", "3.5 订阅更换产品版本"),
    ("SUB-FP-034", "开通方式", "指定开通", "SaaS-admin / 版本管理-指定开通", "产品已上架，版本启用且配置完整，开通方式为指定开通", "点击指定开通，选择商户并提交", "指定开通按钮仅SaaS-admin可见且仅指定开通版本展示；开通前校验产品状态、版本状态和配置完整性；不在官网展示", "P0", "可自动化", "5.2 开通方式区分"),
    ("SUB-FP-035", "开通方式", "默认开通", "购买其他产品触发", "存在默认开通产品", "用户购买其他产品成功", "默认开通产品不对外展示；跟随购买产品的订阅时间开通；开通新产品会更新默认开通产品", "P1", "接口/业务自动化", "5.2 开通方式区分"),
    ("SUB-FP-036", "企业管理", "续费/增购授权时间关联", "企业管理 / 续费、增购", "丸友集或丸掌柜存在授权时间和版本订阅时间", "执行续费或增购", "应用授权时间与版本订阅时间保持关联一致", "P1", "待需求补充", "7 企业管理"),
    ("SUB-FP-037", "商户认证优化", "认证详情字段展示", "SaaS-admin / 商户管理-商户认证-查看", "存在企业商户和个体工商户认证数据", "查看认证详情", "企业商户展示认证资质图片、补充说明等完整审核信息；个体工商户展示经营规模、认证资质图片、补充说明等字段", "P0", "可自动化", "8 商户认证优化"),
    ("SUB-FP-038", "商户认证优化", "审核拒绝后重新认证", "SaaS / 商户认证", "认证记录已被拒绝", "重新提交认证资料", "支持重新认证；提交后新增一条认证数据，不覆盖原拒绝记录", "P0", "可自动化", "8 商户认证优化"),
    ("SUB-FP-039", "权限管理", "角色权限控制菜单", "SaaS-admin / 系统管理-角色管理", "存在不同角色权限配置", "切换角色登录或调整菜单权限", "页面菜单受角色权限控制，授权菜单可见，未授权菜单不可见", "P1", "可自动化", "8 角色权限说明"),
    ("SUB-FP-040", "登录样式", "登录页动态主题与默认样式", "登录页 / URL code", "存在方案code或异常code", "通过不同code访问登录页；模拟配置为空或网络错误", "根据code展示方案名称、Logo、主题色；异常时展示默认登录样式", "P2", "暂不自动化", "9 登录章节标注“不做”，仅保留观察项"),
]


SUMMARY_ROWS = [
    ("SaaS-admin 产品管理", 14, "产品列表、新增/编辑/删除、发布/上下架、状态机、购买中下架校验"),
    ("订阅版本配置/管理", 7, "版本字段、时长折扣、应用权益、复制排序、启禁用、删除、老客户权益影响"),
    ("订阅订单/日志/提醒", 6, "订单状态、订阅状态、导出详情、产品日志、到期和续费通知"),
    ("官网购买/免费试用", 8, "价格页展示、购买校验、支付、0元开通、试用、身份认证、周期计算、升级"),
    ("后台指定/默认开通", 2, "指定商户开通、默认开通联动"),
    ("企业/认证/权限/登录观察", 3, "续费增购时间关联、商户认证优化、角色权限；登录暂不做"),
]


def style_sheet(ws) -> None:
    header_fill = PatternFill("solid", fgColor="1F4E78")
    header_font = Font(color="FFFFFF", bold=True)
    for cell in ws[1]:
        cell.fill = header_fill
        cell.font = header_font
        cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
    widths = [14, 20, 28, 28, 32, 36, 48, 10, 16, 34]
    for index, width in enumerate(widths, 1):
        ws.column_dimensions[get_column_letter(index)].width = width
    for row in ws.iter_rows(min_row=2):
        for cell in row:
            cell.alignment = Alignment(vertical="top", wrap_text=True)
    ws.freeze_panes = "A2"
    ws.auto_filter.ref = ws.dimensions


def main() -> None:
    wb = Workbook()
    ws = wb.active
    ws.title = "测试功能点"
    ws.append(COLUMNS)
    for row in ROWS:
        ws.append(row)
    style_sheet(ws)

    summary = wb.create_sheet("功能点汇总")
    summary.append(["一级模块", "功能点数", "覆盖说明"])
    for row in SUMMARY_ROWS:
        summary.append(row)
    for cell in summary[1]:
        cell.fill = PatternFill("solid", fgColor="548235")
        cell.font = Font(color="FFFFFF", bold=True)
        cell.alignment = Alignment(horizontal="center")
    summary.column_dimensions["A"].width = 26
    summary.column_dimensions["B"].width = 12
    summary.column_dimensions["C"].width = 70
    for row in summary.iter_rows(min_row=2):
        for cell in row:
            cell.alignment = Alignment(vertical="top", wrap_text=True)

    wb.save(OUTPUT)
    print(OUTPUT)


if __name__ == "__main__":
    main()
