feat:新增ai分析,新增储值账户,优化通知规则

This commit is contained in:
2026-03-12 14:03:01 +08:00
parent 6a00875246
commit 6ca962a187
22 changed files with 1294 additions and 237 deletions

View File

@@ -25,6 +25,56 @@ const cases = [
verify(result) {
assert.equal(result.rule?.id, 'transit-card-expense')
assert.equal(result.transaction.amount, -2)
assert.equal(result.transaction.fundSourceType, 'stored_value')
assert.equal(result.transaction.impactExpense, true)
},
},
{
name: 'capture transit expense from route and fare only',
notification: {
id: 'n2b',
channel: '杭州通互联互通卡',
text: '武林广场->古荡2.10元',
createdAt: '2026-03-11T00:00:00.000Z',
},
verify(result) {
assert.equal(result.rule?.id, 'transit-card-expense')
assert.equal(result.transaction.amount, -2.1)
assert.equal(result.transaction.category, 'Transport')
assert.equal(result.transaction.fundSourceName, '杭州通互联互通卡')
},
},
{
name: 'capture stored value topup as transfer',
notification: {
id: 'n2c',
channel: '杭州通互联互通卡',
text: '充值成功20元',
createdAt: '2026-03-11T00:00:00.000Z',
},
verify(result) {
assert.equal(result.rule?.id, 'stored-value-topup')
assert.equal(result.transaction.entryType, 'transfer')
assert.equal(result.transaction.category, 'Transfer')
assert.equal(result.transaction.amount, -20)
assert.equal(result.transaction.impactExpense, false)
assert.equal(result.transaction.fundTargetName, '杭州通互联互通卡')
},
},
{
name: 'capture stored value refund as transfer',
notification: {
id: 'n2d',
channel: '杭州通互联互通卡',
text: '退款成功5元',
createdAt: '2026-03-11T00:00:00.000Z',
},
verify(result) {
assert.equal(result.rule?.id, 'stored-value-refund')
assert.equal(result.transaction.entryType, 'transfer')
assert.equal(result.transaction.amount, 5)
assert.equal(result.transaction.impactIncome, false)
assert.equal(result.transaction.fundSourceName, '杭州通互联互通卡')
},
},
{

View File

@@ -1,4 +1,4 @@
import fs from 'node:fs'
import fs from 'node:fs'
import path from 'node:path'
import notificationRules from '../src/config/notificationRules.js'
@@ -28,6 +28,8 @@ const toKotlinRegex = (spec) => {
return `Regex(${toKotlinString(spec.pattern)}${flags})`
}
const toOptionalString = (value) => (value ? toKotlinString(value) : 'null')
const toRuleBlock = (rule) => ` NotificationRuleDefinition(
id = ${toKotlinString(rule.id)},
label = ${toKotlinString(rule.label)},
@@ -35,12 +37,19 @@ const toRuleBlock = (rule) => ` NotificationRuleDefinition(
keywords = ${toKotlinStringList(rule.keywords)},
requiredTextPatterns = ${toKotlinStringList(rule.requiredTextPatterns)},
direction = NotificationRuleDirection.${rule.direction === 'income' ? 'INCOME' : 'EXPENSE'},
entryType = ${toKotlinString(rule.entryType || 'expense')},
fundSourceType = ${toKotlinString(rule.fundSourceType || 'cash')},
fundSourceName = ${toOptionalString(rule.fundSourceName)},
fundSourceNameFromChannel = ${rule.fundSourceNameFromChannel ? 'true' : 'false'},
fundTargetType = ${toKotlinString(rule.fundTargetType || 'merchant')},
fundTargetName = ${toOptionalString(rule.fundTargetName)},
fundTargetNameFromChannel = ${rule.fundTargetNameFromChannel ? 'true' : 'false'},
impactExpense = ${rule.impactExpense === false ? 'false' : 'true'},
impactIncome = ${rule.impactIncome ? 'true' : 'false'},
defaultCategory = ${toKotlinString(rule.defaultCategory)},
autoCapture = ${rule.autoCapture ? 'true' : 'false'},
merchantPattern = ${toKotlinRegex(rule.merchantPattern)},
defaultMerchant = ${
rule.defaultMerchant ? toKotlinString(rule.defaultMerchant) : 'null'
},
defaultMerchant = ${toOptionalString(rule.defaultMerchant)},
)`
const content = `package com.echo.app.notification