support custom script to process delimiter-separated values (data) file / data
This commit is contained in:
@@ -5,6 +5,7 @@ export class KnownFileType {
|
||||
public static readonly CSV = new KnownFileType('csv', 'text/csv');
|
||||
public static readonly TSV = new KnownFileType('tsv', 'text/tab-separated-values');
|
||||
public static readonly MARKDOWN = new KnownFileType('md', 'text/markdown');
|
||||
public static readonly JS = new KnownFileType('js', 'application/javascript');
|
||||
|
||||
public readonly extension: string;
|
||||
public readonly contentType: string;
|
||||
@@ -30,6 +31,12 @@ export class KnownFileType {
|
||||
});
|
||||
}
|
||||
|
||||
public createFile(content: string, fileName: string): File {
|
||||
return new File([content], this.formatFileName(fileName), {
|
||||
type: this.contentType,
|
||||
});
|
||||
}
|
||||
|
||||
public static parse(extension: string): KnownFileType | undefined {
|
||||
return KnownFileType.allInstancesByExtension[extension];
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "Sie haben {count} Konten erfasst",
|
||||
"addNewTag": "Neuen Tag \"{tag}\" hinzufügen",
|
||||
"clickToSelectedFile": "Klicken Sie, um die Importdatei auszuwählen ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "{count} von {totalCount} ausgewählt",
|
||||
"youHaveUpdatedTransactions": "Sie haben {count} Transaktionen aktualisiert",
|
||||
"confirmImportTransactions": "Sind Sie sicher, dass Sie {count} Transaktionen importieren möchten?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Amount expression is invalid",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "Abbrechen",
|
||||
"Operation": "Vorgang",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Datendatei",
|
||||
"Data to import": "Data to import",
|
||||
"Please select a file to import": "Bitte wählen Sie eine Datei zum Importieren aus",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Ausgewählte Ausgabenkategorien im Batch ersetzen",
|
||||
"Batch Replace Selected Income Categories": "Ausgewählte Einnahmenkategorien im Batch ersetzen",
|
||||
"Batch Replace Selected Transfer Categories": "Ausgewählte Überweisungskategorien im Batch ersetzen",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "You have recorded {count} accounts",
|
||||
"addNewTag": "Add new tag \"{tag}\"",
|
||||
"clickToSelectedFile": "Click to select import file ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "Selected {count} of {totalCount}",
|
||||
"youHaveUpdatedTransactions": "You have updated {count} transactions",
|
||||
"confirmImportTransactions": "Are you sure you want to import {count} transactions?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Amount expression is invalid",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "Cancel",
|
||||
"Operation": "Operation",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Data File",
|
||||
"Data to import": "Data to import",
|
||||
"Please select a file to import": "Please select a file to import",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Batch Replace Selected Expense Categories",
|
||||
"Batch Replace Selected Income Categories": "Batch Replace Selected Income Categories",
|
||||
"Batch Replace Selected Transfer Categories": "Batch Replace Selected Transfer Categories",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "Has registrado {count} cuentas",
|
||||
"addNewTag": "Agregar nueva etiqueta \"{tag}\"",
|
||||
"clickToSelectedFile": "Haga clic para seleccionar el archivo de importación ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "Seleccionado {count} de {totalCount}",
|
||||
"youHaveUpdatedTransactions": "Has actualizado {count} transacciones",
|
||||
"confirmImportTransactions": "¿Está seguro de que desea importar {count} transacciones?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Amount expression is invalid",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "Aceptar",
|
||||
"Cancel": "Cancelar",
|
||||
"Operation": "Operación",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Archivo de datos",
|
||||
"Data to import": "Data to import",
|
||||
"Please select a file to import": "Please select a file to import",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Reemplazar por lotes categorías de gastos seleccionadas",
|
||||
"Batch Replace Selected Income Categories": "Reemplazo por lotes de categorías de ingresos seleccionadas",
|
||||
"Batch Replace Selected Transfer Categories": "Reemplazar por lotes las categorías de transferencia seleccionadas",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "Hai registrato {count} profili",
|
||||
"addNewTag": "Aggiungi nuovo giorno \"{tag}\"",
|
||||
"clickToSelectedFile": "Carica un file ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "{count} selezionati su {totalCount}",
|
||||
"youHaveUpdatedTransactions": "Hai aggiornato {count} transazioni",
|
||||
"confirmImportTransactions": "Sei sicuro di voler importare {count} transazioni?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Espressione dell'importo non valida",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "Annulla",
|
||||
"Operation": "Operazione",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "File dati",
|
||||
"Data to import": "Dati da importare",
|
||||
"Please select a file to import": "Seleziona un file da importare",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Sostituisci in blocco categorie di spesa selezionate",
|
||||
"Batch Replace Selected Income Categories": "Sostituisci in blocco categorie di entrata selezionate",
|
||||
"Batch Replace Selected Transfer Categories": "Sostituisci in blocco categorie di trasferimento selezionate",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "{count}アカウントを記録しました",
|
||||
"addNewTag": "新しいタグ\"{tag}\"を追加しました",
|
||||
"clickToSelectedFile": "クリックしてインポートファイルを選択します({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "{count} / {totalCount}を選択",
|
||||
"youHaveUpdatedTransactions": "{count}件の取引を更新しました",
|
||||
"confirmImportTransactions": "本当に{count}件の取引をインポートしますか?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Amount expression is invalid",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "キャンセル",
|
||||
"Operation": "操作",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "データファイル",
|
||||
"Data to import": "インポートするデータ",
|
||||
"Please select a file to import": "インポートするファイルを選択してください",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "バッチは選択した支出カテゴリを置き換えます",
|
||||
"Batch Replace Selected Income Categories": "バッチは選択した収入カテゴリを置き換えます",
|
||||
"Batch Replace Selected Transfer Categories": "バッチは選択した振替カテゴリを置き換えます",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "Je hebt {count} rekeningen geregistreerd",
|
||||
"addNewTag": "Nieuwe tag toevoegen \"{tag}\"",
|
||||
"clickToSelectedFile": "Klik om importbestand te selecteren ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "{count} van {totalCount} geselecteerd",
|
||||
"youHaveUpdatedTransactions": "Je hebt {count} transacties bijgewerkt",
|
||||
"confirmImportTransactions": "Weet je zeker dat je {count} transacties wilt importeren?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Bedragsexpressie is ongeldig",
|
||||
"invalid xml file": "Ongeldig XML-bestand",
|
||||
"invalid mt940 file": "Ongeldig MT940-bestand",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "Aangepaste wisselkoersgegevens niet gevonden",
|
||||
"cannot update exchange rate data for base currency": "Wisselkoersgegevens voor basisvaluta kunnen niet worden bijgewerkt",
|
||||
"cannot delete exchange rate data for base currency": "Wisselkoersgegevens voor basisvaluta kunnen niet worden verwijderd",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "Annuleren",
|
||||
"Operation": "Bewerking",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Gegevensbestand",
|
||||
"Data to import": "Te importeren gegevens",
|
||||
"Please select a file to import": "Selecteer een bestand om te importeren",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Datatoewijzingsbestand laden",
|
||||
"Save Data Mapping File": "Datatoewijzingsbestand opslaan",
|
||||
"Data mapping file is invalid": "Datatoewijzingsbestand is ongeldig",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Geselecteerde uitgavecategorieën batchgewijs vervangen",
|
||||
"Batch Replace Selected Income Categories": "Geselecteerde inkomencategorieën batchgewijs vervangen",
|
||||
"Batch Replace Selected Transfer Categories": "Geselecteerde overboekingscategorieën batchgewijs vervangen",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "Você registrou {count} contas",
|
||||
"addNewTag": "Adicionar nova etiqueta \"{tag}\"",
|
||||
"clickToSelectedFile": "Clique para selecionar arquivo de importação ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "Selecionado {count} de {totalCount}",
|
||||
"youHaveUpdatedTransactions": "Você atualizou {count} transações",
|
||||
"confirmImportTransactions": "Tem certeza de que deseja importar {count} transações?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Expressão de valor é inválida",
|
||||
"invalid xml file": "Arquivo XML inválido",
|
||||
"invalid mt940 file": "Arquivo MT940 inválido",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "Dados de taxa de câmbio personalizados do usuário não encontrados",
|
||||
"cannot update exchange rate data for base currency": "Não é possível atualizar dados de taxa de câmbio para a moeda base",
|
||||
"cannot delete exchange rate data for base currency": "Não é possível excluir dados de taxa de câmbio para a moeda base",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "Cancelar",
|
||||
"Operation": "Operação",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Arquivo de Dados",
|
||||
"Data to import": "Dados para importar",
|
||||
"Please select a file to import": "Por favor, selecione um arquivo para importar",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Substituir em Lote as Categorias de Despesas Selecionadas",
|
||||
"Batch Replace Selected Income Categories": "Substituir em Lote as Categorias de Renda Selecionadas",
|
||||
"Batch Replace Selected Transfer Categories": "Substituir em Lote as Categorias de Transferência Selecionadas",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "У вас зарегистрировано {count} учетных записей",
|
||||
"addNewTag": "Добавить новый тег \"{tag}\"",
|
||||
"clickToSelectedFile": "Нажмите, чтобы выбрать файл для импорта ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "Выбрано {count} из {totalCount}",
|
||||
"youHaveUpdatedTransactions": "Вы обновили {count} транзакций",
|
||||
"confirmImportTransactions": "Вы уверены, что хотите импортировать {count} транзакций?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Amount expression is invalid",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "ОК",
|
||||
"Cancel": "Отмена",
|
||||
"Operation": "Операция",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Файл данных",
|
||||
"Data to import": "Data to import",
|
||||
"Please select a file to import": "Please select a file to import",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Пакетная замена выбранных категорий расходов",
|
||||
"Batch Replace Selected Income Categories": "Пакетная замена выбранных категорий доходов",
|
||||
"Batch Replace Selected Transfer Categories": "Пакетная замена выбранных категорий переводов",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "У вас зареєстровано {count} рахунків",
|
||||
"addNewTag": "Додати новий тег \"{tag}\"",
|
||||
"clickToSelectedFile": "Натисніть, щоб вибрати файл для імпорту ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "Вибрано {count} з {totalCount}",
|
||||
"youHaveUpdatedTransactions": "Ви оновили {count} транзакцій",
|
||||
"confirmImportTransactions": "Ви впевнені, що хочете імпортувати {count} транзакцій?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Недійсний вираз суми",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "ОК",
|
||||
"Cancel": "Скасувати",
|
||||
"Operation": "Дія",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Файл даних",
|
||||
"Data to import": "Дані для імпорту",
|
||||
"Please select a file to import": "Будь ласка, виберіть файл для імпорту",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Пакетна заміна вибраних категорій витрат",
|
||||
"Batch Replace Selected Income Categories": "Пакетна заміна вибраних категорій доходів",
|
||||
"Batch Replace Selected Transfer Categories": "Пакетна заміна вибраних категорій переказів",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "Bạn đã ghi nhận {count} tài khoản",
|
||||
"addNewTag": "Add new tag \"{tag}\"",
|
||||
"clickToSelectedFile": "Nhấp để chọn tệp nhập khẩu ({extensions})",
|
||||
"previewCount": "Preview Count: {count}",
|
||||
"selectedCount": "Đã chọn {count} trên {totalCount}",
|
||||
"youHaveUpdatedTransactions": "Bạn đã cập nhật {count} giao dịch",
|
||||
"confirmImportTransactions": "Bạn có chắc chắn muốn nhập {count} giao dịch không?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_reconciliation_statements",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_reconciliation_statements",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_import_data_mapping",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_handling_script",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_import_replace_rule"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "Amount expression is invalid",
|
||||
"invalid xml file": "Invalid XML file",
|
||||
"invalid mt940 file": "Invalid MT940 file",
|
||||
"invalid json file": "Invalid JSON file",
|
||||
"user custom exchange rate data not found": "User custom exchange rate data is not found",
|
||||
"cannot update exchange rate data for base currency": "Cannot update exchange rate data for base currency",
|
||||
"cannot delete exchange rate data for base currency": "Cannot delete exchange rate data for base currency",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "Example script:",
|
||||
"functionDescription": "The parse function will be called for each row of the parsed file data, and the function name must be 'parse'",
|
||||
"functionParamRowDescription": "An array of string, each element is a column value",
|
||||
"functionParamIndexDescription": "The row index (0-based)",
|
||||
"functionReturnDescription": "An object representing a transaction (with the fields defined below), or null to skip this row",
|
||||
"fieldTimeDescription": "[required] Transaction time, format: YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[required] Transaction timezone offset in minutes, e.g. '480' for UTC+8, '-300' for UTC-5",
|
||||
"fieldTypeDescription": "[required] Transaction type, must be one of 'TransactionType.Income', 'TransactionType.Expense' or 'TransactionType.Transfer'",
|
||||
"fieldCategoryNameDescription": "[optional] Category name",
|
||||
"fieldSourceAccountNameDescription": "[optional] Source account name",
|
||||
"fieldDestinationAccountNameDescription": "[optional] Destination account name (for transfer type only)",
|
||||
"fieldSourceAmountDescription": "[required] Source amount",
|
||||
"fieldDestinationAmountDescription": "[optional] Destination amount (for transfer type only)",
|
||||
"fieldGeoLocationDescription": "[optional] Geolocation, format: 'longitude latitude', e.g. '116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[optional] Comma separated tag names, e.g. 'tag1;tag2;tag3'",
|
||||
"fieldCommentDescription": "[optional] Description"
|
||||
}
|
||||
},
|
||||
"OK": "OK",
|
||||
"Cancel": "Hủy",
|
||||
"Operation": "Thao tác",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "Alipay (Web) Statement File",
|
||||
"WeChat Pay Statement File": "WeChat Pay Statement File",
|
||||
"JD.com Finance Statement File": "JD.com Finance Statement File",
|
||||
"Handling Method": "Handling Method",
|
||||
"Column Mapping": "Column Mapping",
|
||||
"Custom Script": "Custom Script",
|
||||
"Execute Custom Script": "Execute Custom Script",
|
||||
"Execute Custom Script to Parse Data": "Execute Custom Script to Parse Data",
|
||||
"Data File": "Tệp dữ liệu",
|
||||
"Data to import": "Data to import",
|
||||
"Please select a file to import": "Please select a file to import",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "Load Data Mapping File",
|
||||
"Save Data Mapping File": "Save Data Mapping File",
|
||||
"Data mapping file is invalid": "Data mapping file is invalid",
|
||||
"Load Script File": "Load Script File",
|
||||
"Save Script File": "Save Script File",
|
||||
"Cannot load script file": "Cannot load script file",
|
||||
"No Preview Result": "No Preview Result",
|
||||
"Please execute the custom script first": "Please execute the custom script first",
|
||||
"Executing Script...": "Executing Script...",
|
||||
"No parse function defined": "No parse function defined",
|
||||
"Failed to execute custom script": "Failed to execute custom script",
|
||||
"Batch Replace Selected Expense Categories": "Thay thế hàng loạt các danh mục chi phí đã chọn",
|
||||
"Batch Replace Selected Income Categories": "Thay thế hàng loạt các danh mục thu nhập đã chọn",
|
||||
"Batch Replace Selected Transfer Categories": "Thay thế hàng loạt các danh mục chuyển khoản đã chọn",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "您已经记录了 {count} 个账户",
|
||||
"addNewTag": "添加新标签 \"{tag}\"",
|
||||
"clickToSelectedFile": "点击选择导入文件 ({extensions})",
|
||||
"previewCount": "预览数量: {count}",
|
||||
"selectedCount": "已选择 {count} / {totalCount}",
|
||||
"youHaveUpdatedTransactions": "您已经更新 {count} 个交易",
|
||||
"confirmImportTransactions": "您确定要导入 {count} 个交易?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_对账单",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_对账单",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_导入数据映射文件",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_导入处理脚本",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_导入替换规则文件"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "金额表达式无效",
|
||||
"invalid xml file": "无效的 XML 文件",
|
||||
"invalid mt940 file": "无效的 MT940 文件",
|
||||
"invalid json file": "无效的 JSON 文件",
|
||||
"user custom exchange rate data not found": "用户自定义汇率数据不存在",
|
||||
"cannot update exchange rate data for base currency": "不能更新默认货币的汇率数据",
|
||||
"cannot delete exchange rate data for base currency": "不能删除默认货币的汇率数据",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "示例脚本:",
|
||||
"functionDescription": "解析函数会在解析文件数据的每一行调用,函数名必须为 'parse'",
|
||||
"functionParamRowDescription": "字符串数组,每个元素为一列的值",
|
||||
"functionParamIndexDescription": "行索引 (从0开始)",
|
||||
"functionReturnDescription": "表示一笔交易的对象 (包含下面定义的字段),返回 null 时跳过此行",
|
||||
"fieldTimeDescription": "[必填] 交易时间,格式:YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[必填] 交易时区的分钟偏移量,例如:'480' 表示 UTC+8,'-300' 表示 UTC-5",
|
||||
"fieldTypeDescription": "[必填] 交易类型,必须为 'TransactionType.Income' (收入)、'TransactionType.Expense' (支出) 或 'TransactionType.Transfer' (转账)",
|
||||
"fieldCategoryNameDescription": "[可选] 分类名称",
|
||||
"fieldSourceAccountNameDescription": "[可选] 来源账户名称",
|
||||
"fieldDestinationAccountNameDescription": "[可选] 目标账户名称 (仅用于转账类型)",
|
||||
"fieldSourceAmountDescription": "[必填] 来源金额",
|
||||
"fieldDestinationAmountDescription": "[可选] 目标金额 (仅用于转账类型)",
|
||||
"fieldGeoLocationDescription": "[可选] 地理位置,格式:'经度 纬度',例如:'116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[可选] 以分号分隔的标签名称,例如:'标签1;标签2;标签3'",
|
||||
"fieldCommentDescription": "[可选] 描述"
|
||||
}
|
||||
},
|
||||
"OK": "确定",
|
||||
"Cancel": "取消",
|
||||
"Operation": "操作",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "支付宝 (网页版) 交易流水文件",
|
||||
"WeChat Pay Statement File": "微信支付账单文件",
|
||||
"JD.com Finance Statement File": "京东金融账单文件",
|
||||
"Handling Method": "处理方法",
|
||||
"Column Mapping": "列映射",
|
||||
"Custom Script": "自定义脚本",
|
||||
"Execute Custom Script": "执行自定义脚本",
|
||||
"Execute Custom Script to Parse Data": "执行自定义脚本解析数据",
|
||||
"Data File": "数据文件",
|
||||
"Data to import": "要导入的数据",
|
||||
"Please select a file to import": "请选择要导入的文件",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "加载数据映射文件",
|
||||
"Save Data Mapping File": "保存数据映射文件",
|
||||
"Data mapping file is invalid": "数据映射文件无效",
|
||||
"Load Script File": "加载脚本文件",
|
||||
"Save Script File": "保存脚本文件",
|
||||
"Cannot load script file": "无法加载脚本文件",
|
||||
"No Preview Result": "没有预览结果",
|
||||
"Please execute the custom script first": "请先执行自定义脚本",
|
||||
"Executing Script...": "正在执行脚本...",
|
||||
"No parse function defined": "没有定义解析函数 parse",
|
||||
"Failed to execute custom script": "执行自定义脚本失败",
|
||||
"Batch Replace Selected Expense Categories": "批量替换选中的支出分类",
|
||||
"Batch Replace Selected Income Categories": "批量替换选中的收入分类",
|
||||
"Batch Replace Selected Transfer Categories": "批量替换选中的转账分类",
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"youHaveAccounts": "您已經記錄了 {count} 個帳戶",
|
||||
"addNewTag": "新增標籤 \"{tag}\"",
|
||||
"clickToSelectedFile": "點擊選擇匯入檔案 ({extensions})",
|
||||
"previewCount": "預覽數量: {count}",
|
||||
"selectedCount": "已選擇 {count} / {totalCount}",
|
||||
"youHaveUpdatedTransactions": "您已經更新 {count} 個交易",
|
||||
"confirmImportTransactions": "您確定要匯入 {count} 個交易?",
|
||||
@@ -134,6 +135,7 @@
|
||||
"defaultExportReconciliationStatementsFileName": "ezBookkeeping_對帳單",
|
||||
"exportReconciliationStatementsFileName": "ezBookkeeping_{nickname}_對帳單",
|
||||
"defaultImportDataMappingFileName": "ezBookkeeping_匯入資料對應檔案",
|
||||
"defaultImportHandlingScript": "ezBookkeeping_匯入處理腳本",
|
||||
"defaultImportReplaceRuleFileName": "ezBookkeeping_匯入替換規則檔案"
|
||||
},
|
||||
"calendar": {
|
||||
@@ -1217,6 +1219,7 @@
|
||||
"invalid amount expression": "金額表達式無效",
|
||||
"invalid xml file": "無效的 XML 檔案",
|
||||
"invalid mt940 file": "無效的 MT940 檔案",
|
||||
"invalid json file": "無效的 JSON 檔案",
|
||||
"user custom exchange rate data not found": "使用者自訂匯率資料不存在",
|
||||
"cannot update exchange rate data for base currency": "不能更新基準貨幣的匯率資料",
|
||||
"cannot delete exchange rate data for base currency": "不能刪除基準貨幣的匯率資料",
|
||||
@@ -1349,6 +1352,26 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"sample": {
|
||||
"importTransactionCustomScript": {
|
||||
"headerComment": "範例腳本:",
|
||||
"functionDescription": "解析函式會在解析檔案資料的每一行呼叫,函式名稱必須為 'parse'",
|
||||
"functionParamRowDescription": "字串陣列,每個元素為一列的值",
|
||||
"functionParamIndexDescription": "行索引 (從0開始)",
|
||||
"functionReturnDescription": "表示一筆交易的物件 (包含下面定義的欄位),返回 null 時跳過此行",
|
||||
"fieldTimeDescription": "[必填] 交易時間,格式:YYYY-MM-DD HH:mm:ss",
|
||||
"fieldUtcOffsetDescription": "[必填] 交易時區的分鐘偏移量,例如:'480' 表示 UTC+8,'-300' 表示 UTC-5",
|
||||
"fieldTypeDescription": "[必填] 交易類型,必須為 'TransactionType.Income' (收入)、'TransactionType.Expense' (支出) 或 'TransactionType.Transfer' (轉帳)",
|
||||
"fieldCategoryNameDescription": "[可選] 分類名稱",
|
||||
"fieldSourceAccountNameDescription": "[可選] 來源帳戶名稱",
|
||||
"fieldDestinationAccountNameDescription": "[可選] 目標帳戶名稱 (僅用於轉帳類型)",
|
||||
"fieldSourceAmountDescription": "[必填] 來源金額",
|
||||
"fieldDestinationAmountDescription": "[可選] 目標金額 (僅用於轉帳類型)",
|
||||
"fieldGeoLocationDescription": "[可選] 地理位置,格式:'經度 緯度',例如:'116.3912972 39.9057136'",
|
||||
"fieldTagNamesDescription": "[可選] 以分號分隔的標籤名稱,例如:'標籤1;標籤2;標籤3'",
|
||||
"fieldCommentDescription": "[可選] 描述"
|
||||
}
|
||||
},
|
||||
"OK": "確定",
|
||||
"Cancel": "取消",
|
||||
"Operation": "操作",
|
||||
@@ -1777,6 +1800,11 @@
|
||||
"Alipay (Web) Statement File": "支付寶 (網頁版) 交易流水檔案",
|
||||
"WeChat Pay Statement File": "微信支付帳單檔案",
|
||||
"JD.com Finance Statement File": "京東金融帳單檔案",
|
||||
"Handling Method": "處理方法",
|
||||
"Column Mapping": "欄位對應",
|
||||
"Custom Script": "自訂腳本",
|
||||
"Execute Custom Script": "執行自訂腳本",
|
||||
"Execute Custom Script to Parse Data": "執行自訂腳本來解析資料",
|
||||
"Data File": "資料檔案",
|
||||
"Data to import": "要匯入的資料",
|
||||
"Please select a file to import": "請選擇要匯入的檔案",
|
||||
@@ -1799,6 +1827,14 @@
|
||||
"Load Data Mapping File": "載入資料對應檔案",
|
||||
"Save Data Mapping File": "儲存資料對應檔案",
|
||||
"Data mapping file is invalid": "資料對應檔案無效",
|
||||
"Load Script File": "載入腳本檔案",
|
||||
"Save Script File": "儲存腳本檔案",
|
||||
"Cannot load script file": "無法載入腳本檔案",
|
||||
"No Preview Result": "沒有預覽結果",
|
||||
"Please execute the custom script first": "請先執行自訂腳本",
|
||||
"Executing Script...": "正在執行腳本...",
|
||||
"No parse function defined": "沒有定義解析函式 parse",
|
||||
"Failed to execute custom script": "執行自訂腳本失敗",
|
||||
"Batch Replace Selected Expense Categories": "批次替換選中的支出分類",
|
||||
"Batch Replace Selected Income Categories": "批次替換選中的收入分類",
|
||||
"Batch Replace Selected Transfer Categories": "批次替換選中的轉帳分類",
|
||||
|
||||
@@ -103,6 +103,24 @@ export class ImportTransaction implements ImportTransactionResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ImportTransactionRequest {
|
||||
readonly transactions: ImportTransactionRequestItem[];
|
||||
}
|
||||
|
||||
export interface ImportTransactionRequestItem {
|
||||
readonly time: string;
|
||||
readonly utcOffset: string;
|
||||
readonly type: string;
|
||||
readonly categoryName?: string;
|
||||
readonly sourceAccountName?: string;
|
||||
readonly destinationAccountName?: string;
|
||||
readonly sourceAmount: string;
|
||||
readonly destinationAmount?: string;
|
||||
readonly geoLocation?: string;
|
||||
readonly tagNames?: string;
|
||||
readonly comment?: string;
|
||||
}
|
||||
|
||||
export interface ImportTransactionResponse {
|
||||
readonly type: number;
|
||||
readonly categoryId: string;
|
||||
|
||||
@@ -22,6 +22,21 @@
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading || submitting"
|
||||
v-if="currentStep === 'executeCustomScript' && importTransactionExecuteCustomScriptTab?.menus">
|
||||
<v-icon :icon="mdiDotsVertical" />
|
||||
<v-menu activator="parent" max-height="500">
|
||||
<v-list>
|
||||
<v-list-item :key="index"
|
||||
:prepend-icon="menu.prependIcon"
|
||||
:title="menu.title"
|
||||
:disabled="menu.disabled"
|
||||
@click="menu.onClick()"
|
||||
v-for="(menu, index) in importTransactionExecuteCustomScriptTab.menus"/>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
<v-btn density="comfortable" color="default" variant="text" class="ms-2"
|
||||
:icon="true" :disabled="loading || submitting"
|
||||
v-if="currentStep === 'checkData' && importTransactionCheckDataTab?.filterMenus">
|
||||
@@ -115,6 +130,21 @@
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="12" v-if="fileType === 'dsv' || fileType === 'dsv_data'">
|
||||
<v-select
|
||||
item-title="displayName"
|
||||
item-value="type"
|
||||
:disabled="submitting"
|
||||
:label="tt('Handling Method')"
|
||||
:placeholder="tt('Handling Method')"
|
||||
:items="[
|
||||
{ displayName: tt('Column Mapping'), type: ImportDSVProcessMethod.ColumnMapping },
|
||||
{ displayName: tt('Custom Script'), type: ImportDSVProcessMethod.CustomScript }
|
||||
]"
|
||||
v-model="processDSVMethod"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="12" v-if="!isImportDataFromTextbox">
|
||||
<v-text-field
|
||||
readonly
|
||||
@@ -157,6 +187,13 @@
|
||||
:disabled="loading || submitting"
|
||||
/>
|
||||
</v-window-item>
|
||||
<v-window-item value="executeCustomScript">
|
||||
<import-transaction-execute-custom-script-tab
|
||||
ref="importTransactionExecuteCustomScriptTab"
|
||||
:parsed-file-data="parsedFileData"
|
||||
:disabled="loading || submitting"
|
||||
/>
|
||||
</v-window-item>
|
||||
<v-window-item value="checkData">
|
||||
<import-transaction-check-data-tab
|
||||
ref="importTransactionCheckDataTab"
|
||||
@@ -177,7 +214,7 @@
|
||||
<v-btn class="button-icon-with-direction" color="primary"
|
||||
:disabled="loading || submitting || (!isImportDataFromTextbox && !importFile) || (isImportDataFromTextbox && !importData)"
|
||||
:append-icon="!submitting ? mdiArrowRight : undefined" @click="parseData"
|
||||
v-if="currentStep === 'defineColumn' || currentStep === 'uploadFile'">
|
||||
v-if="currentStep === 'defineColumn' || currentStep === 'executeCustomScript' || currentStep === 'uploadFile'">
|
||||
{{ tt('Next') }}
|
||||
<v-progress-circular indeterminate size="22" class="ms-2" v-if="submitting"></v-progress-circular>
|
||||
</v-btn>
|
||||
@@ -206,6 +243,7 @@ import type { StepBarItem } from '@/components/desktop/StepsBar.vue';
|
||||
import ConfirmDialog from '@/components/desktop/ConfirmDialog.vue';
|
||||
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||
import ImportTransactionDefineColumnTab from './tabs/ImportTransactionDefineColumnTab.vue';
|
||||
import ImportTransactionExecuteCustomScriptTab from './tabs/ImportTransactionExecuteCustomScriptTab.vue';
|
||||
import ImportTransactionCheckDataTab from './tabs/ImportTransactionCheckDataTab.vue';
|
||||
|
||||
import { ref, computed, useTemplateRef, watch } from 'vue';
|
||||
@@ -222,6 +260,7 @@ import { useStatisticsStore } from '@/stores/statistics.ts';
|
||||
import { itemAndIndex } from '@/core/base.ts';
|
||||
import { type NumeralSystem } from '@/core/numeral.ts';
|
||||
import { TransactionType } from '@/core/transaction.ts';
|
||||
import { KnownFileType } from '@/core/file.ts';
|
||||
|
||||
import type { LocalizedImportFileCategoryAndTypes, LocalizedImportFileType, LocalizedImportFileTypeSubType, LocalizedImportFileTypeSupportedEncodings } from '@/core/file.ts';
|
||||
import { ImportTransaction } from '@/models/imported_transaction.ts';
|
||||
@@ -243,9 +282,14 @@ import {
|
||||
type ConfirmDialogType = InstanceType<typeof ConfirmDialog>;
|
||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||
type ImportTransactionDefineColumnTabType = InstanceType<typeof ImportTransactionDefineColumnTab>;
|
||||
type ImportTransactionExecuteCustomScriptTabType = InstanceType<typeof ImportTransactionExecuteCustomScriptTab>;
|
||||
type ImportTransactionCheckDataTabType = InstanceType<typeof ImportTransactionCheckDataTab>;
|
||||
|
||||
type ImportTransactionDialogStep = 'uploadFile' | 'defineColumn' | 'checkData' | 'finalResult';
|
||||
type ImportTransactionDialogStep = 'uploadFile' | 'defineColumn' | 'executeCustomScript' | 'checkData' | 'finalResult';
|
||||
enum ImportDSVProcessMethod {
|
||||
ColumnMapping,
|
||||
CustomScript
|
||||
};
|
||||
|
||||
defineProps<{
|
||||
persistent?: boolean;
|
||||
@@ -268,6 +312,7 @@ const statisticsStore = useStatisticsStore();
|
||||
const confirmDialog = useTemplateRef<ConfirmDialogType>('confirmDialog');
|
||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||
const importTransactionDefineColumnTab = useTemplateRef<ImportTransactionDefineColumnTabType>('importTransactionDefineColumnTab');
|
||||
const importTransactionExecuteCustomScriptTab = useTemplateRef<ImportTransactionExecuteCustomScriptTabType>('importTransactionExecuteCustomScriptTab');
|
||||
const importTransactionCheckDataTab = useTemplateRef<ImportTransactionCheckDataTabType>('importTransactionCheckDataTab');
|
||||
const fileInput = useTemplateRef<HTMLInputElement>('fileInput');
|
||||
|
||||
@@ -278,6 +323,7 @@ const importProcess = ref<number>(0);
|
||||
const fileType = ref<string>('ezbookkeeping');
|
||||
const fileSubType = ref<string>('ezbookkeeping_csv');
|
||||
const fileEncoding = ref<string>('utf-8');
|
||||
const processDSVMethod = ref<ImportDSVProcessMethod>(ImportDSVProcessMethod.ColumnMapping);
|
||||
const importFile = ref<File | null>(null);
|
||||
const importData = ref<string>('');
|
||||
const parsedFileData = ref<string[][] | undefined>(undefined);
|
||||
@@ -307,11 +353,19 @@ const allSteps = computed<StepBarItem[]>(() => {
|
||||
];
|
||||
|
||||
if (fileType.value === 'dsv' || fileType.value === 'dsv_data') {
|
||||
steps.push({
|
||||
name: 'defineColumn',
|
||||
title: tt('Define Column'),
|
||||
subTitle: tt('Define and Check Column Mapping')
|
||||
});
|
||||
if (processDSVMethod.value === ImportDSVProcessMethod.CustomScript) {
|
||||
steps.push({
|
||||
name: 'executeCustomScript',
|
||||
title: tt('Execute Custom Script'),
|
||||
subTitle: tt('Execute Custom Script to Parse Data')
|
||||
});
|
||||
} else {
|
||||
steps.push({
|
||||
name: 'defineColumn',
|
||||
title: tt('Define Column'),
|
||||
subTitle: tt('Define and Check Column Mapping')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
steps.push(...[
|
||||
@@ -378,12 +432,14 @@ function open(): Promise<void> {
|
||||
fileType.value = 'ezbookkeeping';
|
||||
fileSubType.value = 'ezbookkeeping_csv';
|
||||
fileEncoding.value = 'utf-8';
|
||||
processDSVMethod.value = ImportDSVProcessMethod.ColumnMapping;
|
||||
currentStep.value = 'uploadFile';
|
||||
importProcess.value = 0;
|
||||
importFile.value = null;
|
||||
importData.value = '';
|
||||
parsedFileData.value = undefined;
|
||||
importTransactionDefineColumnTab.value?.reset();
|
||||
importTransactionExecuteCustomScriptTab.value?.reset();
|
||||
importTransactions.value = undefined;
|
||||
importTransactionCheckDataTab.value?.reset();
|
||||
showState.value = true;
|
||||
@@ -466,9 +522,9 @@ function parseData(): void {
|
||||
}
|
||||
|
||||
if (type === 'custom_csv') {
|
||||
uploadFile = new File([importData.value], 'import.csv', { type: 'text/csv' });
|
||||
uploadFile = KnownFileType.CSV.createFile(importData.value, 'import');
|
||||
} else if (type === 'custom_tsv') {
|
||||
uploadFile = new File([importData.value], 'import.tsv', { type: 'text/tab-separated-values' });
|
||||
uploadFile = KnownFileType.TSV.createFile(importData.value, 'import');
|
||||
} else {
|
||||
snackbar.value?.showError('Parameter Invalid');
|
||||
return;
|
||||
@@ -491,9 +547,15 @@ function parseData(): void {
|
||||
importFile: uploadFile
|
||||
}).then(response => {
|
||||
if (response && response.length) {
|
||||
importTransactionDefineColumnTab.value?.reset();
|
||||
parsedFileData.value = response;
|
||||
currentStep.value = 'defineColumn';
|
||||
if (processDSVMethod.value === ImportDSVProcessMethod.CustomScript) {
|
||||
importTransactionExecuteCustomScriptTab.value?.reset();
|
||||
parsedFileData.value = response;
|
||||
currentStep.value = 'executeCustomScript';
|
||||
} else {
|
||||
importTransactionDefineColumnTab.value?.reset();
|
||||
parsedFileData.value = response;
|
||||
currentStep.value = 'defineColumn';
|
||||
}
|
||||
} else {
|
||||
parsedFileData.value = undefined;
|
||||
snackbar.value?.showError('No data to import');
|
||||
@@ -519,7 +581,7 @@ function parseData(): void {
|
||||
let geoLocationOrder: string | undefined = undefined;
|
||||
let tagSeparator: string | undefined = undefined;
|
||||
|
||||
if (isDsvFileType) {
|
||||
if (isDsvFileType && processDSVMethod.value === ImportDSVProcessMethod.ColumnMapping) {
|
||||
const defineColumnResult = importTransactionDefineColumnTab.value?.generateResult();
|
||||
|
||||
if (!defineColumnResult) {
|
||||
@@ -536,6 +598,16 @@ function parseData(): void {
|
||||
geoLocationSeparator = defineColumnResult.geoLocationSeparator;
|
||||
geoLocationOrder = defineColumnResult.geoLocationOrder;
|
||||
tagSeparator = defineColumnResult.tagSeparator;
|
||||
} else if (isDsvFileType && processDSVMethod.value === ImportDSVProcessMethod.CustomScript) {
|
||||
const executeCustomScriptResult = importTransactionExecuteCustomScriptTab.value?.generateResult();
|
||||
|
||||
if (!executeCustomScriptResult) {
|
||||
return;
|
||||
}
|
||||
|
||||
type = 'ezbookkeeping_json';
|
||||
encoding = undefined;
|
||||
uploadFile = KnownFileType.JSON.createFile(executeCustomScriptResult, 'import');
|
||||
}
|
||||
|
||||
submitting.value = true;
|
||||
|
||||
+346
@@ -0,0 +1,346 @@
|
||||
<template>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<div class="d-flex w-100 mb-2">
|
||||
<v-btn density="compact" variant="tonal" :prepend-icon="mdiPlay"
|
||||
:disabled="disabled || !sandboxLoaded || executingScript" :loading="executingScript"
|
||||
@click="executeCustomScript()">
|
||||
<template #loader>
|
||||
<v-progress-circular indeterminate size="18" class="me-1"/>
|
||||
<span>{{ tt('Execute Custom Script') }}</span>
|
||||
</template>
|
||||
<span>{{ tt('Execute Custom Script') }}</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-textarea class="w-100" style="height: 360px" :readonly="disabled"
|
||||
v-model="customScript"></v-textarea>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<div class="d-flex w-100 mb-2">
|
||||
<v-btn density="compact" color="default" variant="text"
|
||||
:disabled="disabled || !sandboxLoaded || executingScript || !previewResult">
|
||||
<span>{{ tt('format.misc.previewCount', { count: previewCount > 0 ? getDisplayCount(previewCount) : tt('All') }) }}</span>
|
||||
<v-menu activator="parent">
|
||||
<v-list>
|
||||
<v-list-item :key="count.value" :title="count.name"
|
||||
v-for="count in previewCounts"
|
||||
@click="previewCount = count.value"></v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-btn>
|
||||
</div>
|
||||
<div class="w-100 code-container">
|
||||
<v-textarea class="w-100 always-cursor-text" style="height: 360px" :readonly="true"
|
||||
:value="displayPreviewResult"></v-textarea>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<iframe id="sandbox" ref="sandbox" sandbox="allow-scripts" style="display: none;"></iframe>
|
||||
<snack-bar ref="snackbar" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SnackBar from '@/components/desktop/SnackBar.vue';
|
||||
|
||||
import { ref, computed, useTemplateRef, onMounted, onUnmounted } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import type { NameNumeralValue } from '@/core/base.ts';
|
||||
import type { NumeralSystem } from '@/core/numeral.ts';
|
||||
import { KnownFileType } from '@/core/file.ts';
|
||||
|
||||
import type { ImportTransactionRequest, ImportTransactionRequestItem } from '@/models/imported_transaction.ts';
|
||||
|
||||
import { isDefined } from '@/lib/common.ts';
|
||||
import {
|
||||
openTextFileContent,
|
||||
startDownloadFile
|
||||
} from '@/lib/ui/common.ts';
|
||||
import logger from '@/lib/logger.ts';
|
||||
|
||||
import {
|
||||
mdiPlay,
|
||||
mdiFolderOpenOutline,
|
||||
mdiContentSaveOutline
|
||||
} from '@mdi/js';
|
||||
|
||||
type SnackBarType = InstanceType<typeof SnackBar>;
|
||||
|
||||
type SandboxRequest = {
|
||||
parsedFileData: string[][];
|
||||
code: string;
|
||||
};
|
||||
|
||||
type SandboxResponse = {
|
||||
result?: string;
|
||||
knownError?: string;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
interface ImportTransactionDefineColumnMenu {
|
||||
prependIcon: string;
|
||||
title: string;
|
||||
disabled?: boolean;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
parsedFileData?: string[][];
|
||||
disabled?: boolean;
|
||||
}>();
|
||||
|
||||
const { tt, getCurrentNumeralSystemType } = useI18n();
|
||||
|
||||
const sandbox = useTemplateRef<HTMLIFrameElement>('sandbox');
|
||||
const snackbar = useTemplateRef<SnackBarType>('snackbar');
|
||||
|
||||
const sandboxLoaded = ref<boolean>(false);
|
||||
const customScript = ref<string>('');
|
||||
const previewResult = ref<ImportTransactionRequestItem[] | undefined>(undefined);
|
||||
const executingScript = ref<boolean>(false);
|
||||
const previewCount = ref<number>(10);
|
||||
|
||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||
const previewCounts = computed<NameNumeralValue[]>(() => getTablePageOptions(previewResult.value?.length));
|
||||
|
||||
const sampleScript = computed<string>(() => `// ${tt('sample.importTransactionCustomScript.headerComment')}
|
||||
/**
|
||||
* ${tt('sample.importTransactionCustomScript.functionDescription')}
|
||||
* @param {array} row - ${tt('sample.importTransactionCustomScript.functionParamRowDescription')}
|
||||
* @param {number} index - ${tt('sample.importTransactionCustomScript.functionParamIndexDescription')}
|
||||
* @returns {object|null} ${tt('sample.importTransactionCustomScript.functionReturnDescription')}
|
||||
*/
|
||||
function parse(row, index) {
|
||||
if (index < 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
time: row[0], // ${tt('sample.importTransactionCustomScript.fieldTimeDescription')}
|
||||
utcOffset: '480', // ${tt('sample.importTransactionCustomScript.fieldUtcOffsetDescription')}
|
||||
type: TransactionType.Expense, // ${tt('sample.importTransactionCustomScript.fieldTypeDescription')}
|
||||
categoryName: row[4], // ${tt('sample.importTransactionCustomScript.fieldCategoryNameDescription')}
|
||||
sourceAccountName: row[5], // ${tt('sample.importTransactionCustomScript.fieldSourceAccountNameDescription')}
|
||||
destinationAccountName: row[8], // ${tt('sample.importTransactionCustomScript.fieldDestinationAccountNameDescription')}
|
||||
sourceAmount: row[7], // ${tt('sample.importTransactionCustomScript.fieldSourceAmountDescription')}
|
||||
destinationAmount: row[10], // ${tt('sample.importTransactionCustomScript.fieldDestinationAmountDescription')}
|
||||
geoLocation: undefined, // ${tt('sample.importTransactionCustomScript.fieldGeoLocationDescription')}
|
||||
tagNames: '', // ${tt('sample.importTransactionCustomScript.fieldTagNamesDescription')}
|
||||
description: row[13] // ${tt('sample.importTransactionCustomScript.fieldCommentDescription')}
|
||||
};
|
||||
}`);
|
||||
|
||||
const displayPreviewResult = computed<string>(() => {
|
||||
if (executingScript.value) {
|
||||
return tt('Executing Script...');
|
||||
} else if (previewResult.value) {
|
||||
const rows = previewResult.value.slice(0, previewCount.value);
|
||||
return JSON.stringify(rows, null, 2);
|
||||
} else {
|
||||
return tt('No Preview Result');
|
||||
}
|
||||
});
|
||||
|
||||
const menus = computed<ImportTransactionDefineColumnMenu[]>(() => [
|
||||
{
|
||||
prependIcon: mdiFolderOpenOutline,
|
||||
title: tt('Load Script File'),
|
||||
onClick: loadScriptFile
|
||||
},
|
||||
{
|
||||
prependIcon: mdiContentSaveOutline,
|
||||
title: tt('Save Script File'),
|
||||
onClick: saveScriptFile
|
||||
}
|
||||
]);
|
||||
|
||||
function getDisplayCount(count: number): string {
|
||||
return numeralSystem.value.formatNumber(count);
|
||||
}
|
||||
|
||||
function getTablePageOptions(linesCount?: number): NameNumeralValue[] {
|
||||
const pageOptions: NameNumeralValue[] = [];
|
||||
|
||||
if (!linesCount || linesCount < 1) {
|
||||
pageOptions.push({ value: -1, name: tt('All') });
|
||||
return pageOptions;
|
||||
}
|
||||
|
||||
for (const count of [ 10, 50, 100 ]) {
|
||||
if (linesCount < count) {
|
||||
break;
|
||||
}
|
||||
|
||||
pageOptions.push({ value: count, name: getDisplayCount(count) });
|
||||
}
|
||||
|
||||
pageOptions.push({ value: -1, name: tt('All') });
|
||||
|
||||
return pageOptions;
|
||||
}
|
||||
|
||||
function reloadSandbox(): void {
|
||||
sandboxLoaded.value = false;
|
||||
|
||||
if (sandbox.value) {
|
||||
sandbox.value.src = 'about:blank';
|
||||
sandbox.value.srcdoc = `
|
||||
<script>
|
||||
window.TransactionType = {
|
||||
Income: 'Income',
|
||||
Expense: 'Expense',
|
||||
Transfer: 'Transfer'
|
||||
};
|
||||
|
||||
window.addEventListener('message', function (event) {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
const parsedFileData = data.parsedFileData;
|
||||
eval(data.code);
|
||||
|
||||
if (window.parse) {
|
||||
const result = [];
|
||||
|
||||
for (let i = 0; i < parsedFileData.length; i++) {
|
||||
try {
|
||||
const row = parsedFileData[i];
|
||||
const transaction = window.parse(row, i);
|
||||
|
||||
if (transaction) {
|
||||
result.push(transaction);
|
||||
}
|
||||
} catch (error) {
|
||||
window.parent.postMessage({ error: error.message }, '*');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
window.parent.postMessage({ result: JSON.stringify(result) }, '*');
|
||||
} else {
|
||||
window.parent.postMessage({ knownError: 'No parse function defined' }, '*');
|
||||
}
|
||||
} catch (error) {
|
||||
window.parent.postMessage({ error: error.message }, '*');
|
||||
}
|
||||
});
|
||||
<\/script>
|
||||
`;
|
||||
|
||||
sandbox.value.onload = () => {
|
||||
sandboxLoaded.value = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function executeCustomScript(): void {
|
||||
if (!sandbox.value || props.disabled || executingScript.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
executingScript.value = true;
|
||||
|
||||
const sandboxRequest: SandboxRequest = {
|
||||
parsedFileData: props.parsedFileData || [],
|
||||
code: customScript.value + '\n\n;window.parse = parse;'
|
||||
};
|
||||
|
||||
sandbox.value?.contentWindow?.postMessage(JSON.stringify(sandboxRequest), '*');
|
||||
}
|
||||
|
||||
function generateResult(): string | undefined {
|
||||
if (!previewResult.value) {
|
||||
snackbar.value?.showError('Please execute the custom script first');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result: ImportTransactionRequest = {
|
||||
transactions: previewResult.value
|
||||
};
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
function reset(): void {
|
||||
customScript.value = sampleScript.value;
|
||||
previewResult.value = undefined;
|
||||
executingScript.value = false;
|
||||
previewCount.value = 10;
|
||||
}
|
||||
|
||||
function loadScriptFile(): void {
|
||||
openTextFileContent({
|
||||
allowedExtensions: KnownFileType.JS.contentType
|
||||
}).then(content => {
|
||||
customScript.value = content;
|
||||
}).catch(error => {
|
||||
logger.error('Failed to load script file', error);
|
||||
snackbar.value?.showError('Cannot load script file');
|
||||
});
|
||||
}
|
||||
|
||||
function saveScriptFile(): void {
|
||||
const fileName = KnownFileType.JS.formatFileName(tt('dataExport.defaultImportHandlingScript'));
|
||||
startDownloadFile(fileName, KnownFileType.JS.createBlob(customScript.value));
|
||||
}
|
||||
|
||||
function onMessage(event: MessageEvent<SandboxResponse>): void {
|
||||
if (event.source !== sandbox.value?.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
executingScript.value = false;
|
||||
|
||||
const data = event.data;
|
||||
|
||||
if (data.knownError) {
|
||||
snackbar.value?.showError(data.knownError);
|
||||
previewResult.value = undefined;
|
||||
} else if (data.error) {
|
||||
logger.error('Failed to execute custom script: ' + data.error);
|
||||
snackbar.value?.showError('Failed to execute custom script');
|
||||
previewResult.value = undefined;
|
||||
} else if (data.result) {
|
||||
const originalResult = JSON.parse(data.result) as Record<string, unknown>[];
|
||||
const finalResult: ImportTransactionRequestItem[] = [];
|
||||
|
||||
for (const item of originalResult) {
|
||||
const finalItem: ImportTransactionRequestItem = {
|
||||
time: (isDefined(item['time'])) ? String(item['time']) : '',
|
||||
utcOffset: (isDefined(item['utcOffset'])) ? String(item['utcOffset']) : '',
|
||||
type: (isDefined(item['type'])) ? String(item['type']) : '',
|
||||
categoryName: (isDefined(item['categoryName']) && item['categoryName'] !== '') ? String(item['categoryName']) : undefined,
|
||||
sourceAccountName: (isDefined(item['sourceAccountName']) && item['sourceAccountName'] !== '') ? String(item['sourceAccountName']) : undefined,
|
||||
destinationAccountName: (isDefined(item['destinationAccountName']) && item['destinationAccountName'] !== '') ? String(item['destinationAccountName']) : undefined,
|
||||
sourceAmount: (isDefined(item['sourceAmount'])) ? String(item['sourceAmount']) : '',
|
||||
destinationAmount: (isDefined(item['destinationAmount']) && item['destinationAmount'] !== '') ? String(item['destinationAmount']) : undefined,
|
||||
geoLocation: (isDefined(item['geoLocation']) && item['geoLocation']) ? String(item['geoLocation']) : undefined,
|
||||
tagNames: (isDefined(item['tagNames']) && item['tagNames']) ? String(item['tagNames']) : undefined,
|
||||
comment: (isDefined(item['description']) && item['description']) ? String(item['description']) : undefined
|
||||
};
|
||||
finalResult.push(finalItem);
|
||||
}
|
||||
|
||||
previewResult.value = finalResult;
|
||||
}
|
||||
|
||||
reloadSandbox();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
customScript.value = sampleScript.value;
|
||||
reloadSandbox();
|
||||
window.addEventListener('message', onMessage);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('message', onMessage);
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
menus,
|
||||
generateResult,
|
||||
reset
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user