========================================================================
充值/扣款申请「预约执行时间」- 定时任务/菜单权限手工添加清单 (2026-09-24)
========================================================================

说明：以下内容需要管理员在对应环境手工添加（ Quartz 任务管理页或直接执行 SQL、
UPMS 管理端「菜单管理」）。SQL 按租户幂等，风格与 db/20260920_饭卡卡面模板菜单权限.txt 一致。
注意库名：sys_job 在 `pjcloudx_job` 库（与 qrtz_* / sys_job_log 同库）；sys_menu 在 `pjcloudx` 库。

前置条件：
  1. 先执行 db/20260924_add_wallet_recharge_apply_reserve_exec.sql（加列 + 扫描索引 + 对账差异表）；
  2. 部署包含本次改动的 pjcloud-wallet-biz 与 pjcloud-daemon-quartz 服务；
  3. 两条 sys_job 使用 job_status='2'（运行中），daemon-quartz 重启时由
     PjcloudInitQuartzJob 自动注册进 Quartz；服务不重启可调管理端
     POST /sys-job/refresh-jobs（权限 job_sys_job_refresh_job）手动加载。

功能说明：
  预约执行到期任务：每 10 分钟扫描「已审批通过 + 预约时间已到 + 未执行完」的充值/扣款申请，
  按明细幂等执行（CAS 抢占防并发，失败退避重试，耗尽转终态等人工）。
  预约执行对账任务：每 10 分钟（错开 5 分钟）复核近 7 天预约单「申请明细 ↔ 钱包流水」一致性，
  差异落 wallet_recharge_exec_check 表，修复后自动恢复，页面人工闭环。

------------------------------------------------------------------------
一、sys_job：钱包预约充值到期执行（job_type=2，反射调 daemon 内 spring bean）
------------------------------------------------------------------------

INSERT INTO `pjcloudx_job`.`sys_job`
(`job_id`, `job_name`, `job_group`, `job_order`, `job_type`, `execute_path`, `class_name`, `method_name`,
 `method_params_value`, `cron_expression`, `misfire_policy`, `job_tenant_type`, `job_status`,
 `job_execute_status`, `create_by`, `create_time`, `update_by`, `update_time`, `tenant_id`, `remark`)
SELECT (SELECT GREATEST(COALESCE(MAX(`job_id`), 0), 2026092400000000000) FROM `pjcloudx_job`.`sys_job`) + 1,
       '钱包预约充值到期执行', 'WALLET', '1', '2', NULL, 'walletReserveTask', 'executeDueApplies',
       NULL, '0 */10 * * * ?', '3', '1', '2',
       '0', 'system', NOW(), 'system', NOW(), 1, '每10分钟扫描到期预约充值/扣款申请并幂等执行'
FROM DUAL
WHERE NOT EXISTS (
    SELECT 1 FROM `pjcloudx_job`.`sys_job`
    WHERE `job_name` = '钱包预约充值到期执行' AND `job_group` = 'WALLET' AND `tenant_id` = 1
);

------------------------------------------------------------------------
二、sys_job：钱包预约充值对账（同 bean 第二个方法，错开 5 分钟）
------------------------------------------------------------------------

INSERT INTO `pjcloudx_job`.`sys_job`
(`job_id`, `job_name`, `job_group`, `job_order`, `job_type`, `execute_path`, `class_name`, `method_name`,
 `method_params_value`, `cron_expression`, `misfire_policy`, `job_tenant_type`, `job_status`,
 `job_execute_status`, `create_by`, `create_time`, `update_by`, `update_time`, `tenant_id`, `remark`)
SELECT (SELECT GREATEST(COALESCE(MAX(`job_id`), 0), 2026092400000000000) FROM `pjcloudx_job`.`sys_job`) + 2,
       '钱包预约充值对账', 'WALLET', '2', '2', NULL, 'walletReserveTask', 'reconcile',
       NULL, '5 */10 * * * ?', '3', '1', '2',
       '0', 'system', NOW(), 'system', NOW(), 1, '每10分钟复核近7天预约单明细与钱包流水一致性'
FROM DUAL
WHERE NOT EXISTS (
    SELECT 1 FROM `pjcloudx_job`.`sys_job`
    WHERE `job_name` = '钱包预约充值对账' AND `job_group` = 'WALLET' AND `tenant_id` = 1
);

------------------------------------------------------------------------
三、按钮权限：充值/扣款申请「预约执行」「立即执行」（挂在充值申请页面菜单下）
------------------------------------------------------------------------

「预约执行」控制新增/编辑表单里的预约执行开关与时间控件（前端显隐 + 后端字段校验双重控制，
无权限用户提交的预约设置会被后端忽略或强制关闭）。「立即执行」是待执行/失败单的人工兜底入口。

INSERT INTO `pjcloudx`.`sys_menu`
(`menu_id`, `name`, `permission`, `parent_id`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `del_flag`, `tenant_id`)
SELECT (SELECT GREATEST(COALESCE(MAX(`menu_id`), 0), 2026092400000000000) FROM `pjcloudx`.`sys_menu`) + ROW_NUMBER() OVER (ORDER BY page_menu.`tenant_id`, page_menu.`menu_id`, item.`sort`),
       item.`name`, item.`permission`, page_menu.`menu_id`,
       '1', item.`sort`, '0', '0', '2', 'system', NOW(), '0', page_menu.`tenant_id`
