From e5cf92f84e2411516e6c983c395f74dea167ecef Mon Sep 17 00:00:00 2001 From: MaysWind Date: Mon, 24 Mar 2025 00:10:48 +0800 Subject: [PATCH] batch create nonexistent transaction categories when import transaction --- src/consts/icon.ts | 1 + src/locales/de.json | 7 + src/locales/en.json | 7 + src/locales/es.json | 7 + src/locales/ja.json | 7 + src/locales/ru.json | 7 + src/locales/vi.json | 7 + src/locales/zh_Hans.json | 7 + .../transactions/import/ImportDialog.vue | 107 +++++++- .../import/dialogs/BatchCreateDialog.vue | 256 ++++++++++++++++++ 10 files changed, 407 insertions(+), 6 deletions(-) create mode 100644 src/views/desktop/transactions/import/dialogs/BatchCreateDialog.vue diff --git a/src/consts/icon.ts b/src/consts/icon.ts index 619a62fb..770ceba1 100644 --- a/src/consts/icon.ts +++ b/src/consts/icon.ts @@ -164,6 +164,7 @@ export const ALL_ACCOUNT_ICONS: Record = { export const DEFAULT_ACCOUNT_ICON = ALL_ACCOUNT_ICONS[DEFAULT_ACCOUNT_ICON_ID]; export const DEFAULT_CATEGORY_ICON_ID = '1'; +export const AUTOMATICALLY_CREATED_CATEGORY_ICON_ID = '561'; export const ALL_CATEGORY_ICONS: Record = { // 1 - 99 : Expense - Food & Drink diff --git a/src/locales/de.json b/src/locales/de.json index 1ea54575..4d58b57b 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "Ungültige Überweisungskategorien ersetzen", "Replace Invalid Accounts": "Ungültige Konten ersetzen", "Replace Invalid Transaction Tags": "Ungültige Transaktions-Tags ersetzen", + "Create Nonexistent Expense Categories": "Create Nonexistent Expense Categories", + "Create Nonexistent Income Categories": "Create Nonexistent Income Categories", + "Create Nonexistent Transfer Categories": "Create Nonexistent Transfer Categories", + "Create Nonexistent Transaction Tags": "Create Nonexistent Transaction Tags", "Batch Convert Expense Transaction to Income Transaction": "Batch Convert Expense Transaction to Income Transaction", "Batch Convert Expense Transaction to Transfer Transaction": "Batch Convert Expense Transaction to Transfer Transaction", "Batch Convert Income Transaction to Expense Transaction": "Batch Convert Income Transaction to Expense Transaction", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "Batch Convert Transfer Transaction to Income Transaction", "Invalid Category": "Ungültige Kategorie", "Target Category": "Zielkategorie", + "Default Expense Category": "Default Expense Category", + "Default Income Category": "Default Income Category", + "Default Transfer Category": "Default Transfer Category", "Invalid Account": "Ungültiges Konto", "Target Account": "Zielkonto", "Invalid Tag": "Ungültiges Tag", diff --git a/src/locales/en.json b/src/locales/en.json index a3756514..a6e74848 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "Replace Invalid Transfer Categories", "Replace Invalid Accounts": "Replace Invalid Accounts", "Replace Invalid Transaction Tags": "Replace Invalid Transaction Tags", + "Create Nonexistent Expense Categories": "Create Nonexistent Expense Categories", + "Create Nonexistent Income Categories": "Create Nonexistent Income Categories", + "Create Nonexistent Transfer Categories": "Create Nonexistent Transfer Categories", + "Create Nonexistent Transaction Tags": "Create Nonexistent Transaction Tags", "Batch Convert Expense Transaction to Income Transaction": "Batch Convert Expense Transaction to Income Transaction", "Batch Convert Expense Transaction to Transfer Transaction": "Batch Convert Expense Transaction to Transfer Transaction", "Batch Convert Income Transaction to Expense Transaction": "Batch Convert Income Transaction to Expense Transaction", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "Batch Convert Transfer Transaction to Income Transaction", "Invalid Category": "Invalid Category", "Target Category": "Target Category", + "Default Expense Category": "Default Expense Category", + "Default Income Category": "Default Income Category", + "Default Transfer Category": "Default Transfer Category", "Invalid Account": "Invalid Account", "Target Account": "Target Account", "Invalid Tag": "Invalid Tag", diff --git a/src/locales/es.json b/src/locales/es.json index 12accfb0..4a39779a 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "Reemplazar categorías de transferencia no válidas", "Replace Invalid Accounts": "Reemplazar cuentas no válidas", "Replace Invalid Transaction Tags": "Reemplazar etiquetas de transacciones no válidas", + "Create Nonexistent Expense Categories": "Create Nonexistent Expense Categories", + "Create Nonexistent Income Categories": "Create Nonexistent Income Categories", + "Create Nonexistent Transfer Categories": "Create Nonexistent Transfer Categories", + "Create Nonexistent Transaction Tags": "Create Nonexistent Transaction Tags", "Batch Convert Expense Transaction to Income Transaction": "Batch Convert Expense Transaction to Income Transaction", "Batch Convert Expense Transaction to Transfer Transaction": "Batch Convert Expense Transaction to Transfer Transaction", "Batch Convert Income Transaction to Expense Transaction": "Batch Convert Income Transaction to Expense Transaction", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "Batch Convert Transfer Transaction to Income Transaction", "Invalid Category": "Categoría no válida", "Target Category": "Categoría de destino", + "Default Expense Category": "Default Expense Category", + "Default Income Category": "Default Income Category", + "Default Transfer Category": "Default Transfer Category", "Invalid Account": "Cuenta no válida", "Target Account": "Cuenta de destino", "Invalid Tag": "Etiqueta no válida", diff --git a/src/locales/ja.json b/src/locales/ja.json index 1fedecf0..322b0ddb 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "無効な振替カテゴリを置き換えます", "Replace Invalid Accounts": "無効な口座を置き換えます", "Replace Invalid Transaction Tags": "無効な取引タグを置き換えます", + "Create Nonexistent Expense Categories": "Create Nonexistent Expense Categories", + "Create Nonexistent Income Categories": "Create Nonexistent Income Categories", + "Create Nonexistent Transfer Categories": "Create Nonexistent Transfer Categories", + "Create Nonexistent Transaction Tags": "Create Nonexistent Transaction Tags", "Batch Convert Expense Transaction to Income Transaction": "支出取引を収入取引に一括変換", "Batch Convert Expense Transaction to Transfer Transaction": "支出取引を振替取引に一括変換", "Batch Convert Income Transaction to Expense Transaction": "収入取引を支出取引に一括変換", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "振替取引を収入取引に一括変換", "Invalid Category": "無効なカテゴリ", "Target Category": "対象カテゴリ", + "Default Expense Category": "Default Expense Category", + "Default Income Category": "Default Income Category", + "Default Transfer Category": "Default Transfer Category", "Invalid Account": "無効な口座", "Target Account": "対象口座", "Invalid Tag": "無効なタグ", diff --git a/src/locales/ru.json b/src/locales/ru.json index 6d0769be..1b6931a2 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "Заменить недействительные категории переводов", "Replace Invalid Accounts": "Заменить недействительные счета", "Replace Invalid Transaction Tags": "Заменить недействительные теги транзакций", + "Create Nonexistent Expense Categories": "Create Nonexistent Expense Categories", + "Create Nonexistent Income Categories": "Create Nonexistent Income Categories", + "Create Nonexistent Transfer Categories": "Create Nonexistent Transfer Categories", + "Create Nonexistent Transaction Tags": "Create Nonexistent Transaction Tags", "Batch Convert Expense Transaction to Income Transaction": "Batch Convert Expense Transaction to Income Transaction", "Batch Convert Expense Transaction to Transfer Transaction": "Batch Convert Expense Transaction to Transfer Transaction", "Batch Convert Income Transaction to Expense Transaction": "Batch Convert Income Transaction to Expense Transaction", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "Batch Convert Transfer Transaction to Income Transaction", "Invalid Category": "Недействительная категория", "Target Category": "Целевая категория", + "Default Expense Category": "Default Expense Category", + "Default Income Category": "Default Income Category", + "Default Transfer Category": "Default Transfer Category", "Invalid Account": "Недействительный счет", "Target Account": "Целевой счет", "Invalid Tag": "Недействительный тег", diff --git a/src/locales/vi.json b/src/locales/vi.json index 4fb4ca7e..6ced1edd 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "Thay thế các danh mục chuyển khoản không hợp lệ", "Replace Invalid Accounts": "Thay thế các tài khoản không hợp lệ", "Replace Invalid Transaction Tags": "Thay thế các thẻ giao dịch không hợp lệ", + "Create Nonexistent Expense Categories": "Create Nonexistent Expense Categories", + "Create Nonexistent Income Categories": "Create Nonexistent Income Categories", + "Create Nonexistent Transfer Categories": "Create Nonexistent Transfer Categories", + "Create Nonexistent Transaction Tags": "Create Nonexistent Transaction Tags", "Batch Convert Expense Transaction to Income Transaction": "Batch Convert Expense Transaction to Income Transaction", "Batch Convert Expense Transaction to Transfer Transaction": "Batch Convert Expense Transaction to Transfer Transaction", "Batch Convert Income Transaction to Expense Transaction": "Batch Convert Income Transaction to Expense Transaction", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "Batch Convert Transfer Transaction to Income Transaction", "Invalid Category": "Danh mục không hợp lệ", "Target Category": "Danh mục mục tiêu", + "Default Expense Category": "Default Expense Category", + "Default Income Category": "Default Income Category", + "Default Transfer Category": "Default Transfer Category", "Invalid Account": "Tài khoản không hợp lệ", "Target Account": "Tài khoản mục tiêu", "Invalid Tag": "Thẻ không hợp lệ", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 41787d3e..682691e1 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1689,6 +1689,10 @@ "Replace Invalid Transfer Categories": "替换无效的转账分类", "Replace Invalid Accounts": "替换无效的账户", "Replace Invalid Transaction Tags": "替换无效的交易标签", + "Create Nonexistent Expense Categories": "创建不存在的支出分类", + "Create Nonexistent Income Categories": "创建不存在的收入分类", + "Create Nonexistent Transfer Categories": "创建不存在的转账分类", + "Create Nonexistent Transaction Tags": "创建不存在的交易标签", "Batch Convert Expense Transaction to Income Transaction": "批量转换支出交易为收入交易", "Batch Convert Expense Transaction to Transfer Transaction": "批量转换支出交易为转账交易", "Batch Convert Income Transaction to Expense Transaction": "批量转换收入交易为支出交易", @@ -1697,6 +1701,9 @@ "Batch Convert Transfer Transaction to Income Transaction": "批量转换转账交易为收入交易", "Invalid Category": "无效分类", "Target Category": "目标分类", + "Default Expense Category": "默认支出分类", + "Default Income Category": "默认收入分类", + "Default Transfer Category": "默认转账分类", "Invalid Account": "无效账户", "Target Account": "目标账户", "Invalid Tag": "无效标签", diff --git a/src/views/desktop/transactions/import/ImportDialog.vue b/src/views/desktop/transactions/import/ImportDialog.vue index 1d6c6117..1eb09022 100644 --- a/src/views/desktop/transactions/import/ImportDialog.vue +++ b/src/views/desktop/transactions/import/ImportDialog.vue @@ -143,27 +143,44 @@ :title="tt('Replace Invalid Transaction Tags')" @click="showReplaceInvalidItemDialog('tag', allInvalidTransactionTagNames)"> - + + + + + + + + - - - - - @@ -812,6 +829,7 @@ @dateRange:change="changeCustomDateFilter" @error="onShowDateRangeError" /> + @@ -823,6 +841,7 @@ import PaginationButtons from '@/components/desktop/PaginationButtons.vue'; import ConfirmDialog from '@/components/desktop/ConfirmDialog.vue'; import SnackBar from '@/components/desktop/SnackBar.vue'; import BatchReplaceDialog, { type BatchReplaceDialogDataType } from './dialogs/BatchReplaceDialog.vue'; +import BatchCreateDialog, { type BatchCreateDialogDataType } from './dialogs/BatchCreateDialog.vue'; import { ref, computed, useTemplateRef, watch } from 'vue'; @@ -885,6 +904,8 @@ import { mdiDotsVertical, mdiHelpCircleOutline, mdiFindReplace, + mdiShapePlusOutline, + mdiTransfer, mdiClose, mdiArrowRight, mdiSelectAll, @@ -898,6 +919,7 @@ import { type ConfirmDialogType = InstanceType; type SnackBarType = InstanceType; type BatchReplaceDialogType = InstanceType; +type BatchCreateDialogType = InstanceType; type ImportTransactionDialogStep = 'uploadFile' | 'defineColumn' | 'checkData' | 'finalResult'; @@ -941,6 +963,7 @@ const statisticsStore = useStatisticsStore(); const confirmDialog = useTemplateRef('confirmDialog'); const snackbar = useTemplateRef('snackbar'); const batchReplaceDialog = useTemplateRef('batchReplaceDialog'); +const batchCreateDialog = useTemplateRef('batchCreateDialog'); const fileInput = useTemplateRef('fileInput'); const showState = ref(false); @@ -2507,6 +2530,78 @@ function showReplaceInvalidItemDialog(type: BatchReplaceDialogDataType, invalidI }); } +function showBatchCreateInvalidItemDialog(type: BatchCreateDialogDataType, invalidItems: NameValue[]): void { + if (editingTransaction.value) { + return; + } + + batchCreateDialog.value?.open({ + type: type, + invalidItems: invalidItems + }).then(result => { + if (!result || !result.sourceTargetMap) { + return; + } + + let updatedCount = 0; + + if (importTransactions.value) { + const sourceTargetMap: Record = result.sourceTargetMap; + + for (let i = 0; i < importTransactions.value.length; i++) { + const transaction: ImportTransaction = importTransactions.value[i]; + + if (transaction.valid) { + continue; + } + + let updated = false; + + if (type === 'expenseCategory' || type === 'incomeCategory' || type === 'transferCategory') { + const categoryId = transaction.categoryId; + const originalCategoryName = transaction.originalCategoryName; + const targetItem = sourceTargetMap[originalCategoryName]; + + if (transaction.type !== TransactionType.ModifyBalance && targetItem && (!categoryId || categoryId === '0' || !allCategoriesMap.value[categoryId])) { + if (type === 'expenseCategory' && transaction.type === TransactionType.Expense) { + transaction.categoryId = targetItem; + updated = true; + } else if (type === 'incomeCategory' && transaction.type === TransactionType.Income) { + transaction.categoryId = targetItem; + updated = true; + } else if (type === 'transferCategory' && transaction.type === TransactionType.Transfer) { + transaction.categoryId = targetItem; + updated = true; + } + } + } else if (type === 'tag' && transaction.tagIds) { + for (let j = 0; j < transaction.tagIds.length; j++) { + const tagId = transaction.tagIds[j]; + const originalTagName = transaction.originalTagNames ? transaction.originalTagNames[j] : ""; + const targetItem = sourceTargetMap[originalTagName]; + + if (targetItem && (!tagId || tagId === '0' || !allTagsMap.value[tagId])) { + transaction.tagIds[j] = targetItem; + updated = true; + } + } + } + + if (updated) { + updatedCount++; + updateTransactionData(transaction); + } + } + } + + if (updatedCount > 0) { + snackbar.value?.showMessage('format.misc.youHaveUpdatedTransactions', { + count: updatedCount + }); + } + }); +} + function convertTransactionType(fromType: TransactionType, toType: TransactionType): void { if (!importTransactions.value || importTransactions.value.length < 1) { return; diff --git a/src/views/desktop/transactions/import/dialogs/BatchCreateDialog.vue b/src/views/desktop/transactions/import/dialogs/BatchCreateDialog.vue new file mode 100644 index 00000000..9b41a216 --- /dev/null +++ b/src/views/desktop/transactions/import/dialogs/BatchCreateDialog.vue @@ -0,0 +1,256 @@ + + +