fix(plan): 修正 coverage 与 annual_premium 字段映射错误
修复 coverage 字段错误映射到 annual_premium API 字段的问题, 新增独立的 annual_premium 字段定义,同步更新 API 文档。 - coverage 现正确映射到 coverage API 字段(保额) - annual_premium 独立映射到 annual_premium API 字段(年缴保费) - 更新 API 文档补充 coverage 参数和完整请求示例 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Showing
9 changed files
with
110 additions
and
27 deletions
| ... | @@ -569,7 +569,7 @@ GET /api/plan/config/:form_sn | ... | @@ -569,7 +569,7 @@ GET /api/plan/config/:form_sn |
| 569 | }, | 569 | }, |
| 570 | "submit_mapping": { | 570 | "submit_mapping": { |
| 571 | "customer_name": { "api_field": "customer_name" }, | 571 | "customer_name": { "api_field": "customer_name" }, |
| 572 | - "coverage": { "api_field": "annual_premium", "transform": "fen_to_yuan" } | 572 | + "annual_premium": { "api_field": "annual_premium", "transform": "fen_to_yuan" } |
| 573 | // ... 更多映射 | 573 | // ... 更多映射 |
| 574 | } | 574 | } |
| 575 | } | 575 | } |
| ... | @@ -676,7 +676,7 @@ CREATE TABLE product_configs ( | ... | @@ -676,7 +676,7 @@ CREATE TABLE product_configs ( |
| 676 | }, | 676 | }, |
| 677 | "submit_mapping": { | 677 | "submit_mapping": { |
| 678 | "customer_name": { "api_field": "customer_name" }, | 678 | "customer_name": { "api_field": "customer_name" }, |
| 679 | - "coverage": { "api_field": "annual_premium", "transform": "fen_to_yuan" } | 679 | + "annual_premium": { "api_field": "annual_premium", "transform": "fen_to_yuan" } |
| 680 | } | 680 | } |
| 681 | } | 681 | } |
| 682 | ``` | 682 | ``` | ... | ... |
| ... | @@ -616,7 +616,7 @@ | ... | @@ -616,7 +616,7 @@ |
| 616 | "submit_mapping": { | 616 | "submit_mapping": { |
| 617 | "customer_name": { "api_field": "customer_name" }, | 617 | "customer_name": { "api_field": "customer_name" }, |
| 618 | "gender": { "api_field": "customer_gender" }, | 618 | "gender": { "api_field": "customer_gender" }, |
| 619 | - "coverage": { "api_field": "annual_premium", "transform": "fen_to_yuan" }, | 619 | + "annual_premium": { "api_field": "annual_premium", "transform": "fen_to_yuan" }, |
| 620 | "payment_period": { "api_field": "payment_years" }, | 620 | "payment_period": { "api_field": "payment_years" }, |
| 621 | "withdrawal_enabled": { "api_field": "allow_reduce_amount" }, | 621 | "withdrawal_enabled": { "api_field": "allow_reduce_amount" }, |
| 622 | "withdrawal_mode": { "api_field": "withdrawal_option" }, | 622 | "withdrawal_mode": { "api_field": "withdrawal_option" }, | ... | ... |
| ... | @@ -79,7 +79,7 @@ const reset_map = { | ... | @@ -79,7 +79,7 @@ const reset_map = { |
| 79 | ```javascript | 79 | ```javascript |
| 80 | // submit_mapping 示例(金额字段统一从分转元) | 80 | // submit_mapping 示例(金额字段统一从分转元) |
| 81 | const submit_mapping = { | 81 | const submit_mapping = { |
| 82 | - coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | 82 | + annual_premium: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, |
| 83 | annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, | 83 | annual_withdrawal_amount: { api_field: 'annual_withdrawal_amount', transform: 'fen_to_yuan' }, |
| 84 | withdrawal_mode: { api_field: 'withdrawal_option' } | 84 | withdrawal_mode: { api_field: 'withdrawal_option' } |
| 85 | } | 85 | } |
| ... | @@ -101,7 +101,7 @@ const submit_mapping = { | ... | @@ -101,7 +101,7 @@ const submit_mapping = { |
| 101 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], | 101 | withdrawal_modes: ['年龄指定金额', '最高固定金额'], |
| 102 | withdrawal_periods: ['1年', '3年', '5年', '10年'], | 102 | withdrawal_periods: ['1年', '3年', '5年', '10年'], |
| 103 | form_schema: { base_fields: [], withdrawal_fields: [], reset_map: {} }, | 103 | form_schema: { base_fields: [], withdrawal_fields: [], reset_map: {} }, |
| 104 | - submit_mapping: { coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' } }, | 104 | + submit_mapping: { annual_premium: { api_field: 'annual_premium', transform: 'fen_to_yuan' } }, |
| 105 | source_file: '产品说明书.pdf', | 105 | source_file: '产品说明书.pdf', |
| 106 | warnings: [] | 106 | warnings: [] |
| 107 | } | 107 | } | ... | ... |
| ... | @@ -52,15 +52,12 @@ paths: | ... | @@ -52,15 +52,12 @@ paths: |
| 52 | customer_age: | 52 | customer_age: |
| 53 | type: integer | 53 | type: integer |
| 54 | title: 年龄 | 54 | title: 年龄 |
| 55 | - description: 与 customer_birthday 二选一,至少提供一个 | ||
| 56 | customer_birthday: | 55 | customer_birthday: |
| 57 | type: string | 56 | type: string |
| 58 | title: 出生年月日 | 57 | title: 出生年月日 |
| 59 | - format: date | ||
| 60 | - description: 与 customer_age 二选一,至少提供一个。格式:YYYY-MM-DD | ||
| 61 | annual_premium: | 58 | annual_premium: |
| 62 | type: integer | 59 | type: integer |
| 63 | - title: 保额 | 60 | + title: 年缴保费 |
| 64 | payment_years: | 61 | payment_years: |
| 65 | type: string | 62 | type: string |
| 66 | title: 繳費年期 | 63 | title: 繳費年期 |
| ... | @@ -94,12 +91,14 @@ paths: | ... | @@ -94,12 +91,14 @@ paths: |
| 94 | annual_increase_percentage: | 91 | annual_increase_percentage: |
| 95 | type: integer | 92 | type: integer |
| 96 | title: 每年递增提取百分比 | 93 | title: 每年递增提取百分比 |
| 94 | + coverage: | ||
| 95 | + type: string | ||
| 96 | + title: 保额 | ||
| 97 | required: | 97 | required: |
| 98 | - customer_name | 98 | - customer_name |
| 99 | - customer_gender | 99 | - customer_gender |
| 100 | - # 年龄与出生年月日二选一(至少提供一个) | 100 | + - customer_age |
| 101 | - # - customer_age | 101 | + - customer_birthday |
| 102 | - # - customer_birthday | ||
| 103 | - annual_premium | 102 | - annual_premium |
| 104 | - payment_years | 103 | - payment_years |
| 105 | - currency_type | 104 | - currency_type |
| ... | @@ -112,12 +111,14 @@ paths: | ... | @@ -112,12 +111,14 @@ paths: |
| 112 | - product_id | 111 | - product_id |
| 113 | - annual_increase_percentage | 112 | - annual_increase_percentage |
| 114 | - annual_withdrawal_amount | 113 | - annual_withdrawal_amount |
| 114 | + - coverage | ||
| 115 | x-apifox-orders: | 115 | x-apifox-orders: |
| 116 | - customer_name | 116 | - customer_name |
| 117 | - customer_gender | 117 | - customer_gender |
| 118 | - customer_age | 118 | - customer_age |
| 119 | - annual_premium | 119 | - annual_premium |
| 120 | - payment_years | 120 | - payment_years |
| 121 | + - coverage | ||
| 121 | - currency_type | 122 | - currency_type |
| 122 | - product_id | 123 | - product_id |
| 123 | - customer_birthday | 124 | - customer_birthday |
| ... | @@ -129,7 +130,23 @@ paths: | ... | @@ -129,7 +130,23 @@ paths: |
| 129 | - total_premium | 130 | - total_premium |
| 130 | - annual_withdrawal_amount | 131 | - annual_withdrawal_amount |
| 131 | - annual_increase_percentage | 132 | - annual_increase_percentage |
| 132 | - example: "{\r\n customer_name: '张三',\r\n customer_gender: 'male',\r\n customer_age: 30,\r\n annual_premium: 5000,\r\n payment_years: '10年',\r\n currency_type: 'CNY',\r\n product_id: 1\r\n }" | 133 | + example: |
| 134 | + customer_name: 张三 | ||
| 135 | + customer_gender: 男 | ||
| 136 | + customer_age: 30 | ||
| 137 | + annual_premium: 5000 | ||
| 138 | + payment_years: 10年 | ||
| 139 | + currency_type: CNY | ||
| 140 | + product_id: 3151974 | ||
| 141 | + customer_birthday: '2025-03-21' | ||
| 142 | + allow_reduce_amount: 是 | ||
| 143 | + withdrawal_option: 指定提取金额 | ||
| 144 | + withdrawal_start_age: 60 | ||
| 145 | + withdrawal_period: 10 | ||
| 146 | + smoking_status: 否 | ||
| 147 | + total_premium: 0 | ||
| 148 | + annual_withdrawal_amount: 6 | ||
| 149 | + annual_increase_percentage: 33 | ||
| 133 | responses: | 150 | responses: |
| 134 | '200': | 151 | '200': |
| 135 | description: '' | 152 | description: '' |
| ... | @@ -169,15 +186,13 @@ paths: | ... | @@ -169,15 +186,13 @@ paths: |
| 169 | x-apifox-ordering: 0 | 186 | x-apifox-ordering: 0 |
| 170 | security: [] | 187 | security: [] |
| 171 | x-apifox-folder: 计划书 | 188 | x-apifox-folder: 计划书 |
| 172 | - x-apifox-status: developing | 189 | + x-apifox-status: released |
| 173 | x-run-in-apifox: https://app.apifox.com/web/project/7792797/apis/api-417310981-run | 190 | x-run-in-apifox: https://app.apifox.com/web/project/7792797/apis/api-417310981-run |
| 174 | components: | 191 | components: |
| 175 | schemas: {} | 192 | schemas: {} |
| 176 | responses: {} | 193 | responses: {} |
| 177 | securitySchemes: {} | 194 | securitySchemes: {} |
| 178 | -servers: | 195 | +servers: [] |
| 179 | - - url: https://manulife.onwall.cn | ||
| 180 | - description: 正式环境 | ||
| 181 | security: [] | 196 | security: [] |
| 182 | 197 | ||
| 183 | -```\ | 198 | +``` | ... | ... |
| ... | @@ -13,9 +13,9 @@ const Api = { | ... | @@ -13,9 +13,9 @@ const Api = { |
| 13 | * @param {Object} params 请求参数 | 13 | * @param {Object} params 请求参数 |
| 14 | * @param {string} params.customer_name 申请人 | 14 | * @param {string} params.customer_name 申请人 |
| 15 | * @param {string} params.customer_gender 性别 | 15 | * @param {string} params.customer_gender 性别 |
| 16 | - * @param {integer} params.customer_age (可选) 与 customer_birthday 二选一,至少提供一个 | 16 | + * @param {integer} params.customer_age 年龄 |
| 17 | - * @param {string} params.customer_birthday (可选) 与 customer_age 二选一,至少提供一个。格式:YYYY-MM-DD | 17 | + * @param {string} params.customer_birthday 出生年月日 |
| 18 | - * @param {integer} params.annual_premium 保额 | 18 | + * @param {integer} params.annual_premium 年缴保费 |
| 19 | * @param {string} params.payment_years 繳費年期 | 19 | * @param {string} params.payment_years 繳費年期 |
| 20 | * @param {string} params.currency_type 币种 | 20 | * @param {string} params.currency_type 币种 |
| 21 | * @param {string} params.allow_reduce_amount 是否容许减少名义金额 | 21 | * @param {string} params.allow_reduce_amount 是否容许减少名义金额 |
| ... | @@ -27,6 +27,7 @@ const Api = { | ... | @@ -27,6 +27,7 @@ const Api = { |
| 27 | * @param {integer} params.product_id 产品id | 27 | * @param {integer} params.product_id 产品id |
| 28 | * @param {integer} params.annual_withdrawal_amount 每年提取金额 | 28 | * @param {integer} params.annual_withdrawal_amount 每年提取金额 |
| 29 | * @param {integer} params.annual_increase_percentage 每年递增提取百分比 | 29 | * @param {integer} params.annual_increase_percentage 每年递增提取百分比 |
| 30 | + * @param {string} params.coverage 保额 | ||
| 30 | * @returns {Promise<{ | 31 | * @returns {Promise<{ |
| 31 | * code: number; // 状态码 | 32 | * code: number; // 状态码 |
| 32 | * msg: string; // 消息 | 33 | * msg: string; // 消息 | ... | ... |
| ... | @@ -277,7 +277,8 @@ const submit = async () => { | ... | @@ -277,7 +277,8 @@ const submit = async () => { |
| 277 | gender: { api_field: 'customer_gender' }, | 277 | gender: { api_field: 'customer_gender' }, |
| 278 | birthday: { api_field: 'customer_birthday' }, | 278 | birthday: { api_field: 'customer_birthday' }, |
| 279 | smoker: { api_field: 'smoking_status' }, | 279 | smoker: { api_field: 'smoking_status' }, |
| 280 | - coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | 280 | + coverage: { api_field: 'coverage', transform: 'fen_to_yuan' }, |
| 281 | + annual_premium: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | ||
| 281 | payment_period: { api_field: 'payment_years' }, | 282 | payment_period: { api_field: 'payment_years' }, |
| 282 | withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | 283 | withdrawal_enabled: { api_field: 'allow_reduce_amount' }, |
| 283 | withdrawal_mode: { api_field: 'withdrawal_option' }, | 284 | withdrawal_mode: { api_field: 'withdrawal_option' }, | ... | ... |
src/config/__tests__/plan-templates.test.js
0 → 100644
| 1 | +import { describe, expect, it } from 'vitest' | ||
| 2 | +import { PLAN_TEMPLATES } from '../plan-templates' | ||
| 3 | +import { PLAN_FIELD_DEFINITIONS } from '../plan-fields' | ||
| 4 | + | ||
| 5 | +describe('plan template amount field mapping', () => { | ||
| 6 | + it('should map protection coverage to coverage api field', () => { | ||
| 7 | + expect(PLAN_TEMPLATES['life-insurance-wiop3e'].config.submit_mapping.coverage).toEqual({ | ||
| 8 | + api_field: 'coverage', | ||
| 9 | + transform: 'fen_to_yuan' | ||
| 10 | + }) | ||
| 11 | + }) | ||
| 12 | + | ||
| 13 | + it('should use annual_premium field for savings schema and submit mapping', () => { | ||
| 14 | + const savingsConfig = PLAN_TEMPLATES['savings-gs'].config | ||
| 15 | + const annualPremiumField = savingsConfig.form_schema.base_fields.find(field => field.key === 'annual_premium') | ||
| 16 | + | ||
| 17 | + expect(annualPremiumField).toMatchObject({ | ||
| 18 | + key: 'annual_premium', | ||
| 19 | + label: '年缴保费', | ||
| 20 | + type: 'amount' | ||
| 21 | + }) | ||
| 22 | + | ||
| 23 | + expect(savingsConfig.submit_mapping.annual_premium).toEqual({ | ||
| 24 | + api_field: 'annual_premium', | ||
| 25 | + transform: 'fen_to_yuan' | ||
| 26 | + }) | ||
| 27 | + | ||
| 28 | + expect(savingsConfig.submit_mapping.coverage).toBeUndefined() | ||
| 29 | + }) | ||
| 30 | +}) | ||
| 31 | + | ||
| 32 | +describe('plan field definitions amount semantics', () => { | ||
| 33 | + it('should expose separate coverage and annual_premium definitions', () => { | ||
| 34 | + expect(PLAN_FIELD_DEFINITIONS.coverage).toMatchObject({ | ||
| 35 | + label: '保额', | ||
| 36 | + api_field: 'coverage', | ||
| 37 | + transform: 'fen_to_yuan' | ||
| 38 | + }) | ||
| 39 | + | ||
| 40 | + expect(PLAN_FIELD_DEFINITIONS.annual_premium).toMatchObject({ | ||
| 41 | + label: '年缴保费', | ||
| 42 | + api_field: 'annual_premium', | ||
| 43 | + transform: 'fen_to_yuan' | ||
| 44 | + }) | ||
| 45 | + }) | ||
| 46 | +}) |
| ... | @@ -51,6 +51,7 @@ export const TRANSFORM_TYPES = { | ... | @@ -51,6 +51,7 @@ export const TRANSFORM_TYPES = { |
| 51 | * @property {Object} birthday - 出生日期 | 51 | * @property {Object} birthday - 出生日期 |
| 52 | * @property {Object} smoker - 是否吸烟 | 52 | * @property {Object} smoker - 是否吸烟 |
| 53 | * @property {Object} coverage - 保额 | 53 | * @property {Object} coverage - 保额 |
| 54 | + * @property {Object} annual_premium - 年缴保费 | ||
| 54 | * @property {Object} payment_period - 缴费年期 | 55 | * @property {Object} payment_period - 缴费年期 |
| 55 | * @property {Object} withdrawal_enabled - 是否启用提取 | 56 | * @property {Object} withdrawal_enabled - 是否启用提取 |
| 56 | * @property {Object} withdrawal_mode - 提取模式 | 57 | * @property {Object} withdrawal_mode - 提取模式 |
| ... | @@ -126,13 +127,13 @@ export const PLAN_FIELD_DEFINITIONS = { | ... | @@ -126,13 +127,13 @@ export const PLAN_FIELD_DEFINITIONS = { |
| 126 | }, | 127 | }, |
| 127 | 128 | ||
| 128 | /** | 129 | /** |
| 129 | - * 保额(年缴) | 130 | + * 保额 |
| 130 | */ | 131 | */ |
| 131 | coverage: { | 132 | coverage: { |
| 132 | label: '保额', | 133 | label: '保额', |
| 133 | type: FIELD_TYPES.AMOUNT, | 134 | type: FIELD_TYPES.AMOUNT, |
| 134 | required: true, | 135 | required: true, |
| 135 | - api_field: 'annual_premium', | 136 | + api_field: 'coverage', |
| 136 | transform: TRANSFORM_TYPES.FEN_TO_YUAN, | 137 | transform: TRANSFORM_TYPES.FEN_TO_YUAN, |
| 137 | component: 'PlanFieldAmount', | 138 | component: 'PlanFieldAmount', |
| 138 | group: FIELD_GROUPS.COVERAGE, | 139 | group: FIELD_GROUPS.COVERAGE, |
| ... | @@ -145,6 +146,25 @@ export const PLAN_FIELD_DEFINITIONS = { | ... | @@ -145,6 +146,25 @@ export const PLAN_FIELD_DEFINITIONS = { |
| 145 | }, | 146 | }, |
| 146 | 147 | ||
| 147 | /** | 148 | /** |
| 149 | + * 年缴保费 | ||
| 150 | + */ | ||
| 151 | + annual_premium: { | ||
| 152 | + label: '年缴保费', | ||
| 153 | + type: FIELD_TYPES.AMOUNT, | ||
| 154 | + required: true, | ||
| 155 | + api_field: 'annual_premium', | ||
| 156 | + transform: TRANSFORM_TYPES.FEN_TO_YUAN, | ||
| 157 | + component: 'PlanFieldAmount', | ||
| 158 | + group: FIELD_GROUPS.COVERAGE, | ||
| 159 | + placeholder: '请输入年缴保费', | ||
| 160 | + validation: { | ||
| 161 | + required: (value) => value > 0, | ||
| 162 | + min: (value, config) => value >= (config?.min_coverage || 1000), | ||
| 163 | + max: (value, config) => value <= (config?.max_coverage || 10000000) | ||
| 164 | + } | ||
| 165 | + }, | ||
| 166 | + | ||
| 167 | + /** | ||
| 148 | * 缴费年期 | 168 | * 缴费年期 |
| 149 | */ | 169 | */ |
| 150 | payment_period: { | 170 | payment_period: { | ... | ... |
| ... | @@ -43,7 +43,7 @@ const baseSubmitMapping = { | ... | @@ -43,7 +43,7 @@ const baseSubmitMapping = { |
| 43 | age: { api_field: 'customer_age' }, | 43 | age: { api_field: 'customer_age' }, |
| 44 | birthday: { api_field: 'customer_birthday' }, | 44 | birthday: { api_field: 'customer_birthday' }, |
| 45 | smoker: { api_field: 'smoking_status' }, | 45 | smoker: { api_field: 'smoking_status' }, |
| 46 | - coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | 46 | + coverage: { api_field: 'coverage', transform: 'fen_to_yuan' }, |
| 47 | payment_period: { api_field: 'payment_years' }, | 47 | payment_period: { api_field: 'payment_years' }, |
| 48 | total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } | 48 | total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' } |
| 49 | } | 49 | } |
| ... | @@ -70,7 +70,7 @@ const savingsSubmitMapping = { | ... | @@ -70,7 +70,7 @@ const savingsSubmitMapping = { |
| 70 | age: { api_field: 'customer_age' }, | 70 | age: { api_field: 'customer_age' }, |
| 71 | birthday: { api_field: 'customer_birthday' }, | 71 | birthday: { api_field: 'customer_birthday' }, |
| 72 | // smoker: { api_field: 'smoking_status' }, // 储蓄类产品不需要吸烟字段 | 72 | // smoker: { api_field: 'smoking_status' }, // 储蓄类产品不需要吸烟字段 |
| 73 | - coverage: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, | 73 | + annual_premium: { api_field: 'annual_premium', transform: 'fen_to_yuan' }, |
| 74 | payment_period: { api_field: 'payment_years' }, | 74 | payment_period: { api_field: 'payment_years' }, |
| 75 | total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' }, | 75 | total_amount: { api_field: 'total_premium', transform: 'fen_to_yuan' }, |
| 76 | withdrawal_enabled: { api_field: 'allow_reduce_amount' }, | 76 | withdrawal_enabled: { api_field: 'allow_reduce_amount' }, |
| ... | @@ -97,7 +97,7 @@ const savingsFormSchema = { | ... | @@ -97,7 +97,7 @@ const savingsFormSchema = { |
| 97 | // 年龄与出生年月日二选一填写 | 97 | // 年龄与出生年月日二选一填写 |
| 98 | { id: 'age', key: 'age', type: 'age', label: '年龄', placeholder: '请输入年龄', input_label: '岁', required: false }, | 98 | { id: 'age', key: 'age', type: 'age', label: '年龄', placeholder: '请输入年龄', input_label: '岁', required: false }, |
| 99 | { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: false }, | 99 | { id: 'birthday', key: 'birthday', type: 'date', label: '出生年月日', placeholder: '请选择年月日', required: false }, |
| 100 | - { id: 'coverage', key: 'coverage', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, | 100 | + { id: 'annual_premium', key: 'annual_premium', type: 'amount', label: '年缴保费', placeholder: '请输入年缴保费', input_label: '请输入年缴保费金额', required: true, currency_from: 'currency' }, |
| 101 | { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } | 101 | { id: 'payment_period', key: 'payment_period', type: 'payment_period', label: '缴费年期', required: true, options_from: 'payment_periods' } |
| 102 | ], | 102 | ], |
| 103 | // 提取计划字段:由 withdrawal_plan 开关控制 | 103 | // 提取计划字段:由 withdrawal_plan 开关控制 | ... | ... |
-
Please register or login to post a comment