FROM `pjcloudx`.`sys_menu` page_menu
JOIN (
    SELECT '预约执行' AS `name`, 'wallet_walletRechargeApply_reserve' AS `permission`, 59 AS `sort`
    UNION ALL SELECT '立即执行', 'wallet_walletRechargeApply_execute', 60
) item ON item.`name` IS NOT NULL
WHERE page_menu.`permission` = 'wallet_walletRechargeApply_view' AND page_menu.`menu_type` = '0' AND page_menu.`del_flag` = '0'
  AND NOT EXISTS (
      SELECT 1 FROM `pjcloudx`.`sys_menu` existing
      WHERE existing.`tenant_id` = page_menu.`tenant_id`
        AND existing.`permission` = item.`permission` AND existing.`del_flag` = '0'
  );

------------------------------------------------------------------------
四、按钮权限：预约执行对账 tab 与「标记已处理」（挂在充值/扣款申请页面菜单下）
------------------------------------------------------------------------

对账入口集成在充值/扣款申请列表页（tab 形式，无独立页面/路由）：
  src/views/wallet/wallet-recharge-apply/index.vue
  持有 wallet_walletRechargeExecCheck_view 权限的用户才会看到「预约执行对账」tab。

INSERT INTO `pjcloudx`.`sys_menu`
(`menu_id`, `name`, `permission`, `parent_id`, `visible`, `sort_order`, `keep_alive`, `embedded`, `menu_type`, `create_by`, `create_time`, `del_flag`, `tenant_id`)
SELECT (SELECT GREATEST(COALESCE(MAX(`menu_id`), 0), 2026092400000000000) FROM `pjcloudx`.`sys_menu`) + ROW_NUMBER() OVER (ORDER BY page_menu.`tenant_id`, page_menu.`menu_id`, item.`sort`),
       item.`name`, item.`permission`, page_menu.`menu_id`,
       '1', item.`sort`, '0', '0', '2', 'system', NOW(), '0', page_menu.`tenant_id`
FROM `pjcloudx`.`sys_menu` page_menu
JOIN (
    SELECT '预约执行对账' AS `name`, 'wallet_walletRechargeExecCheck_view' AS `permission`, 61 AS `sort`
    UNION ALL SELECT '标记已处理', 'wallet_walletRechargeExecCheck_handle', 62
) item ON item.`name` IS NOT NULL
WHERE page_menu.`permission` = 'wallet_walletRechargeApply_view' AND page_menu.`menu_type` = '0' AND page_menu.`del_flag` = '0'
  AND NOT EXISTS (
      SELECT 1 FROM `pjcloudx`.`sys_menu` existing
      WHERE existing.`tenant_id` = page_menu.`tenant_id`
        AND existing.`permission` = item.`permission` AND existing.`del_flag` = '0'
  );

------------------------------------------------------------------------
五、后端权限字符串与接口对应关系（前端页面取用）
------------------------------------------------------------------------

wallet_walletRechargeApply_reserve:
  前端表单「预约执行」开关与时间控件显隐（v-if）；后端新增接口无权限强制关闭预约、
  修改接口无权限忽略预约字段保持原值，防止绕过前端越权设置

wallet_walletRechargeApply_execute:
  POST /wallet/wallet-recharge-apply/execute   立即执行预约单（待执行/待重试/失败终态均可触发）

wallet_walletRechargeExecCheck_view:
  GET  /wallet/wallet-recharge-exec-check/page 对账差异分页（同时控制列表页「预约执行对账」tab 显隐）

wallet_walletRechargeExecCheck_handle:
  PUT  /wallet/wallet-recharge-exec-check/handle 标记差异已处理（填处理备注）

内部端点（daemon-quartz 定时任务专用，@Inner 鉴权，勿对外）：
  POST /wallet/wallet-recharge-apply/inner/execute-due-reserve   扫描并执行到期预约单
  POST /wallet/wallet-recharge-apply/inner/reconcile              预约单对账复核

------------------------------------------------------------------------
六、回滚说明
------------------------------------------------------------------------
  停用任务：将两条 sys_job 的 job_status 改为 '4'（删除）或 '3'（暂停）并重启 daemon-quartz
  （或调 POST /sys-job/refresh-jobs）；
  回滚菜单：按本文件新增的 permission 值删除对应 sys_menu 行；
  字段与差异表回滚（确认无进行中的预约单后执行）：
    ALTER TABLE `pjcloudx_wallet`.`wallet_recharge_apply`
      DROP INDEX `idx_wra_reserve_scan`,
      DROP COLUMN `reserve_flag`, DROP COLUMN `reserve_time`, DROP COLUMN `exec_status`,
      DROP COLUMN `exec_time`, DROP COLUMN `exec_count`, DROP COLUMN `next_exec_time`,
      DROP COLUMN `last_error`, DROP COLUMN `claim_time`;
    DROP TABLE IF EXISTS `pjcloudx_wallet`.`wallet_recharge_exec_check`;
