use the daylight saving time zone as default time zone rather than the current standard time zone during the DST
This commit is contained in:
+6
-6
@@ -150,10 +150,10 @@ func (a *AccountsApi) AccountCreateHandler(c *core.WebContext) (any, *errs.Error
|
|||||||
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, utcOffset, err := c.GetClientTimezone()
|
clientTimezone, _, err := c.GetClientTimezone()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf(c, "[accounts.AccountCreateHandler] cannot get client timezone offset, because %s", err.Error())
|
log.Warnf(c, "[accounts.AccountCreateHandler] cannot get client timezone, because %s", err.Error())
|
||||||
return nil, errs.ErrClientTimezoneOffsetInvalid
|
return nil, errs.ErrClientTimezoneOffsetInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +278,7 @@ func (a *AccountsApi) AccountCreateHandler(c *core.WebContext) (any, *errs.Error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.accounts.CreateAccounts(c, mainAccount, accountCreateReq.BalanceTime, childrenAccounts, childrenAccountBalanceTimes, utcOffset)
|
err = a.accounts.CreateAccounts(c, mainAccount, accountCreateReq.BalanceTime, childrenAccounts, childrenAccountBalanceTimes, clientTimezone)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(c, "[accounts.AccountCreateHandler] failed to create account \"id:%d\" for user \"uid:%d\", because %s", mainAccount.AccountId, uid, err.Error())
|
log.Errorf(c, "[accounts.AccountCreateHandler] failed to create account \"id:%d\" for user \"uid:%d\", because %s", mainAccount.AccountId, uid, err.Error())
|
||||||
@@ -315,10 +315,10 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
|
|||||||
return nil, errs.ErrAccountIdInvalid
|
return nil, errs.ErrAccountIdInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
_, utcOffset, err := c.GetClientTimezone()
|
clientTimezone, _, err := c.GetClientTimezone()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf(c, "[accounts.AccountModifyHandler] cannot get client timezone offset, because %s", err.Error())
|
log.Warnf(c, "[accounts.AccountModifyHandler] cannot get client timezone, because %s", err.Error())
|
||||||
return nil, errs.ErrClientTimezoneOffsetInvalid
|
return nil, errs.ErrClientTimezoneOffsetInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,7 +521,7 @@ func (a *AccountsApi) AccountModifyHandler(c *core.WebContext) (any, *errs.Error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = a.accounts.ModifyAccounts(c, mainAccount, toUpdateAccounts, toAddAccounts, toAddAccountBalanceTimes, toDeleteAccountIds, utcOffset)
|
err = a.accounts.ModifyAccounts(c, mainAccount, toUpdateAccounts, toAddAccounts, toAddAccountBalanceTimes, toDeleteAccountIds, clientTimezone)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(c, "[accounts.AccountModifyHandler] failed to update account \"id:%d\" for user \"uid:%d\", because %s", accountModifyReq.Id, uid, err.Error())
|
log.Errorf(c, "[accounts.AccountModifyHandler] failed to update account \"id:%d\" for user \"uid:%d\", because %s", accountModifyReq.Id, uid, err.Error())
|
||||||
|
|||||||
@@ -302,11 +302,11 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType
|
|||||||
return nil, "", errs.NewIncompleteOrIncorrectSubmissionError(err)
|
return nil, "", errs.NewIncompleteOrIncorrectSubmissionError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
timezone, _, err := c.GetClientTimezone()
|
clientTimezone, _, err := c.GetClientTimezone()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf(c, "[data_managements.getExportedFileContent] cannot get client timezone offset, because %s", err.Error())
|
log.Warnf(c, "[data_managements.getExportedFileContent] cannot get client timezone, because %s", err.Error())
|
||||||
timezone = time.Local
|
clientTimezone = time.Local
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := c.GetCurrentUid()
|
uid := c.GetCurrentUid()
|
||||||
@@ -413,13 +413,13 @@ func (a *DataManagementsApi) getExportedFileContent(c *core.WebContext, fileType
|
|||||||
return nil, "", errs.Or(err, errs.ErrOperationFailed)
|
return nil, "", errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := a.getFileName(user, timezone, fileType)
|
fileName := a.getFileName(user, clientTimezone, fileType)
|
||||||
|
|
||||||
return result, fileName, nil
|
return result, fileName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *DataManagementsApi) getFileName(user *models.User, timezone *time.Location, fileExtension string) string {
|
func (a *DataManagementsApi) getFileName(user *models.User, clientTimezone *time.Location, fileExtension string) string {
|
||||||
currentTime := utils.FormatUnixTimeToLongDateTimeWithoutSecond(time.Now().Unix(), timezone)
|
currentTime := utils.FormatUnixTimeToLongDateTimeWithoutSecond(time.Now().Unix(), clientTimezone)
|
||||||
currentTime = strings.Replace(currentTime, "-", "_", -1)
|
currentTime = strings.Replace(currentTime, "-", "_", -1)
|
||||||
currentTime = strings.Replace(currentTime, " ", "_", -1)
|
currentTime = strings.Replace(currentTime, " ", "_", -1)
|
||||||
currentTime = strings.Replace(currentTime, ":", "_", -1)
|
currentTime = strings.Replace(currentTime, ":", "_", -1)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func (a *LargeLanguageModelsApi) RecognizeReceiptImageHandler(c *core.WebContext
|
|||||||
return nil, errs.ErrLargeLanguageModelProviderNotEnabled
|
return nil, errs.ErrLargeLanguageModelProviderNotEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
clientTimezone, utcOffset, err := c.GetClientTimezone()
|
clientTimezone, _, err := c.GetClientTimezone()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf(c, "[large_language_models.RecognizeReceiptImageHandler] cannot get client timezone, because %s", err.Error())
|
log.Warnf(c, "[large_language_models.RecognizeReceiptImageHandler] cannot get client timezone, because %s", err.Error())
|
||||||
@@ -238,10 +238,10 @@ func (a *LargeLanguageModelsApi) RecognizeReceiptImageHandler(c *core.WebContext
|
|||||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.parseRecognizedReceiptImageResponse(c, uid, utcOffset, result, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return a.parseRecognizedReceiptImageResponse(c, uid, clientTimezone, result, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *LargeLanguageModelsApi) parseRecognizedReceiptImageResponse(c *core.WebContext, uid int64, utcOffset int16, recognizedResult *models.RecognizedReceiptImageResult, accountMap map[string]*models.Account, expenseCategoryMap map[string]*models.TransactionCategory, incomeCategoryMap map[string]*models.TransactionCategory, transferCategoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (*models.RecognizedReceiptImageResponse, *errs.Error) {
|
func (a *LargeLanguageModelsApi) parseRecognizedReceiptImageResponse(c *core.WebContext, uid int64, clientTimezone *time.Location, recognizedResult *models.RecognizedReceiptImageResult, accountMap map[string]*models.Account, expenseCategoryMap map[string]*models.TransactionCategory, incomeCategoryMap map[string]*models.TransactionCategory, transferCategoryMap map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (*models.RecognizedReceiptImageResponse, *errs.Error) {
|
||||||
recognizedReceiptImageResponse := &models.RecognizedReceiptImageResponse{
|
recognizedReceiptImageResponse := &models.RecognizedReceiptImageResponse{
|
||||||
Type: models.TRANSACTION_TYPE_EXPENSE,
|
Type: models.TRANSACTION_TYPE_EXPENSE,
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,7 @@ func (a *LargeLanguageModelsApi) parseRecognizedReceiptImageResponse(c *core.Web
|
|||||||
|
|
||||||
if len(recognizedResult.Time) > 0 {
|
if len(recognizedResult.Time) > 0 {
|
||||||
longDateTime := a.getLongDateTime(recognizedResult.Time)
|
longDateTime := a.getLongDateTime(recognizedResult.Time)
|
||||||
timestamp, err := utils.ParseFromLongDateTime(longDateTime, utcOffset)
|
timestamp, err := utils.ParseFromLongDateTimeInTimeZone(longDateTime, clientTimezone)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf(c, "[large_language_models.parseRecognizedReceiptImageResponse] recoginzed time \"%s\" is invalid", recognizedResult.Time)
|
log.Warnf(c, "[large_language_models.parseRecognizedReceiptImageResponse] recoginzed time \"%s\" is invalid", recognizedResult.Time)
|
||||||
|
|||||||
@@ -1488,10 +1488,10 @@ func (a *TransactionsApi) TransactionParseImportFileHandler(c *core.WebContext)
|
|||||||
return nil, errs.ErrParameterInvalid
|
return nil, errs.ErrParameterInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
_, utcOffset, err := c.GetClientTimezone()
|
clientTimezone, _, err := c.GetClientTimezone()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf(c, "[transactions.TransactionParseImportFileHandler] cannot get client timezone offset, because %s", err.Error())
|
log.Warnf(c, "[transactions.TransactionParseImportFileHandler] cannot get client timezone, because %s", err.Error())
|
||||||
return nil, errs.ErrClientTimezoneOffsetInvalid
|
return nil, errs.ErrClientTimezoneOffsetInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1688,7 +1688,7 @@ func (a *TransactionsApi) TransactionParseImportFileHandler(c *core.WebContext)
|
|||||||
|
|
||||||
tagMap := a.transactionTags.GetVisibleTagNameMapByList(tags)
|
tagMap := a.transactionTags.GetVisibleTagNameMapByList(tags)
|
||||||
|
|
||||||
parsedTransactions, _, _, _, _, _, err := dataImporter.ParseImportedData(c, user, fileData, utcOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
parsedTransactions, _, _, _, _, _, err := dataImporter.ParseImportedData(c, user, fileData, clientTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(c, "[transactions.TransactionParseImportFileHandler] failed to parse imported data for user \"uid:%d\", because %s", user.Uid, err.Error())
|
log.Errorf(c, "[transactions.TransactionParseImportFileHandler] failed to parse imported data for user \"uid:%d\", because %s", user.Uid, err.Error())
|
||||||
|
|||||||
@@ -819,7 +819,7 @@ func (l *UserDataCli) ImportTransaction(c *core.CliContext, username string, fil
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedTransactions, newAccounts, newSubExpenseCategories, newSubIncomeCategories, newSubTransferCategories, newTags, err := dataImporter.ParseImportedData(c, user, data, utils.GetTimezoneOffsetMinutes(time.Local), converter.DefaultImporterOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
parsedTransactions, newAccounts, newSubExpenseCategories, newSubIncomeCategories, newSubTransferCategories, newTags, err := dataImporter.ParseImportedData(c, user, data, time.Local, converter.DefaultImporterOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.CliErrorf(c, "[user_data.ImportTransaction] failed to parse imported data for \"%s\", because %s", username, err.Error())
|
log.CliErrorf(c, "[user_data.ImportTransaction] failed to parse imported data for \"%s\", because %s", username, err.Error())
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package alipay
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/simplifiedchinese"
|
"golang.org/x/text/encoding/simplifiedchinese"
|
||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
@@ -53,7 +54,7 @@ type alipayTransactionDataCsvFileImporter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the alipay transaction csv data
|
// ParseImportedData returns the imported data by parsing the alipay transaction csv data
|
||||||
func (c *alipayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *alipayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
enc := simplifiedchinese.GB18030
|
enc := simplifiedchinese.GB18030
|
||||||
reader := transform.NewReader(bytes.NewReader(data), enc.NewDecoder())
|
reader := transform.NewReader(bytes.NewReader(data), enc.NewDecoder())
|
||||||
|
|
||||||
@@ -83,5 +84,5 @@ func (c *alipayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Contex
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, alipayTransactionSupportedColumns, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, alipayTransactionSupportedColumns, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(alipayTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(alipayTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func TestAlipayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 4, len(allNewTransactions))
|
assert.Equal(t, 4, len(allNewTransactions))
|
||||||
@@ -113,7 +113,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
||||||
@@ -133,7 +133,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRefundTransaction(t *testin
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
||||||
@@ -164,7 +164,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvestmentRefundTransaction
|
|||||||
"2024-09-01 01:00:00,Test Account2,xxx-买入,不计收支,0.01,Test Account,退款成功,\n" +
|
"2024-09-01 01:00:00,Test Account2,xxx-买入,不计收支,0.01,Test Account,退款成功,\n" +
|
||||||
"2024-09-01 02:00:00,Test Account2,xxx-买入退款,不计收支,0.01,Test Account,退款成功,\n")
|
"2024-09-01 02:00:00,Test Account2,xxx-买入退款,不计收支,0.01,Test Account,退款成功,\n")
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 2, len(allNewTransactions))
|
assert.Equal(t, 2, len(allNewTransactions))
|
||||||
@@ -202,7 +202,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
data2, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" +
|
data2, err := simplifiedchinese.GB18030.NewEncoder().String("支付宝交易记录明细查询\n" +
|
||||||
@@ -214,7 +214,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +259,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -275,7 +275,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -291,7 +291,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -308,7 +308,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -325,7 +325,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -342,7 +342,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -359,7 +359,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data7), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data7), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -389,7 +389,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseCategory(t *testing.T) {
|
|||||||
"2024-09-01 23:59:59,Test Category3,充值-普通充值,不计收支,0.05,交易成功,\n")
|
"2024-09-01 23:59:59,Test Category3,充值-普通充值,不计收支,0.05,交易成功,\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 3, len(allNewTransactions))
|
assert.Equal(t, 3, len(allNewTransactions))
|
||||||
@@ -435,7 +435,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseRelatedAccount(t *testing.T
|
|||||||
"2024-09-01 08:00:00,Test Account4,信用卡还款,不计收支,0.01,Test Account,还款成功,repayment,\n")
|
"2024-09-01 08:00:00,Test Account4,信用卡还款,不计收支,0.01,Test Account,还款成功,repayment,\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 9, len(allNewTransactions))
|
assert.Equal(t, 9, len(allNewTransactions))
|
||||||
@@ -547,7 +547,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -562,7 +562,7 @@ func TestAlipayCsvFileImporterParseImportedData_ParseDescription(t *testing.T) {
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -587,7 +587,7 @@ func TestAlipayCsvFileImporterParseImportedData_SkipClosedIncomeOrTransferTransa
|
|||||||
"2024-09-01 23:59:59 ,充值-普通充值 ,0.05 ,不计收支 ,交易关闭 ,\n" +
|
"2024-09-01 23:59:59 ,充值-普通充值 ,0.05 ,不计收支 ,交易关闭 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,7 +608,7 @@ func TestAlipayCsvFileImporterParseImportedData_SkipUnknownProductTransferTransa
|
|||||||
"2024-09-01 23:59:59 ,xxxx ,0.05 ,不计收支 ,交易成功 ,\n" +
|
"2024-09-01 23:59:59 ,xxxx ,0.05 ,不计收支 ,交易成功 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +629,7 @@ func TestAlipayCsvFileImporterParseImportedData_SkipUnknownStatusTransaction(t *
|
|||||||
"2024-09-01 01:23:45 ,xxxx ,0.12 ,收入 ,xxxx ,\n" +
|
"2024-09-01 01:23:45 ,xxxx ,0.12 ,收入 ,xxxx ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,10 +648,10 @@ func TestAlipayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.T)
|
|||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +672,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
|
|||||||
"金额(元),收/支 ,交易状态 ,\n" +
|
"金额(元),收/支 ,交易状态 ,\n" +
|
||||||
"0.12 ,收入 ,交易成功 ,\n" +
|
"0.12 ,收入 ,交易成功 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
@@ -683,7 +683,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
|
|||||||
"交易创建时间 ,收/支 ,交易状态 ,\n" +
|
"交易创建时间 ,收/支 ,交易状态 ,\n" +
|
||||||
"2024-09-01 12:34:56 ,收入 ,交易成功 ,\n" +
|
"2024-09-01 12:34:56 ,收入 ,交易成功 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Status Column
|
// Missing Status Column
|
||||||
@@ -694,7 +694,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
|
|||||||
"交易创建时间 ,金额(元),收/支 ,\n" +
|
"交易创建时间 ,金额(元),收/支 ,\n" +
|
||||||
"2024-09-01 12:34:56 ,0.12 ,收入 ,\n" +
|
"2024-09-01 12:34:56 ,0.12 ,收入 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Type Column
|
// Missing Type Column
|
||||||
@@ -705,7 +705,7 @@ func TestAlipayCsvFileImporterParseImportedData_MissingRequiredColumn(t *testing
|
|||||||
"交易创建时间 ,金额(元),交易状态 ,\n" +
|
"交易创建时间 ,金额(元),交易状态 ,\n" +
|
||||||
"2024-09-01 12:34:56 ,0.12 ,交易成功 ,\n" +
|
"2024-09-01 12:34:56 ,0.12 ,交易成功 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,6 +724,6 @@ func TestAlipayCsvFileImporterParseImportedData_NoTransactionData(t *testing.T)
|
|||||||
"---------------------------------交易记录明细列表------------------------------------\n" +
|
"---------------------------------交易记录明细列表------------------------------------\n" +
|
||||||
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
|
"交易创建时间 ,金额(元),收/支 ,交易状态 ,\n" +
|
||||||
"------------------------------------------------------------------------------------\n")
|
"------------------------------------------------------------------------------------\n")
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package beancount
|
package beancount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -24,7 +26,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the Beancount transaction data
|
// ParseImportedData returns the imported data by parsing the Beancount transaction data
|
||||||
func (c *beancountTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *beancountTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
beancountDataReader, err := createNewBeancountDataReader(ctx, data)
|
beancountDataReader, err := createNewBeancountDataReader(ctx, data)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,5 +47,5 @@ func (c *beancountTransactionDataImporter) ParseImportedData(ctx core.Context, u
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(beancountTransactionTypeNameMapping, "", "", BEANCOUNT_TRANSACTION_TAG_SEPARATOR)
|
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(beancountTransactionTypeNameMapping, "", "", BEANCOUNT_TRANSACTION_TAG_SEPARATOR)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package beancount
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData(t *testi
|
|||||||
" Expenses:TestCategory2 1.00 CNY\n"+
|
" Expenses:TestCategory2 1.00 CNY\n"+
|
||||||
"2024-09-04 *\n"+
|
"2024-09-04 *\n"+
|
||||||
" Assets:TestAccount -0.05 CNY\n"+
|
" Assets:TestAccount -0.05 CNY\n"+
|
||||||
" Assets:TestAccount2 0.05 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount2 0.05 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -112,7 +113,7 @@ func TestBeancountTransactionDataFileParseImportedData_MinimumValidData2(t *test
|
|||||||
" Assets:TestAccount -1.00 CNY\n"+
|
" Assets:TestAccount -1.00 CNY\n"+
|
||||||
"2024-09-04 *\n"+
|
"2024-09-04 *\n"+
|
||||||
" Assets:TestAccount2 0.05 CNY\n"+
|
" Assets:TestAccount2 0.05 CNY\n"+
|
||||||
" Assets:TestAccount -0.05 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount -0.05 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -182,7 +183,7 @@ func TestBeancountTransactionDataFileParseImportedData_ParseInvalidTime(t *testi
|
|||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024/09/01 *\n"+
|
"2024/09/01 *\n"+
|
||||||
" Equity:Opening-Balances -123.45 CNY\n"+
|
" Equity:Opening-Balances -123.45 CNY\n"+
|
||||||
" Assets:TestAccount 123.45 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount 123.45 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +199,7 @@ func TestBeancountTransactionDataFileParseImportedData_ParseValidCurrency(t *tes
|
|||||||
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-01 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Assets:TestAccount -0.12 USD\n"+
|
" Assets:TestAccount -0.12 USD\n"+
|
||||||
" Assets:TestAccount2 0.84 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount2 0.84 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -234,13 +235,13 @@ func TestBeancountTransactionDataFileParseImportedData_ParseInvalidAmount(t *tes
|
|||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 *\n"+
|
"2024-09-01 *\n"+
|
||||||
" Equity:Opening-Balances -abc CNY\n"+
|
" Equity:Opening-Balances -abc CNY\n"+
|
||||||
" Assets:TestAccount abc CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount abc CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 *\n"+
|
"2024-09-01 *\n"+
|
||||||
" Equity:Opening-Balances -1/0 CNY\n"+
|
" Equity:Opening-Balances -1/0 CNY\n"+
|
||||||
" Assets:TestAccount 1/0 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount 1/0 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +260,7 @@ func TestBeancountTransactionDataFileParseImportedData_ParseDescription(t *testi
|
|||||||
" Assets:TestAccount 123.45 CNY\n"+
|
" Assets:TestAccount 123.45 CNY\n"+
|
||||||
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Income:TestCategory -0.12 CNY\n"+
|
" Income:TestCategory -0.12 CNY\n"+
|
||||||
" Assets:TestAccount 0.12 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount 0.12 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -281,25 +282,25 @@ func TestBeancountTransactionDataFileParseImportedData_InvalidTransaction(t *tes
|
|||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Assets:TestAccount 0.11 CNY\n"+
|
" Assets:TestAccount 0.11 CNY\n"+
|
||||||
" Assets:TestAccount2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount2 0.11 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Expenses:TestCategory -0.11 CNY\n"+
|
" Expenses:TestCategory -0.11 CNY\n"+
|
||||||
" Expenses:TestCategory2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Expenses:TestCategory2 0.11 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
|
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Income:TestCategory -0.11 CNY\n"+
|
" Income:TestCategory -0.11 CNY\n"+
|
||||||
" Income:TestCategory2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Income:TestCategory2 0.11 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
|
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Equity:TestCategory -0.11 CNY\n"+
|
" Equity:TestCategory -0.11 CNY\n"+
|
||||||
" Equity:TestCategory2 0.11 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Equity:TestCategory2 0.11 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
|
assert.EqualError(t, err, errs.ErrThereAreNotSupportedTransactionType.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +317,7 @@ func TestBeancountTransactionDataFileParseImportedData_NotSupportedToParseSplitT
|
|||||||
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
"2024-09-02 * \"Payee Name\" \"Hello\nWorld\"\n"+
|
||||||
" Assets:TestAccount -0.23 CNY\n"+
|
" Assets:TestAccount -0.23 CNY\n"+
|
||||||
" Assets:TestAccount2 0.11 CNY\n"+
|
" Assets:TestAccount2 0.11 CNY\n"+
|
||||||
" Assets:TestAccount3 0.12 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount3 0.12 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,27 +334,27 @@ func TestBeancountTransactionDataFileParseImportedData_MissingTransactionRequire
|
|||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"* \"narration\"\n"+
|
"* \"narration\"\n"+
|
||||||
" Equity:Opening-Balances -123.45 CNY\n"+
|
" Equity:Opening-Balances -123.45 CNY\n"+
|
||||||
" Assets:TestAccount 123.45 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount 123.45 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
|
|
||||||
// Missing Account Name
|
// Missing Account Name
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 * \"narration\"\n"+
|
"2024-09-01 * \"narration\"\n"+
|
||||||
" Equity:Opening-Balances -123.45 CNY\n"+
|
" Equity:Opening-Balances -123.45 CNY\n"+
|
||||||
" 123.45 CNY\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" 123.45 CNY\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
||||||
|
|
||||||
// Missing Amount
|
// Missing Amount
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 * \"narration\"\n"+
|
"2024-09-01 * \"narration\"\n"+
|
||||||
" Equity:Opening-Balances\n"+
|
" Equity:Opening-Balances\n"+
|
||||||
" Assets:TestAccount\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
||||||
|
|
||||||
// Missing Commodity
|
// Missing Commodity
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 * \"narration\"\n"+
|
"2024-09-01 * \"narration\"\n"+
|
||||||
" Equity:Opening-Balances -123.45\n"+
|
" Equity:Opening-Balances -123.45\n"+
|
||||||
" Assets:TestAccount 123.45\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
" Assets:TestAccount 123.45\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidBeancountFile.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ func (t *camtStatementTransactionDataRowIterator) parseTransaction(ctx core.Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
||||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Location())
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Unix(), dateTime.Location())
|
||||||
} else if entry.BookingDate != nil && entry.BookingDate.Date != "" {
|
} else if entry.BookingDate != nil && entry.BookingDate.Date != "" {
|
||||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = fmt.Sprintf("%s 00:00:00", entry.BookingDate.Date)
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = fmt.Sprintf("%s 00:00:00", entry.BookingDate.Date)
|
||||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = datatable.TRANSACTION_DATA_TABLE_TIMEZONE_NOT_AVAILABLE
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = datatable.TRANSACTION_DATA_TABLE_TIMEZONE_NOT_AVAILABLE
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package camt
|
package camt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -23,7 +25,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the camt.053 file transaction data
|
// ParseImportedData returns the imported data by parsing the camt.053 file transaction data
|
||||||
func (c *camt053TransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *camt053TransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
camt053DataReader, err := createNewCamt053FileReader(data)
|
camt053DataReader, err := createNewCamt053FileReader(data)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,5 +46,5 @@ func (c *camt053TransactionDataImporter) ParseImportedData(ctx core.Context, use
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(camtTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(camtTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package camt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ func TestCamt053TransactionDataFileParseImportedData_MinimumValidData(t *testing
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseValidTransactionTime(t
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 3, len(allNewTransactions))
|
assert.Equal(t, 3, len(allNewTransactions))
|
||||||
@@ -197,7 +198,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -220,7 +221,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -243,7 +244,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -266,7 +267,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseInvalidTransactionTime
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +316,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(allNewTransactions))
|
assert.Equal(t, 2, len(allNewTransactions))
|
||||||
@@ -366,7 +367,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(allNewTransactions))
|
assert.Equal(t, 2, len(allNewTransactions))
|
||||||
@@ -404,7 +405,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -431,7 +432,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionValidAmount
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -468,7 +469,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -499,7 +500,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -530,7 +531,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseTransactionInvalidAmou
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,7 +574,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -608,7 +609,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -635,7 +636,7 @@ func TestCamt053TransactionDataFileParseImportedData_ParseDescription(t *testing
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -665,7 +666,7 @@ func TestCamt053TransactionDataFileParseImportedData_MissingAccountNode(t *testi
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
|
assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,7 +696,7 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -717,7 +718,7 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -739,7 +740,7 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -761,6 +762,6 @@ func TestCamt053TransactionDataFileParseImportedData_MissingTransactionRequiredN
|
|||||||
</Ntry>
|
</Ntry>
|
||||||
</Stmt>
|
</Stmt>
|
||||||
</BkToCstmrStmt>
|
</BkToCstmrStmt>
|
||||||
</Document>`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
</Document>`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ func (c *DataTableTransactionDataExporter) BuildExportedContent(ctx core.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
dataRowMap := make(map[datatable.TransactionDataTableColumn]string, 15)
|
dataRowMap := make(map[datatable.TransactionDataTableColumn]string, 15)
|
||||||
|
transactionUnixTime := utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime)
|
||||||
transactionTimeZone := time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60)
|
transactionTimeZone := time.FixedZone("Transaction Timezone", int(transaction.TimezoneUtcOffset)*60)
|
||||||
|
|
||||||
dataRowMap[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(utils.GetUnixTimeFromTransactionTime(transaction.TransactionTime), transactionTimeZone)
|
dataRowMap[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(transactionUnixTime, transactionTimeZone)
|
||||||
dataRowMap[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(transactionTimeZone)
|
dataRowMap[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(transactionUnixTime, transactionTimeZone)
|
||||||
dataRowMap[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = dataTableBuilder.ReplaceDelimiters(c.getDisplayTransactionTypeName(transaction.Type))
|
dataRowMap[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = dataTableBuilder.ReplaceDelimiters(c.getDisplayTransactionTypeName(transaction.Type))
|
||||||
dataRowMap[datatable.TRANSACTION_DATA_TABLE_CATEGORY] = c.getExportedTransactionCategoryName(dataTableBuilder, transaction.CategoryId, categoryMap)
|
dataRowMap[datatable.TRANSACTION_DATA_TABLE_CATEGORY] = c.getExportedTransactionCategoryName(dataTableBuilder, transaction.CategoryId, categoryMap)
|
||||||
dataRowMap[datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY] = c.getExportedTransactionSubCategoryName(dataTableBuilder, transaction.CategoryId, categoryMap)
|
dataRowMap[datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY] = c.getExportedTransactionSubCategoryName(dataTableBuilder, transaction.CategoryId, categoryMap)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package converter
|
|||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
@@ -29,7 +30,7 @@ type DataTableTransactionDataImporter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseImportedData returns the imported transaction data
|
// ParseImportedData returns the imported transaction data
|
||||||
func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, dataTable datatable.TransactionDataTable, defaultTimezoneOffset int16, additionalOptions TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, dataTable datatable.TransactionDataTable, defaultTimezone *time.Location, additionalOptions TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
if dataTable.TransactionRowCount() < 1 {
|
if dataTable.TransactionRowCount() < 1 {
|
||||||
log.Errorf(ctx, "[data_table_transaction_data_importer.ParseImportedData] cannot parse import data for user \"uid:%d\", because data table row count is less 1", user.Uid)
|
log.Errorf(ctx, "[data_table_transaction_data_importer.ParseImportedData] cannot parse import data for user \"uid:%d\", because data table row count is less 1", user.Uid)
|
||||||
return nil, nil, nil, nil, nil, nil, errs.ErrNotFoundTransactionDataInFile
|
return nil, nil, nil, nil, nil, nil, errs.ErrNotFoundTransactionDataInFile
|
||||||
@@ -94,7 +95,7 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
timezoneOffset := defaultTimezoneOffset
|
timezone := defaultTimezone
|
||||||
|
|
||||||
if dataTable.HasColumn(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE) &&
|
if dataTable.HasColumn(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE) &&
|
||||||
dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE) != datatable.TRANSACTION_DATA_TABLE_TIMEZONE_NOT_AVAILABLE {
|
dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE) != datatable.TRANSACTION_DATA_TABLE_TIMEZONE_NOT_AVAILABLE {
|
||||||
@@ -105,10 +106,10 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
|
|||||||
return nil, nil, nil, nil, nil, nil, errs.ErrTransactionTimeZoneInvalid
|
return nil, nil, nil, nil, nil, nil, errs.ErrTransactionTimeZoneInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
timezoneOffset = utils.GetTimezoneOffsetMinutes(transactionTimezone)
|
timezone = transactionTimezone
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionTime, err := utils.ParseFromLongDateTime(dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME), timezoneOffset)
|
transactionTime, err := utils.ParseFromLongDateTimeInTimeZone(dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME), timezone)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx, "[data_table_transaction_data_importer.ParseImportedData] cannot parse time \"%s\" in data row \"index:%d\" for user \"uid:%d\", because %s", dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME), dataRowIndex, user.Uid, err.Error())
|
log.Errorf(ctx, "[data_table_transaction_data_importer.ParseImportedData] cannot parse time \"%s\" in data row \"index:%d\" for user \"uid:%d\", because %s", dataRow.GetData(datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME), dataRowIndex, user.Uid, err.Error())
|
||||||
@@ -373,7 +374,7 @@ func (c *DataTableTransactionDataImporter) ParseImportedData(ctx core.Context, u
|
|||||||
Type: transactionDbType,
|
Type: transactionDbType,
|
||||||
CategoryId: categoryId,
|
CategoryId: categoryId,
|
||||||
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionTime.Unix()),
|
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionTime.Unix()),
|
||||||
TimezoneUtcOffset: timezoneOffset,
|
TimezoneUtcOffset: utils.GetTimezoneOffsetMinutes(transactionTime.Unix(), timezone),
|
||||||
AccountId: account.AccountId,
|
AccountId: account.AccountId,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
HideAmount: false,
|
HideAmount: false,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package converter
|
package converter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
)
|
)
|
||||||
@@ -14,7 +16,7 @@ type TransactionDataExporter interface {
|
|||||||
// TransactionDataImporter defines the structure of transaction data importer
|
// TransactionDataImporter defines the structure of transaction data importer
|
||||||
type TransactionDataImporter interface {
|
type TransactionDataImporter interface {
|
||||||
// ParseImportedData returns the imported data
|
// ParseImportedData returns the imported data
|
||||||
ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error)
|
ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionDataConverter defines the structure of transaction data converter
|
// TransactionDataConverter defines the structure of transaction data converter
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the transaction json data
|
// ParseImportedData returns the imported data by parsing the transaction json data
|
||||||
func (c *defaultTransactionDataJsonImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *defaultTransactionDataJsonImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
var importRequest models.ImportTransactionRequest
|
var importRequest models.ImportTransactionRequest
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &importRequest); err != nil {
|
if err := json.Unmarshal(data, &importRequest); err != nil {
|
||||||
@@ -55,7 +55,7 @@ func (c *defaultTransactionDataJsonImporter) ParseImportedData(ctx core.Context,
|
|||||||
ezbookkeepingTagSeparator,
|
ezbookkeepingTagSeparator,
|
||||||
)
|
)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *defaultTransactionDataJsonImporter) createNewDefaultTransactionDataTable(importRequest models.ImportTransactionRequest) (datatable.TransactionDataTable, error) {
|
func (c *defaultTransactionDataJsonImporter) createNewDefaultTransactionDataTable(importRequest models.ImportTransactionRequest) (datatable.TransactionDataTable, error) {
|
||||||
@@ -75,10 +75,11 @@ func (c *defaultTransactionDataJsonImporter) createNewDefaultTransactionDataTabl
|
|||||||
}
|
}
|
||||||
|
|
||||||
timezone := time.FixedZone("Transaction Timezone", utcOffset*60)
|
timezone := time.FixedZone("Transaction Timezone", utcOffset*60)
|
||||||
|
timezoneOffset := utils.FormatTimezoneOffset(time.Now().Unix(), timezone)
|
||||||
|
|
||||||
row := make(map[datatable.TransactionDataTableColumn]string, len(allJsonDataSupportedColumns))
|
row := make(map[datatable.TransactionDataTableColumn]string, len(allJsonDataSupportedColumns))
|
||||||
row[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = transaction.Time
|
row[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = transaction.Time
|
||||||
row[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(timezone)
|
row[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = timezoneOffset
|
||||||
row[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = transaction.Type
|
row[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = transaction.Type
|
||||||
row[datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY] = transaction.CategoryName
|
row[datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY] = transaction.CategoryName
|
||||||
row[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = transaction.SourceAccountName
|
row[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = transaction.SourceAccountName
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package _default
|
package _default
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
@@ -84,7 +86,7 @@ func (c *defaultTransactionDataPlainTextConverter) ToExportedContent(ctx core.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the transaction plain text data
|
// ParseImportedData returns the imported data by parsing the transaction plain text data
|
||||||
func (c *defaultTransactionDataPlainTextConverter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *defaultTransactionDataPlainTextConverter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
dataTable, err := createNewDefaultPlainTextDataTable(
|
dataTable, err := createNewDefaultPlainTextDataTable(
|
||||||
string(data),
|
string(data),
|
||||||
c.columnSeparator,
|
c.columnSeparator,
|
||||||
@@ -104,5 +106,5 @@ func (c *defaultTransactionDataPlainTextConverter) ParseImportedData(ctx core.Co
|
|||||||
ezbookkeepingTagSeparator,
|
ezbookkeepingTagSeparator,
|
||||||
)
|
)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package _default
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -139,7 +140,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MinimumValidDat
|
|||||||
"2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,\n"+
|
"2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,\n"+
|
||||||
"2024-09-01 01:23:45,Income,Test Category,Test Account,0.12,,\n"+
|
"2024-09-01 01:23:45,Income,Test Category,Test Account,0.12,,\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category2,Test Account,1.00,,\n"+
|
"2024-09-01 12:34:56,Expense,Test Category2,Test Account,1.00,,\n"+
|
||||||
"2024-09-01 23:59:59,Transfer,Test Category3,Test Account,0.05,Test Account2,0.05"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 23:59:59,Transfer,Test Category3,Test Account,0.05,Test Account2,0.05"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -207,11 +208,11 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTim
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01T12:34:56,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01T12:34:56,Expense,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"09/01/2024 12:34:56,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"09/01/2024 12:34:56,Expense,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +226,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,Type,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Type,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,19 +240,19 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidTimez
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,-10:00,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,-10:00,Expense,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,+00:00,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,+00:00,Expense,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,+12:45,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,+12:45,Expense,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -267,7 +268,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidTim
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,Asia/Shanghai,Expense,Test Category,Test Account,123.45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Asia/Shanghai,Expense,Test Category,Test Account,123.45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +283,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidAccou
|
|||||||
|
|
||||||
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
||||||
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
|
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
|
||||||
"2024-09-01 12:34:56,Transfer,Test Category2,Test Account,USD,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Transfer,Test Category2,Test Account,USD,1.23,Test Account2,EUR,1.10"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -309,12 +310,12 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAcc
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
||||||
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
|
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
|
||||||
"2024-09-01 12:34:56,Transfer,Test Category3,Test Account,CNY,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Transfer,Test Category3,Test Account,CNY,1.23,Test Account2,EUR,1.10"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
||||||
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
|
"2024-09-01 01:23:45,Balance Modification,,Test Account,USD,123.45,,,\n"+
|
||||||
"2024-09-01 12:34:56,Transfer,Test Category3,Test Account2,CNY,1.23,Test Account,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Transfer,Test Category3,Test Account2,CNY,1.23,Test Account,EUR,1.10"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,11 +329,11 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNotSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
||||||
"2024-09-01 01:23:45,Balance Modification,,Test Account,XXX,123.45,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 01:23:45,Balance Modification,,Test Account,XXX,123.45,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount\n"+
|
||||||
"2024-09-01 01:23:45,Transfer,Test Category,Test Account,USD,123.45,Test Account2,XXX,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 01:23:45,Transfer,Test Category,Test Account,USD,123.45,Test Account2,XXX,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,11 +347,11 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidAmo
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123 45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123 45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount\n"+
|
||||||
"2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2,123 45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2,123 45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,14 +365,14 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseNoAmount2(
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
||||||
assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount)
|
assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2\n"+
|
||||||
"2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Transfer,Test Category,Test Account,123.45,Test Account2"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
||||||
@@ -388,7 +389,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseValidGeogr
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,123.45 45.56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,123.45 45.56"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -406,18 +407,18 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseInvalidGeo
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude)
|
assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude)
|
||||||
assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude)
|
assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,a b"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,a b"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
|
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Geographic Location\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1 "), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,1 "), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
|
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +432,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseTag(t *tes
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Tags\n"+
|
_, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Tags\n"+
|
||||||
"2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,,foo;;bar.;#test;hello\tworld;;"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,Balance Modification,,Test Account,123.45,,,foo;;bar.;#test;hello\tworld;;"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -460,7 +461,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_ParseDescriptio
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Description\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Time,Type,Sub Category,Account,Amount,Account2,Account2 Amount,Description\n"+
|
||||||
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,foo bar\t#test"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Expense,Test Category,Test Account,123.45,,,foo bar\t#test"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -476,7 +477,7 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingFileHead
|
|||||||
DefaultCurrency: "CNY",
|
DefaultCurrency: "CNY",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,31 +492,31 @@ func TestDefaultTransactionDataCSVFileConverterParseImportedData_MissingRequired
|
|||||||
|
|
||||||
// Missing Time Column
|
// Missing Time Column
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
||||||
"+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Type Column
|
// Missing Type Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Category,Sub Category,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
||||||
"2024-09-01 00:00:00,+08:00,Test Category,Test Sub Category,Test Account,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,+08:00,Test Category,Test Sub Category,Test Account,CNY,123.45,,,,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Sub Category Column
|
// Missing Sub Category Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Type,Account,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
||||||
"2024-09-01 00:00:00,+08:00,Balance Modification,Test Account,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,+08:00,Balance Modification,Test Account,CNY,123.45,,,,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Account Name Column
|
// Missing Account Name Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account Currency,Amount,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
||||||
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,CNY,123.45,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,CNY,123.45,,,,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Account2,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
||||||
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,,,,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Account2 Name Column
|
// Missing Account2 Name Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("Time,Timezone,Type,Category,Sub Category,Account,Account Currency,Amount,Account2 Currency,Account2 Amount,Geographic Location,Tags,Description\n"+
|
||||||
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,+08:00,Balance Modification,,Test Sub Category,Test Account,CNY,123.45,,,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/text/encoding"
|
"golang.org/x/text/encoding"
|
||||||
"golang.org/x/text/encoding/charmap"
|
"golang.org/x/text/encoding/charmap"
|
||||||
@@ -148,7 +149,7 @@ func (c *customTransactionDataDsvFileImporter) ParseDsvFileLines(ctx core.Contex
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the custom transaction dsv data
|
// ParseImportedData returns the imported data by parsing the custom transaction dsv data
|
||||||
func (c *customTransactionDataDsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *customTransactionDataDsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
allLines, err := c.ParseDsvFileLines(ctx, data)
|
allLines, err := c.ParseDsvFileLines(ctx, data)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -159,7 +160,7 @@ func (c *customTransactionDataDsvFileImporter) ParseImportedData(ctx core.Contex
|
|||||||
transactionDataTable := CreateNewCustomPlainTextDataTable(dataTable, c.columnIndexMapping, c.transactionTypeNameMapping, c.timeFormat, c.timezoneFormat, c.amountDecimalSeparator, c.amountDigitGroupingSymbol)
|
transactionDataTable := CreateNewCustomPlainTextDataTable(dataTable, c.columnIndexMapping, c.transactionTypeNameMapping, c.timeFormat, c.timezoneFormat, c.amountDecimalSeparator, c.amountDigitGroupingSymbol)
|
||||||
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(customTransactionTypeNameMapping, c.geoLocationSeparator, c.geoLocationOrder, c.transactionTagSeparator)
|
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(customTransactionTypeNameMapping, c.geoLocationSeparator, c.geoLocationOrder, c.transactionTagSeparator)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsDelimiterSeparatedValuesFileType returns whether the file type is the delimiter-separated values file type
|
// IsDelimiterSeparatedValuesFileType returns whether the file type is the delimiter-separated values file type
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dsv
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ func TestCustomTransactionDataDsvFileImporter_MinimumValidData(t *testing.T) {
|
|||||||
"2024-09-01 00:00:00,B,123.45\n"+
|
"2024-09-01 00:00:00,B,123.45\n"+
|
||||||
"2024-09-01 01:23:45,I,0.12\n"+
|
"2024-09-01 01:23:45,I,0.12\n"+
|
||||||
"2024-09-01 12:34:56,E,1.00\n"+
|
"2024-09-01 12:34:56,E,1.00\n"+
|
||||||
"2024-09-01 23:59:59,T,0.05"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 23:59:59,T,0.05"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -184,7 +185,7 @@ func TestCustomTransactionDataDsvFileImporter_WithAllSupportedColumns(t *testing
|
|||||||
"\"2024-09-01 00:00:00\",\"+08:00\",\"Balance Modification\",\"\",\"\",\"Test Account\",\"CNY\",\"123.45\",\"\",\"\",\"\",\"\",\"\",\"\"\n"+
|
"\"2024-09-01 00:00:00\",\"+08:00\",\"Balance Modification\",\"\",\"\",\"Test Account\",\"CNY\",\"123.45\",\"\",\"\",\"\",\"\",\"\",\"\"\n"+
|
||||||
"\"2024-09-01 01:23:45\",\"+08:00\",\"Income\",\"Test Category\",\"Test Sub Category\",\"Test Account\",\"CNY\",\"0.12\",\"\",\"\",\"\",\"123.450000 45.670000\",\"Test Tag;Test Tag2\",\"Hello World\"\n"+
|
"\"2024-09-01 01:23:45\",\"+08:00\",\"Income\",\"Test Category\",\"Test Sub Category\",\"Test Account\",\"CNY\",\"0.12\",\"\",\"\",\"\",\"123.450000 45.670000\",\"Test Tag;Test Tag2\",\"Hello World\"\n"+
|
||||||
"\"2024-09-01 12:34:56\",\"+00:00\",\"Expense\",\"Test Category2\",\"Test Sub Category2\",\"Test Account\",\"CNY\",\"1.00\",\"\",\"\",\"\",\"\",\"Test Tag\",\"Foo#Bar\"\n"+
|
"\"2024-09-01 12:34:56\",\"+00:00\",\"Expense\",\"Test Category2\",\"Test Sub Category2\",\"Test Account\",\"CNY\",\"1.00\",\"\",\"\",\"\",\"\",\"Test Tag\",\"Foo#Bar\"\n"+
|
||||||
"\"2024-09-01 23:59:59\",\"-05:00\",\"Transfer\",\"Test Category3\",\"Test Sub Category3\",\"Test Account\",\"CNY\",\"0.05\",\"Test Account2\",\"USD\",\"0.35\",\"\",\"Test Tag2\",\"foo\tbar\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"2024-09-01 23:59:59\",\"-05:00\",\"Transfer\",\"Test Category3\",\"Test Sub Category3\",\"Test Account\",\"CNY\",\"0.05\",\"Test Account2\",\"USD\",\"0.35\",\"\",\"Test Tag2\",\"foo\tbar\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -273,11 +274,11 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTime(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01T12:34:56,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01T12:34:56,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"09/01/2024 12:34:56,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"09/01/2024 12:34:56,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +305,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTransactionWithoutType(t *tes
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,A,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,A,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,7 +329,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,B,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,B,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,19 +353,19 @@ func TestCustomTransactionDataDsvFileImporter_ParseTimeWithTimezone(t *testing.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56-10:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56-10:00,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56+00:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56+00:00,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56+12:45,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56+12:45,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -390,19 +391,19 @@ func TestCustomTransactionDataDsvFileImporter_ParseTimeWithTimezone2(t *testing.
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56-1000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56-1000,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56+0000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56+0000,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56+1245,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56+1245,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -429,19 +430,19 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidTimezone(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,-10:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,-10:00,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,+00:00,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,+00:00,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,+12:45,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,+12:45,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -468,19 +469,19 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidTimezone2(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,-1000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,-1000,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,+0000,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,+0000,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,+1245,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,+1245,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -507,7 +508,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezoneFormat(t *test
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,CST,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,CST,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrImportFileTransactionTimezoneFormatInvalid.Message)
|
assert.EqualError(t, err, errs.ErrImportFileTransactionTimezoneFormatInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,11 +533,11 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezone(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,-0700,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,-0700,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,11 +562,11 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidTimezone2(t *testing.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,Asia/Shanghai,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,0700,E,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,0700,E,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeZoneInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,7 +590,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithCustomFormat(t *tes
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56\tE\t1.234,56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56\tE\t1.234,56"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(123456), allNewTransactions[0].Amount)
|
assert.Equal(t, int64(123456), allNewTransactions[0].Amount)
|
||||||
@@ -615,7 +616,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmountWithCustomFormat
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56\tE\t1.234,56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56\tE\t1.234,56"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,7 +640,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmountWithCustomFormat
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56\tE\t1.234,56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56\tE\t1.234,56"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,7 +671,7 @@ func TestCustomTransactionDataDsvFileImporter_ParsePrimaryCategory(t *testing.T)
|
|||||||
"2024-09-01 00:00:00,B,,123.45\n"+
|
"2024-09-01 00:00:00,B,,123.45\n"+
|
||||||
"2024-09-01 01:23:45,I,Test Category,0.12\n"+
|
"2024-09-01 01:23:45,I,Test Category,0.12\n"+
|
||||||
"2024-09-01 12:34:56,E,Test Category2,1.00\n"+
|
"2024-09-01 12:34:56,E,Test Category2,1.00\n"+
|
||||||
"2024-09-01 23:59:59,T,Test Category3,0.05"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 23:59:59,T,Test Category3,0.05"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -737,7 +738,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidAccountCurrency(t *testi
|
|||||||
|
|
||||||
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
|
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
|
||||||
"2024-09-01 12:34:56,T,Test Account,USD,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,T,Test Account,USD,1.23,Test Account2,EUR,1.10"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -780,12 +781,12 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAccountCurrency(t *tes
|
|||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
|
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
|
||||||
"2024-09-01 12:34:56,T,Test Account,CNY,1.23,Test Account2,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,T,Test Account,CNY,1.23,Test Account2,EUR,1.10"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
|
"2024-09-01 01:23:45,B,Test Account,USD,123.45,,,\n"+
|
||||||
"2024-09-01 12:34:56,T,Test Account2,CNY,1.23,Test Account,EUR,1.10"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,T,Test Account2,CNY,1.23,Test Account,EUR,1.10"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -815,11 +816,11 @@ func TestCustomTransactionDataDsvFileImporter_ParseNotSupportedCurrency(t *testi
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 01:23:45,B,Test Account,XXX,123.45,,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 01:23:45,B,Test Account,XXX,123.45,,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 01:23:45,T,Test Account,USD,123.45,Test Account2,XXX,123.45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 01:23:45,T,Test Account,USD,123.45,Test Account2,XXX,123.45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,7 +851,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidAmount(t *testing.T) {
|
|||||||
"2024-09-01 00:00:00,B,123.45000000,\n"+
|
"2024-09-01 00:00:00,B,123.45000000,\n"+
|
||||||
"2024-09-01 01:23:45,I,0.12000000,\n"+
|
"2024-09-01 01:23:45,I,0.12000000,\n"+
|
||||||
"2024-09-01 12:34:56,E,1.00000000,\n"+
|
"2024-09-01 12:34:56,E,1.00000000,\n"+
|
||||||
"2024-09-01 23:59:59,T,0.05000000,0.35000000"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 23:59:59,T,0.05000000,0.35000000"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -895,7 +896,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithSpaceDigitGroupingS
|
|||||||
|
|
||||||
// normal space
|
// normal space
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 00:00:00,E,1 234,\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,E,1 234,\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -904,7 +905,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithSpaceDigitGroupingS
|
|||||||
|
|
||||||
// no-break space (NBSP)
|
// no-break space (NBSP)
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 00:00:00,E,1 234,\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,E,1 234,\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -913,7 +914,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithSpaceDigitGroupingS
|
|||||||
|
|
||||||
// narrow no-break space (NNBSP)
|
// narrow no-break space (NNBSP)
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 00:00:00,E,1 234,\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,E,1 234,\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -922,7 +923,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseAmountWithSpaceDigitGroupingS
|
|||||||
|
|
||||||
// figure space
|
// figure space
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 00:00:00,E,1 234,\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,E,1 234,\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -954,11 +955,11 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidAmount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,E,Test Account,123 45,,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,E,Test Account,123 45,,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,T,Test Account,123.45,Test Account2,123 45"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,T,Test Account,123.45,Test Account2,123 45"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -985,14 +986,14 @@ func TestCustomTransactionDataDsvFileImporter_ParseNoAmount2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,E,Test Account,123.45,"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,E,Test Account,123.45,"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
||||||
assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount)
|
assert.Equal(t, int64(0), allNewTransactions[0].RelatedAccountAmount)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,T,Test Account,123.45,Test Account2"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,T,Test Account,123.45,Test Account2"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
assert.Equal(t, int64(12345), allNewTransactions[0].Amount)
|
||||||
@@ -1020,7 +1021,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseValidGeographicLocation(t *te
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,E,123.45,123.45;45.56"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,E,123.45,123.45;45.56"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -1049,14 +1050,14 @@ func TestCustomTransactionDataDsvFileImporter_ParseInvalidGeographicLocation(t *
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,E,123.45,,,1"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,E,123.45,,,1"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude)
|
assert.Equal(t, float64(0), allNewTransactions[0].GeoLongitude)
|
||||||
assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude)
|
assert.Equal(t, float64(0), allNewTransactions[0].GeoLatitude)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,E,123.45,a b"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,E,123.45,a b"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
|
assert.EqualError(t, err, errs.ErrGeographicLocationInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1081,7 +1082,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -1121,7 +1122,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseTagWithoutSeparator(t *testin
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 00:00:00,E,123.45,foo;;bar.;#test;hello\tworld;;"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -1152,7 +1153,7 @@ func TestCustomTransactionDataDsvFileImporter_ParseDescription(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"2024-09-01 12:34:56,T,123.45,foo bar\t#test"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"2024-09-01 12:34:56,T,123.45,foo bar\t#test"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ func (t *customPlainTextDataRowIterator) parseTransaction(ctx core.Context, user
|
|||||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
||||||
|
|
||||||
if t.transactionDataTable.timeFormatIncludeTimezone {
|
if t.transactionDataTable.timeFormatIncludeTimezone {
|
||||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Location())
|
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Unix(), dateTime.Location())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package feidee
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/unicode"
|
"golang.org/x/text/encoding/unicode"
|
||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
@@ -61,7 +62,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the feidee mymoney app transaction csv data
|
// ParseImportedData returns the imported data by parsing the feidee mymoney app transaction csv data
|
||||||
func (c *feideeMymoneyAppTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *feideeMymoneyAppTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
fallback := unicode.UTF8.NewDecoder()
|
fallback := unicode.UTF8.NewDecoder()
|
||||||
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
|
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ func (c *feideeMymoneyAppTransactionDataCsvFileImporter) ParseImportedData(ctx c
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *feideeMymoneyAppTransactionDataCsvFileImporter) createNewFeideeMymoneyAppTransactionDataTable(ctx core.Context, commonDataTable datatable.CommonDataTable) (datatable.TransactionDataTable, error) {
|
func (c *feideeMymoneyAppTransactionDataCsvFileImporter) createNewFeideeMymoneyAppTransactionDataTable(ctx core.Context, commonDataTable datatable.CommonDataTable) (datatable.TransactionDataTable, error) {
|
||||||
|
|||||||
+29
-29
@@ -31,7 +31,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MinimumValidData(t *testi
|
|||||||
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\"\n"+
|
"\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\"\n"+
|
||||||
"\"转出\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转出\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account2\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseOutstandingBalanceMo
|
|||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"负债变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"+
|
"\"负债变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"+
|
||||||
"\"负债变更\",\"2024-09-01 01:00:00\",\"\",\"Test Account2\",\"-0.12\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"负债变更\",\"2024-09-01 01:00:00\",\"\",\"Test Account2\",\"-0.12\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -171,12 +171,12 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidTime(t *testi
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"收入\",\"2024-09-01T12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"收入\",\"2024-09-01T12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"收入\",\"09/01/2024 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"收入\",\"09/01/2024 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidType(t *testi
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"Type\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Type\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"0.12\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseValidAccountCurrency
|
|||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
|
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"USD\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"USD\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -237,14 +237,14 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAccountCurren
|
|||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
|
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
|
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"USD\",\"123.45\",\"\",\"\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account2\",\"CNY\",\"1.23\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category3\",\"Test Account\",\"EUR\",\"1.10\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,19 +259,19 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseNotSupportedCurrency
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"账户币种\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"XXX\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"USD\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,24 +286,24 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseInvalidAmount(t *tes
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"负债变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"负债变更\",\"2024-09-01 01:23:45\",\"\",\"Test Account\",\"123 45\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account2\",\"123 45\",\"\",\"00000000-0000-0000-0000-000000000001\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +319,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_ParseDescription(t *testi
|
|||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"Test\n"+
|
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"Test\n"+
|
||||||
"A new line break\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"A new line break\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -337,7 +337,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_WithAdditionalOptions(t *
|
|||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\",\"成员\",\"项目\",\"商家\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\",\"成员\",\"项目\",\"商家\"\n"+
|
||||||
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\",\"test1\",\"test2\",\"test3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\",\"test1\",\"test2\",\"test3\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -345,7 +345,7 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_WithAdditionalOptions(t *
|
|||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\",\"成员\",\"项目\",\"商家\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\",\"成员\",\"项目\",\"商家\"\n"+
|
||||||
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\",\"test1\",\"test2\",\"test3\""), 0, converter.DefaultImporterOptions.WithMemberAsTag().WithProjectAsTag().WithMerchantAsTag(), nil, nil, nil, nil, nil)
|
"\"支出\",\"2024-09-01 12:34:56\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\",\"test1\",\"test2\",\"test3\""), time.UTC, converter.DefaultImporterOptions.WithMemberAsTag().WithProjectAsTag().WithMerchantAsTag(), nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -366,18 +366,18 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_InvalidRelatedId(t *testi
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message)
|
assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message)
|
assert.EqualError(t, err, errs.ErrRelatedIdCannotBeBlank.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
"\"转出\",\"2024-09-01 23:59:59\",\"Test Category3\",\"Test Account\",\"0.05\",\"\",\"00000000-0000-0000-0000-000000000001\"\n"+
|
||||||
"\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"转入\",\"2024-09-02 23:59:59\",\"Test Category3\",\"Test Account\",\"0.5\",\"\",\"00000000-0000-0000-0000-000000000002\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrFoundRecordNotHasRelatedRecord.Message)
|
assert.EqualError(t, err, errs.ErrFoundRecordNotHasRelatedRecord.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,10 +390,10 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingFileHeader(t *test
|
|||||||
DefaultCurrency: "CNY",
|
DefaultCurrency: "CNY",
|
||||||
}
|
}
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,36 +409,36 @@ func TestFeideeMymoneyCsvFileImporterParseImportedData_MissingRequiredColumn(t *
|
|||||||
// Missing Time Column
|
// Missing Time Column
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"\",\"Test Account\",\"123.45\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Type Column
|
// Missing Type Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"2024-09-01 00:00:00\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"2024-09-01 00:00:00\",\"Test Category\",\"Test Account\",\"123.45\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Sub Category Column
|
// Missing Sub Category Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"账户\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 00:00:00\",\"Test Account\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 00:00:00\",\"Test Account\",\"123.45\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Account Name Column
|
// Missing Account Name Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"金额\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"金额\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"123.45\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"123.45\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"备注\",\"关联Id\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"备注\",\"关联Id\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Related ID Column
|
// Missing Related ID Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("随手记导出文件(headers:v5;xxxxx)\n"+
|
||||||
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\"\n"+
|
"\"交易类型\",\"日期\",\"子类别\",\"账户\",\"金额\",\"备注\"\n"+
|
||||||
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"余额变更\",\"2024-09-01 00:00:00\",\"\",\"Test Account\",\"123.45\",\"\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,8 @@
|
|||||||
package feidee
|
package feidee
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/excel"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/excel"
|
||||||
@@ -34,7 +36,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the feidee mymoney (elecloud) transaction xlsx data
|
// ParseImportedData returns the imported data by parsing the feidee mymoney (elecloud) transaction xlsx data
|
||||||
func (c *feideeMymoneyElecloudTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *feideeMymoneyElecloudTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
dataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, true)
|
dataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,5 +47,5 @@ func (c *feideeMymoneyElecloudTransactionDataXlsxFileImporter) ParseImportedData
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyElecloudDataColumnNameMapping, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyElecloudDataColumnNameMapping, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewSimpleImporter(feideeMymoneyElecloudTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporter(feideeMymoneyElecloudTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ func TestFeideeMymoneyElecloudTransactionDataXlsxImporterParseImportedData_Minim
|
|||||||
testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_elecloud_test_file.xlsx")
|
testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_elecloud_test_file.xlsx")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, testdata, 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, testdata, time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 7, len(allNewTransactions))
|
assert.Equal(t, 7, len(allNewTransactions))
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package feidee
|
package feidee
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/excel"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/excel"
|
||||||
@@ -33,7 +35,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the feidee mymoney (web) transaction xls data
|
// ParseImportedData returns the imported data by parsing the feidee mymoney (web) transaction xls data
|
||||||
func (c *feideeMymoneyWebTransactionDataXlsFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *feideeMymoneyWebTransactionDataXlsFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
dataTable, err := excel.CreateNewExcelMSCFBFileBasicDataTable(data, true)
|
dataTable, err := excel.CreateNewExcelMSCFBFileBasicDataTable(data, true)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,5 +46,5 @@ func (c *feideeMymoneyWebTransactionDataXlsFileImporter) ParseImportedData(ctx c
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyWebDataColumnNameMapping, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, feideeMymoneyWebDataColumnNameMapping, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(feideeMymoneyTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func TestFeideeMymoneyTransactionDataXlsImporterParseImportedData_MinimumValidDa
|
|||||||
testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_test_file.xls")
|
testdata, err := os.ReadFile("../../../testdata/feidee_mymoney_test_file.xls")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, testdata, 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, testdata, time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 7, len(allNewTransactions))
|
assert.Equal(t, 7, len(allNewTransactions))
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package fireflyIII
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/csv"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/csv"
|
||||||
@@ -40,7 +41,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the firefly III transaction csv data
|
// ParseImportedData returns the imported data by parsing the firefly III transaction csv data
|
||||||
func (c *fireflyIIITransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *fireflyIIITransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
reader := bytes.NewReader(data)
|
reader := bytes.NewReader(data)
|
||||||
dataTable, err := csv.CreateNewCsvBasicDataTable(ctx, reader, true)
|
dataTable, err := csv.CreateNewCsvBasicDataTable(ctx, reader, true)
|
||||||
|
|
||||||
@@ -52,5 +53,5 @@ func (c *fireflyIIITransactionDataCsvFileImporter) ParseImportedData(ctx core.Co
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, fireflyIIITransactionDataColumnNameMapping, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromBasicDataTableWithRowParser(dataTable, fireflyIIITransactionDataColumnNameMapping, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(fireflyIIITransactionTypeNameMapping, "", "", ",")
|
dataTableImporter := converter.CreateNewImporterWithTypeNameMapping(fireflyIIITransactionTypeNameMapping, "", "", ",")
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package fireflyIII
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_MinimumValidData(t *testing.
|
|||||||
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
||||||
"Deposit,0.12,2024-09-01T01:23:45+08:00,\"A revenue account\",\"Test Account\",\"Test Category\"\n"+
|
"Deposit,0.12,2024-09-01T01:23:45+08:00,\"A revenue account\",\"Test Account\",\"Test Category\"\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category2\"\n"+
|
"Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category2\"\n"+
|
||||||
"Transfer,0.05,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,0.05,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category3\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -93,11 +94,11 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidTime(t *testing.
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01T12:34:56,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-1.00,2024-09-01T12:34:56,\"Test Account\",\"A expense account\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01 12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-1.00,2024-09-01 12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +112,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidType(t *testing.
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Type,123.45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Type,123.45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,14 +126,14 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseAccountNameAsCategoryNa
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-1.00,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, "A expense account", allNewTransactions[0].OriginalCategoryName)
|
assert.Equal(t, "A expense account", allNewTransactions[0].OriginalCategoryName)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Deposit,10.00,2024-09-01T12:34:56+08:00,\"A revenue account\",\"Test Account\",\"\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Deposit,10.00,2024-09-01T12:34:56+08:00,\"A revenue account\",\"Test Account\",\"\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -149,19 +150,19 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidTimezone(t *testin
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01T12:34:56-10:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-1.00,2024-09-01T12:34:56-10:00,\"Test Account\",\"A expense account\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01T12:34:56+00:00,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-1.00,2024-09-01T12:34:56+00:00,\"Test Account\",\"A expense account\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725194096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-1.00,2024-09-01T12:34:56+12:45,\"Test Account\",\"A expense account\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-1.00,2024-09-01T12:34:56+12:45,\"Test Account\",\"A expense account\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -178,7 +179,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidAccountCurrency(t
|
|||||||
|
|
||||||
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
allNewTransactions, allNewAccounts, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
||||||
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category2\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -204,7 +205,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidForeignAmountAndCu
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"Transfer,10.00,15.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,10.00,15.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -215,7 +216,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidForeignAmountAndCu
|
|||||||
assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency)
|
assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"Transfer,10.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,10.00,2024-09-01T12:34:56+08:00,USD,EUR,\"Test Account\",\"Test Account2\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -225,7 +226,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseValidForeignAmountAndCu
|
|||||||
assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency)
|
assert.Equal(t, "EUR", allNewTransactions[0].OriginalDestinationAccountCurrency)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"Transfer,10.00,2024-09-01T12:34:56+08:00,USD,,\"Test Account\",\"Test Account2\",\"Test Category\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,10.00,2024-09-01T12:34:56+08:00,USD,,\"Test Account\",\"Test Account2\",\"Test Category\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -244,12 +245,12 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidAccountCurrency(
|
|||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
||||||
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account\",\"Test Account2\",\"Test Category3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account\",\"Test Account2\",\"Test Category3\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,USD,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"+
|
||||||
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account2\",\"Test Account\",\"Test Category3\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,1.23,1.10,2024-09-01T23:59:59+08:00,CNY,EUR,\"Test Account2\",\"Test Account\",\"Test Category3\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,11 +264,11 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseNotSupportedCurrency(t
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,XXX,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Opening balance\",123.45,,2024-09-01T00:00:00+08:00,XXX,,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,currency_code,foreign_currency_code,source_name,destination_name,category\n"+
|
||||||
"Transfer,123.45,123.45,2024-09-01T23:59:59+08:00,USD,XXX,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,123.45,123.45,2024-09-01T23:59:59+08:00,USD,XXX,\"Test Account\",\"Test Account2\",\"Test Category2\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,11 +282,11 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseInvalidAmount(t *testin
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-123 45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-123 45,2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,foreign_amount,date,source_name,destination_name,category\n"+
|
||||||
"Transfer,123.45,123 45,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category2\""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Transfer,123.45,123 45,2024-09-01T23:59:59+08:00,\"Test Account\",\"Test Account2\",\"Test Category2\""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +300,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseDescription(t *testing.
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,description,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,description,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-123.45,\"foo bar\t#test\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-123.45,\"foo bar\t#test\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -316,7 +317,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_ParseTags(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte("type,amount,tags,date,source_name,destination_name,category\n"+
|
allNewTransactions, _, _, _, _, allNewTags, err := importer.ParseImportedData(context, user, []byte("type,amount,tags,date,source_name,destination_name,category\n"+
|
||||||
"Withdrawal,-123.45,\"tag1,tag2,tag3\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"Withdrawal,-123.45,\"tag1,tag2,tag3\",2024-09-01T12:34:56+08:00,\"Test Account\",\"A expense account\",\"Test Category\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -338,7 +339,7 @@ func TestFireFlyIIICsvFileimporterParseImportedData_MissingFileHeader(t *testing
|
|||||||
DefaultCurrency: "CNY",
|
DefaultCurrency: "CNY",
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,31 +354,31 @@ func TestFireFlyIIICsvFileimporterParseImportedData_MissingRequiredColumn(t *tes
|
|||||||
|
|
||||||
// Missing Time Column
|
// Missing Time Column
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte("type,amount,source_name,destination_name,category\n"+
|
||||||
"\"Opening balance\",123.45,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Opening balance\",123.45,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Type Column
|
// Missing Type Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("amount,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("amount,date,source_name,destination_name,category\n"+
|
||||||
"123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Sub Category Column
|
// Missing Sub Category Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,destination_name\n"+
|
||||||
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\"\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\"\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Account Name Column
|
// Missing Account Name Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,destination_name,category\n"+
|
||||||
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Test Account\",\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,date,source_name,destination_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,date,source_name,destination_name,category\n"+
|
||||||
"\"Opening balance\",2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Opening balance\",2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\"Test Account\",\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Account2 Name Column
|
// Missing Account2 Name Column
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,category\n"+
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte("type,amount,date,source_name,category\n"+
|
||||||
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"\"Opening balance\",123.45,2024-09-01T00:00:00+08:00,\"Initial balance for \"\"Test Account\"\"\",\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func (p *fireflyIIITransactionDataRowParser) Parse(data map[datatable.Transactio
|
|||||||
}
|
}
|
||||||
|
|
||||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
||||||
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Location())
|
rowData[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Unix(), dateTime.Location())
|
||||||
}
|
}
|
||||||
|
|
||||||
// trim trailing zero in decimal
|
// trim trailing zero in decimal
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package gnucash
|
package gnucash
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -24,7 +26,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the gnucash transaction data
|
// ParseImportedData returns the imported data by parsing the gnucash transaction data
|
||||||
func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
gnucashDataReader, err := createNewGnuCashDatabaseReader(data)
|
gnucashDataReader, err := createNewGnuCashDatabaseReader(data)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -45,5 +47,5 @@ func (c *gnucashTransactionDataImporter) ParseImportedData(ctx core.Context, use
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(gnucashTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(gnucashTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -194,7 +195,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidData(t *tes
|
|||||||
DefaultCurrency: "CNY",
|
DefaultCurrency: "CNY",
|
||||||
}
|
}
|
||||||
|
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(gnucashMinimumValidDataCase), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(gnucashMinimumValidDataCase), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
|
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
|
||||||
@@ -218,7 +219,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_GzippedMinimumValidData
|
|||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
gzippedData := buffer.Bytes()
|
gzippedData := buffer.Bytes()
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, gzippedData, 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, gzippedData, time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
|
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
|
||||||
@@ -357,7 +358,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MinimumValidDataWithRev
|
|||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
"</gnc:book>\n"+
|
"</gnc:book>\n"+
|
||||||
"</gnc-v2>\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</gnc-v2>\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
|
checkParsedMinimumValidData(t, allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags)
|
||||||
@@ -389,7 +390,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *tes
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -409,7 +410,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidTime(t *tes
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +440,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *t
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725230096), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -461,7 +462,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidTimezone(t *t
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
assert.Equal(t, int64(1725148196), utils.GetUnixTimeFromTransactionTime(allNewTransactions[0].TransactionTime))
|
||||||
@@ -558,7 +559,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAccountCurren
|
|||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
"</gnc:book>\n"+
|
"</gnc:book>\n"+
|
||||||
"</gnc-v2>\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</gnc-v2>\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -600,7 +601,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *tes
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -623,7 +624,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseValidAmount(t *tes
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -656,7 +657,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -676,7 +677,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -696,7 +697,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseInvalidAmount(t *t
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,7 +728,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_ParseDescription(t *tes
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -756,7 +757,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_SkipZeroAmountTransacti
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,7 +807,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_NotSupportedToParseSpli
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,7 +874,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingAccountRequiredN
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -901,7 +902,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
||||||
|
|
||||||
// Missing Transaction Splits Node
|
// Missing Transaction Splits Node
|
||||||
@@ -912,7 +913,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
|
|||||||
" <ts:date>2024-09-01 00:00:00 +0000</ts:date>\n"+
|
" <ts:date>2024-09-01 00:00:00 +0000</ts:date>\n"+
|
||||||
" </trn:date-posted>\n"+
|
" </trn:date-posted>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidGnuCashFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidGnuCashFile.Message)
|
||||||
|
|
||||||
// Missing Transaction Split Quantity Node
|
// Missing Transaction Split Quantity Node
|
||||||
@@ -931,7 +932,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
// Missing Transaction Split Account Node
|
// Missing Transaction Split Account Node
|
||||||
@@ -951,7 +952,7 @@ func TestGnuCashTransactionDatabaseFileParseImportedData_MissingTransactionRequi
|
|||||||
" </trn:split>\n"+
|
" </trn:split>\n"+
|
||||||
" </trn:splits>\n"+
|
" </trn:splits>\n"+
|
||||||
"</gnc:transaction>\n"+
|
"</gnc:transaction>\n"+
|
||||||
gnucashCommonValidDataCaseFooter), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
gnucashCommonValidDataCaseFooter), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
|
assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func (t *gnucashTransactionDataRowIterator) parseTransaction(ctx core.Context, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = utils.FormatUnixTimeToLongDateTime(dateTime.Unix(), dateTime.Location())
|
||||||
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Location())
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIMEZONE] = utils.FormatTimezoneOffset(dateTime.Unix(), dateTime.Location())
|
||||||
|
|
||||||
if len(gnucashTransaction.Splits) == 2 {
|
if len(gnucashTransaction.Splits) == 2 {
|
||||||
splitData1 := gnucashTransaction.Splits[0]
|
splitData1 := gnucashTransaction.Splits[0]
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package iif
|
package iif
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -23,7 +25,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the intuit interchange format (iif) data
|
// ParseImportedData returns the imported data by parsing the intuit interchange format (iif) data
|
||||||
func (c *iifTransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *iifTransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
iifDataReader := createNewIifDataReader(data)
|
iifDataReader := createNewIifDataReader(data)
|
||||||
accountDatasets, transactionDatasets, err := iifDataReader.read(ctx)
|
accountDatasets, transactionDatasets, err := iifDataReader.read(ctx)
|
||||||
|
|
||||||
@@ -39,5 +41,5 @@ func (c *iifTransactionDataFileImporter) ParseImportedData(ctx core.Context, use
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(iifTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(iifTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package iif
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
|
|||||||
"ENDTRNS\t\t\t\t\n"+
|
"ENDTRNS\t\t\t\t\n"+
|
||||||
"TRNS\tCREDIT CARD\t09/07/2024\tTest Category2\t34.56\n"+
|
"TRNS\tCREDIT CARD\t09/07/2024\tTest Category2\t34.56\n"+
|
||||||
"SPL\tCREDIT CARD\t09/07/2024\tTest Account2\t-34.56\n"+
|
"SPL\tCREDIT CARD\t09/07/2024\tTest Account2\t-34.56\n"+
|
||||||
"ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ func TestIIFTransactionDataFileParseImportedData_MinimumValidDataWithoutAccountD
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Category\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Category\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -203,7 +204,7 @@ func TestIIFTransactionDataFileParseImportedData_MultipleDataset(t *testing.T) {
|
|||||||
"ENDTRNS\t\t\t\t\n"+
|
"ENDTRNS\t\t\t\t\n"+
|
||||||
"!ACCNT\tTEST\tNAME\tACCNTTYPE\n"+
|
"!ACCNT\tTEST\tNAME\tACCNTTYPE\n"+
|
||||||
"ACCNT\t\tTest Category\tINC\n"+
|
"ACCNT\t\tTest Category\tINC\n"+
|
||||||
"ACCNT\t\tTest Category2\tEXP\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ACCNT\t\tTest Category2\tEXP\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -268,7 +269,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseCategoryAndSubCategory(t *
|
|||||||
"ENDTRNS\t\t\t\n"+
|
"ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/02/2024\tTest Account2\t-123.45\n"+
|
"TRNS\t09/02/2024\tTest Account2\t-123.45\n"+
|
||||||
"SPL\t09/02/2024\tTest Parent Category2:Test Category2\t123.45\n"+
|
"SPL\t09/02/2024\tTest Parent Category2:Test Category2\t123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -323,7 +324,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseYearMonthDayFormatTime(t *
|
|||||||
"ENDTRNS\t\t\t\n"+
|
"ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t2024/9/4\tTest Account\t123.45\n"+
|
"TRNS\t2024/9/4\tTest Account\t123.45\n"+
|
||||||
"SPL\t2024/9/4\tTest Account2\t-123.45\n"+
|
"SPL\t2024/9/4\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -355,7 +356,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayYearFormatTim
|
|||||||
"ENDTRNS\t\t\t\n"+
|
"ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t9/3/2024\tTest Account\t123.45\n"+
|
"TRNS\t9/3/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t9/3/2024\tTest Account2\t-123.45\n"+
|
"SPL\t9/3/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -386,7 +387,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseShortMonthDayTwoDigitsYear
|
|||||||
"ENDTRNS\t\t\t\n"+
|
"ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t24/9/3\tTest Account\t123.45\n"+
|
"TRNS\t24/9/3\tTest Account\t123.45\n"+
|
||||||
"SPL\t24/9/3\tTest Account2\t-123.45\n"+
|
"SPL\t24/9/3\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -411,7 +412,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T)
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09-01-2024\tTest Account\t123.45\n"+
|
"TRNS\t09-01-2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09-01-2024\tTest Account2\t-123.45\n"+
|
"SPL\t09-01-2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -420,7 +421,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T)
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t2024-09-01\tTest Account\t123.45\n"+
|
"TRNS\t2024-09-01\tTest Account\t123.45\n"+
|
||||||
"SPL\t2024-09-01\tTest Account2\t-123.45\n"+
|
"SPL\t2024-09-01\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -429,7 +430,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T)
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t9/24\tTest Account\t123.45\n"+
|
"TRNS\t9/24\tTest Account\t123.45\n"+
|
||||||
"SPL\t9/24\tTest Account2\t-123.45\n"+
|
"SPL\t9/24\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +449,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparat
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t9/01/2024\tTest Account\t123,456.78\n"+
|
"TRNS\t9/01/2024\tTest Account\t123,456.78\n"+
|
||||||
"SPL\t9/01/2024\tTest Account2\t-123,456.78\n"+
|
"SPL\t9/01/2024\tTest Account2\t-123,456.78\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -471,7 +472,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123 45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123 45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -480,7 +481,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123 45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123 45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,7 +500,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
"!ENDTRNS\t\t\t\t\t\n"+
|
"!ENDTRNS\t\t\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+
|
"TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+
|
"SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+
|
||||||
"ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -511,7 +512,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
"!ENDTRNS\t\t\t\t\t\n"+
|
"!ENDTRNS\t\t\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\tTest\t123.45\t\n"+
|
"TRNS\t09/01/2024\tTest Account\tTest\t123.45\t\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+
|
"SPL\t09/01/2024\tTest Account2\t\t-123.45\t\n"+
|
||||||
"ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -553,7 +554,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransaction(t *testin
|
|||||||
"TRNS\t09/05/2024\tTest Category2\t100.00\n"+
|
"TRNS\t09/05/2024\tTest Category2\t100.00\n"+
|
||||||
"SPL\t09/05/2024\tTest Account3\t-40.00\n"+
|
"SPL\t09/05/2024\tTest Account3\t-40.00\n"+
|
||||||
"SPL\t09/05/2024\tTest Account4\t-60.00\n"+
|
"SPL\t09/05/2024\tTest Account4\t-60.00\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -667,7 +668,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescriptio
|
|||||||
"TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+
|
"TRNS\t09/01/2024\tTest Account\t\"Test\"\t123.45\t\"foo bar\t#test\"\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"foo\ttest#bar\"\n"+
|
"SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"foo\ttest#bar\"\n"+
|
||||||
"SPL\t09/01/2024\tTest Account3\t\t-23.45\t\n"+
|
"SPL\t09/01/2024\tTest Account3\t\t-23.45\t\n"+
|
||||||
"ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(allNewTransactions))
|
assert.Equal(t, 2, len(allNewTransactions))
|
||||||
@@ -682,7 +683,7 @@ func TestIIFTransactionDataFileParseImportedData_ParseSplitTransactionDescriptio
|
|||||||
"SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"test\"\n"+
|
"SPL\t09/01/2024\tTest Account2\t\t-100.00\t\"test\"\n"+
|
||||||
"SPL\t09/01/2024\tTest Account3\tfoo\t-12.34\t\n"+
|
"SPL\t09/01/2024\tTest Account3\tfoo\t-12.34\t\n"+
|
||||||
"SPL\t09/01/2024\tTest Account4\t\t-11.11\t\n"+
|
"SPL\t09/01/2024\tTest Account4\t\t-11.11\t\n"+
|
||||||
"ENDTRNS\t\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 3, len(allNewTransactions))
|
assert.Equal(t, 3, len(allNewTransactions))
|
||||||
@@ -708,7 +709,7 @@ func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t
|
|||||||
"TRNS\tBEGINBALCHECK\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\tBEGINBALCHECK\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\tBEGINBALCHECK\t09/01/2024\tTest Account2\t-100.00\n"+
|
"SPL\tBEGINBALCHECK\t09/01/2024\tTest Account2\t-100.00\n"+
|
||||||
"SPL\tBEGINBALCHECK\t09/01/2024\tTest Account3\t-23.45\n"+
|
"SPL\tBEGINBALCHECK\t09/01/2024\tTest Account3\t-23.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
||||||
|
|
||||||
// Transaction with invalid amount
|
// Transaction with invalid amount
|
||||||
@@ -719,7 +720,7 @@ func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123 45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123 45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-100.00\n"+
|
"SPL\t09/01/2024\tTest Account2\t-100.00\n"+
|
||||||
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+
|
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
// Transaction split data with invalid amount
|
// Transaction split data with invalid amount
|
||||||
@@ -730,7 +731,7 @@ func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-100 00\n"+
|
"SPL\t09/01/2024\tTest Account2\t-100 00\n"+
|
||||||
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+
|
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
|
|
||||||
// Transaction amount not equal to sum of split data amount
|
// Transaction amount not equal to sum of split data amount
|
||||||
@@ -741,7 +742,7 @@ func TestIIFTransactionDataFileParseImportedData_NotSupportedSplitTransaction(t
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123.00\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.00\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-100.00\n"+
|
"SPL\t09/01/2024\tTest Account2\t-100.00\n"+
|
||||||
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+
|
"SPL\t09/01/2024\tTest Account3\t-23.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
assert.EqualError(t, err, errs.ErrNotSupportedSplitTransactions.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,7 +761,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Transaction And Split Line
|
// Missing Transaction And Split Line
|
||||||
@@ -768,7 +769,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Split Line
|
// Missing Split Line
|
||||||
@@ -777,7 +778,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Transaction End Line
|
// Missing Transaction End Line
|
||||||
@@ -786,7 +787,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Transaction End Line (following is another header)
|
// Missing Transaction End Line (following is another header)
|
||||||
@@ -797,7 +798,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"!ACCNT\tNAME\tACCNTTYPE\n"+
|
"!ACCNT\tNAME\tACCNTTYPE\n"+
|
||||||
"ACCNT\tTest Account\tBANK\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ACCNT\tTest Account\tBANK\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Invalid Line
|
// Invalid Line
|
||||||
@@ -808,7 +809,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"TEST\t\t\t\n"+
|
"TEST\t\t\t\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Repeat Transaction Line
|
// Repeat Transaction Line
|
||||||
@@ -819,7 +820,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Repeat Transaction End Line
|
// Repeat Transaction End Line
|
||||||
@@ -831,7 +832,7 @@ func TestIIFTransactionDataFileParseImportedData_InvalidDataLines(t *testing.T)
|
|||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"+
|
"ENDTRNS\t\t\t\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,25 +849,25 @@ func TestIIFTransactionDataFileParseImportedData_InvalidHeaderLines(t *testing.T
|
|||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Transaction Sample Line
|
// Missing Transaction Sample Line
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"!ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Split Sample Line
|
// Missing Split Sample Line
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"!ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Transaction End Sample Line
|
// Missing Transaction End Sample Line
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Missing Transaction End Sample Line (following is data line)
|
// Missing Transaction End Sample Line (following is data line)
|
||||||
@@ -875,14 +876,14 @@ func TestIIFTransactionDataFileParseImportedData_InvalidHeaderLines(t *testing.T
|
|||||||
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
"!SPL\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
"TRNS\t09/01/2024\tTest Account\t123.45\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
"SPL\t09/01/2024\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
|
|
||||||
// Invalid Sample Line
|
// Invalid Sample Line
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
"!TRNS\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!TEST\tDATE\tACCNT\tAMOUNT\n"+
|
"!TEST\tDATE\tACCNT\tAMOUNT\n"+
|
||||||
"!ENDTRNS\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"!ENDTRNS\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
assert.EqualError(t, err, errs.ErrInvalidIIFFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,7 +903,7 @@ func TestIIFTransactionDataFileParseImportedData_MissingRequiredColumn(t *testin
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\tTest Account\t123.45\n"+
|
"TRNS\tTest Account\t123.45\n"+
|
||||||
"SPL\tTest Account2\t-123.45\n"+
|
"SPL\tTest Account2\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Account Column
|
// Missing Account Column
|
||||||
@@ -912,7 +913,7 @@ func TestIIFTransactionDataFileParseImportedData_MissingRequiredColumn(t *testin
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\t123.45\n"+
|
"TRNS\t09/01/2024\t123.45\n"+
|
||||||
"SPL\t09/01/2024\t-123.45\n"+
|
"SPL\t09/01/2024\t-123.45\n"+
|
||||||
"ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
@@ -922,6 +923,6 @@ func TestIIFTransactionDataFileParseImportedData_MissingRequiredColumn(t *testin
|
|||||||
"!ENDTRNS\t\t\t\n"+
|
"!ENDTRNS\t\t\t\n"+
|
||||||
"TRNS\t09/01/2024\tTest Account\n"+
|
"TRNS\t09/01/2024\tTest Account\n"+
|
||||||
"SPL\t09/01/2024\tTest Account2\n"+
|
"SPL\t09/01/2024\tTest Account2\n"+
|
||||||
"ENDTRNS\t\t\t\t\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"ENDTRNS\t\t\t\t\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package jdcom
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/unicode"
|
"golang.org/x/text/encoding/unicode"
|
||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
@@ -27,7 +28,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the jd.com finance transaction csv data
|
// ParseImportedData returns the imported data by parsing the jd.com finance transaction csv data
|
||||||
func (c *jdComFinanceTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *jdComFinanceTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
fallback := unicode.UTF8.NewDecoder()
|
fallback := unicode.UTF8.NewDecoder()
|
||||||
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
|
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
|
||||||
|
|
||||||
@@ -60,5 +61,5 @@ func (c *jdComFinanceTransactionDataCsvFileImporter) ParseImportedData(ctx core.
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, jdComFinanceTransactionSupportedColumns, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, jdComFinanceTransactionSupportedColumns, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(jdComFinanceTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(jdComFinanceTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MinimumValidData(t *testin
|
|||||||
"2025-09-01 12:34:56,xxx,xxx,123.45,银行卡,交易成功,支出,其他网购\n" +
|
"2025-09-01 12:34:56,xxx,xxx,123.45,银行卡,交易成功,支出,其他网购\n" +
|
||||||
"2025-09-01 23:59:59,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n" +
|
"2025-09-01 23:59:59,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n" +
|
||||||
"2025-09-02 23:59:59,xxx,京东余额提现,0.03,银行卡,交易成功,不计收支,余额\n"
|
"2025-09-02 23:59:59,xxx,京东余额提现,0.03,银行卡,交易成功,不计收支,余额\n"
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 4, len(allNewTransactions))
|
assert.Equal(t, 4, len(allNewTransactions))
|
||||||
@@ -111,7 +111,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseRefundTransaction(t *
|
|||||||
"2025-09-01 02:34:56,xxx,xxx,0.12(已全额退款),银行卡,交易成功,不计收支\n" +
|
"2025-09-01 02:34:56,xxx,xxx,0.12(已全额退款),银行卡,交易成功,不计收支\n" +
|
||||||
"2025-09-02 01:23:45,xxx,xxx,3.45,银行卡,退款成功,不计收支\n" +
|
"2025-09-02 01:23:45,xxx,xxx,3.45,银行卡,退款成功,不计收支\n" +
|
||||||
"2025-09-02 02:34:56,xxx,xxx,123.45(已退款3.45),银行卡,交易成功,支出\n"
|
"2025-09-02 02:34:56,xxx,xxx,123.45(已退款3.45),银行卡,交易成功,支出\n"
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
||||||
@@ -154,7 +154,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidTime(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01T01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
"2025-09-01T01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
data2 := "导出信息:\n" +
|
data2 := "导出信息:\n" +
|
||||||
@@ -163,7 +163,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidTime(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"09/01/2025 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
"09/01/2025 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidType(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,转账\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,转账\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseInvalidAmount(t *test
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,¥0.12,银行卡,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,xxx,¥0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" +
|
||||||
"2025-09-01 01:23:45,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n"
|
"2025-09-01 01:23:45,xxx,京东钱包余额充值,0.05,银行卡,交易成功,不计收支,余额\n"
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -236,7 +236,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支,交易分类\n" +
|
||||||
"2025-09-01 01:23:45,xxx,京东余额提现,0.05,银行卡,交易成功,不计收支,余额\n"
|
"2025-09-01 01:23:45,xxx,京东余额提现,0.05,银行卡,交易成功,不计收支,余额\n"
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -253,7 +253,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
|
|||||||
"2025-09-01 01:23:45,xxx,京东小金库-转入,0.05,余额,交易成功,不计收支,小金库\n"
|
"2025-09-01 01:23:45,xxx,京东小金库-转入,0.05,余额,交易成功,不计收支,小金库\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -270,7 +270,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
|
|||||||
"2025-09-01 01:23:45,xxx,京东小金库-转出,0.05,余额,交易成功,不计收支,小金库\n"
|
"2025-09-01 01:23:45,xxx,京东小金库-转出,0.05,余额,交易成功,不计收支,小金库\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -287,7 +287,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
|
|||||||
"2025-09-01 01:23:45,xxx,价保退款,0.05,银行卡,交易成功,不计收支,其他\n"
|
"2025-09-01 01:23:45,xxx,价保退款,0.05,银行卡,交易成功,不计收支,其他\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -303,7 +303,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseAccountName(t *testin
|
|||||||
"2025-09-01 01:23:45,xxx,白条主动还款,0.05,银行卡,交易成功,不计收支,白条\n"
|
"2025-09-01 01:23:45,xxx,白条主动还款,0.05,银行卡,交易成功,不计收支,白条\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -327,7 +327,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,,0.12,银行卡,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,,0.12,银行卡,交易成功,支出\n"
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -339,7 +339,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" +
|
"交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\"foo\"\"bar,\ntest\"\n"
|
"2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\"foo\"\"bar,\ntest\"\n"
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment)
|
assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment)
|
||||||
|
|
||||||
@@ -349,7 +349,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_ParseDescription(t *testin
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" +
|
"交易时间,商户名称,交易说明,交易说明,金额,收/付款方式,交易状态,收/支,备注\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\n"
|
"2025-09-01 01:23:45,xxx,xxx,Test,0.12,银行卡,交易成功,支出,\n"
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, "Test", allNewTransactions[0].Comment)
|
assert.Equal(t, "Test", allNewTransactions[0].Comment)
|
||||||
}
|
}
|
||||||
@@ -369,7 +369,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownStatusTransacti
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,xxxx,支出\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,xxxx,支出\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,7 +388,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_SkipUnknownMemoTransferTra
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,不计收支\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,不计收支\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,10 +403,10 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingFileHeader(t *testi
|
|||||||
|
|
||||||
data := "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
data := "交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +426,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
"xxx,xxx,0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
|
|
||||||
// Missing Merchant Name Column
|
// Missing Merchant Name Column
|
||||||
@@ -436,7 +436,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,交易说明,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Transaction Memo Column
|
// Missing Transaction Memo Column
|
||||||
@@ -446,7 +446,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,金额,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,金额,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,0.12,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
@@ -456,7 +456,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,收/付款方式,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,收/付款方式,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,银行卡,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,xxx,银行卡,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Related Account Column
|
// Missing Related Account Column
|
||||||
@@ -466,7 +466,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,交易状态,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,交易状态,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,交易成功,支出\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,交易成功,支出\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Status Column
|
// Missing Status Column
|
||||||
@@ -476,7 +476,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,收/支\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,收/支\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,支出\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,支出\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data6), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Type Column
|
// Missing Type Column
|
||||||
@@ -486,7 +486,7 @@ func TestJDComFinanceCsvFileImporterParseImportedData_MissingRequiredColumn(t *t
|
|||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态\n" +
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态\n" +
|
||||||
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功\n"
|
"2025-09-01 01:23:45,xxx,xxx,0.12,银行卡,交易成功\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data7), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data7), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,6 +504,6 @@ func TestJDComFinanceCsvFileImporterParseImportedData_NoTransactionData(t *testi
|
|||||||
"日期区间:2025-01-01 至 2025-09-01\n" +
|
"日期区间:2025-01-01 至 2025-09-01\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n"
|
"交易时间,商户名称,交易说明,金额,收/付款方式,交易状态,收/支\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package mt
|
package mt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -22,7 +24,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the mt940 file statement data
|
// ParseImportedData returns the imported data by parsing the mt940 file statement data
|
||||||
func (c *mt940TransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *mt940TransactionDataFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
mt940DataReader := createNewMT940FileReader(data)
|
mt940DataReader := createNewMT940FileReader(data)
|
||||||
mt940Data, err := mt940DataReader.read(ctx)
|
mt940Data, err := mt940DataReader.read(ctx)
|
||||||
|
|
||||||
@@ -38,5 +40,5 @@ func (c *mt940TransactionDataFileImporter) ParseImportedData(ctx core.Context, u
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(mt940TransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(mt940TransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package mt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ func TestMT940TransactionDataFileParseImportedData_MinimumValidData(t *testing.T
|
|||||||
:61:2506020603D234,56NTRFFOOBAR
|
:61:2506020603D234,56NTRFFOOBAR
|
||||||
:86:Transaction 2
|
:86:Transaction 2
|
||||||
:62F:C250601CNY123,45
|
:62F:C250601CNY123,45
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionValidAmountAn
|
|||||||
:61:250603C1,NTRFTEST
|
:61:250603C1,NTRFTEST
|
||||||
:86:Transaction 3
|
:86:Transaction 3
|
||||||
:62F:C250601CNY123,45
|
:62F:C250601CNY123,45
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 3, len(allNewTransactions))
|
assert.Equal(t, 3, len(allNewTransactions))
|
||||||
@@ -118,7 +119,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmount
|
|||||||
:60F:C250601CNY123,45
|
:60F:C250601CNY123,45
|
||||||
:61:2506010602C123 45NTRFTEST
|
:61:2506010602C123 45NTRFTEST
|
||||||
:62F:C250601CNY123,45
|
:62F:C250601CNY123,45
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
|
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -129,7 +130,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionInvalidAmount
|
|||||||
:60F:C250601CNY123,45
|
:60F:C250601CNY123,45
|
||||||
:61:2506010602C12.45NTRFTEST
|
:61:2506010602C12.45NTRFTEST
|
||||||
:62F:C250601CNY123,45
|
:62F:C250601CNY123,45
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
|
assert.EqualError(t, err, errs.ErrInvalidMT940File.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseTransactionType(t *testi
|
|||||||
:61:250604RD123,45NTRFTEST
|
:61:250604RD123,45NTRFTEST
|
||||||
:86:Transaction 4
|
:86:Transaction 4
|
||||||
:62F:C250601CNY123,45
|
:62F:C250601CNY123,45
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 4, len(allNewTransactions))
|
assert.Equal(t, 4, len(allNewTransactions))
|
||||||
@@ -187,7 +188,7 @@ func TestMT940TransactionDataFileParseImportedData_ParseDescription(t *testing.T
|
|||||||
Part 2
|
Part 2
|
||||||
Part 3
|
Part 3
|
||||||
:62F:C250601CNY123,45
|
:62F:C250601CNY123,45
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -210,6 +211,6 @@ func TestMT940TransactionDataFileParseImportedData_MissingRequiredField(t *testi
|
|||||||
:28C:123/1
|
:28C:123/1
|
||||||
:61:250601C123,45NTRFTEST
|
:61:250601C123,45NTRFTEST
|
||||||
:86:Transaction 1
|
:86:Transaction 1
|
||||||
-}`), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
-}`), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package ofx
|
package ofx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -23,7 +25,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the open financial exchange (ofx) file transaction data
|
// ParseImportedData returns the imported data by parsing the open financial exchange (ofx) file transaction data
|
||||||
func (c *ofxTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *ofxTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
ofxDataReader, err := createNewOFXFileReader(ctx, data)
|
ofxDataReader, err := createNewOFXFileReader(ctx, data)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,5 +46,5 @@ func (c *ofxTransactionDataImporter) ParseImportedData(ctx core.Context, user *m
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(ofxTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(ofxTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ofx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ func TestOFXTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
|
|||||||
" </CCSTMTRS>\n"+
|
" </CCSTMTRS>\n"+
|
||||||
" </CCSTMTTRNRS>\n"+
|
" </CCSTMTTRNRS>\n"+
|
||||||
" </CREDITCARDMSGSRSV1>\n"+
|
" </CREDITCARDMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -211,7 +212,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAccountTo(t *testing.T) {
|
|||||||
" </CCSTMTRS>\n"+
|
" </CCSTMTRS>\n"+
|
||||||
" </CCSTMTTRNRS>\n"+
|
" </CCSTMTTRNRS>\n"+
|
||||||
" </CREDITCARDMSGSRSV1>\n"+
|
" </CREDITCARDMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -296,7 +297,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseValidTransactionTime(t *te
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -338,7 +339,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -360,7 +361,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -382,7 +383,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
@@ -404,7 +405,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidTransactionTime(t *
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +437,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseAmount_CommaAsDecimalPoint
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -472,7 +473,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,7 +506,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseTransactionCurrency(t *tes
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -542,7 +543,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -568,7 +569,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -596,7 +597,7 @@ func TestOFXTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -629,7 +630,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingAccountFromNode(t *testi
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
|
assert.EqualError(t, err, errs.ErrMissingAccountData.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,7 +662,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingCurrencyNode(t *testing.
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAccountCurrencyInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +694,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
||||||
|
|
||||||
// Missing Transaction Type Node
|
// Missing Transaction Type Node
|
||||||
@@ -715,7 +716,7 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTypeInvalid.Message)
|
||||||
|
|
||||||
// Missing Amount Node
|
// Missing Amount Node
|
||||||
@@ -737,6 +738,6 @@ func TestOFXTransactionDataFileParseImportedData_MissingTransactionRequiredNode(
|
|||||||
" </STMTRS>\n"+
|
" </STMTRS>\n"+
|
||||||
" </STMTTRNRS>\n"+
|
" </STMTTRNRS>\n"+
|
||||||
" </BANKMSGSRSV1>\n"+
|
" </BANKMSGSRSV1>\n"+
|
||||||
"</OFX>"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"</OFX>"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package qif
|
package qif
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/core"
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/models"
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
||||||
@@ -35,7 +37,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the quicken interchange format (qif) transaction data
|
// ParseImportedData returns the imported data by parsing the quicken interchange format (qif) transaction data
|
||||||
func (c *qifTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *qifTransactionDataImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
qifDataReader := createNewQifDataReader(data)
|
qifDataReader := createNewQifDataReader(data)
|
||||||
qifData, err := qifDataReader.read(ctx)
|
qifData, err := qifDataReader.read(ctx)
|
||||||
|
|
||||||
@@ -51,5 +53,5 @@ func (c *qifTransactionDataImporter) ParseImportedData(ctx core.Context, user *m
|
|||||||
|
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(qifTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(qifTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package qif
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ func TestQIFTransactionDataFileParseImportedData_MinimumValidData(t *testing.T)
|
|||||||
"D2024-09-05\n"+
|
"D2024-09-05\n"+
|
||||||
"T0.06\n"+
|
"T0.06\n"+
|
||||||
"L[Test Account2]\n"+
|
"L[Test Account2]\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseYearMonthDayDateFormatTime
|
|||||||
"^\n"+
|
"^\n"+
|
||||||
"D2024'9.5\n"+
|
"D2024'9.5\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -176,7 +177,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseMonthDayYearDateFormatTime
|
|||||||
"^\n"+
|
"^\n"+
|
||||||
"D9.5'2024\n"+
|
"D9.5'2024\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -214,7 +215,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDayYearMonthDateFormatTime
|
|||||||
"^\n"+
|
"^\n"+
|
||||||
"D5'9.2024\n"+
|
"D5'9.2024\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -252,7 +253,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseShortYearMonthDayDateForma
|
|||||||
"^\n"+
|
"^\n"+
|
||||||
"D24'9.5\n"+
|
"D24'9.5\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -278,7 +279,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseInvalidTime(t *testing.T)
|
|||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"D2024 09 01\n"+
|
"D2024 09 01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +296,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAmountWithThousandsSeparat
|
|||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123,456.78\n"+
|
"T-123,456.78\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
@@ -317,7 +318,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseInvalidAmount(t *testing.T
|
|||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123 45\n"+
|
"T-123 45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +335,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
|
|||||||
"!Type:Cash\n"+
|
"!Type:Cash\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -347,7 +348,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
|
|||||||
"!Type:CCard\n"+
|
"!Type:CCard\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -360,7 +361,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
|
|||||||
"!Type:Oth A\n"+
|
"!Type:Oth A\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -373,7 +374,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccountType(t *testing.T)
|
|||||||
"!Type:Oth L\n"+
|
"!Type:Oth L\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -399,7 +400,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAccount(t *testing.T) {
|
|||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -425,7 +426,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseAmountWithLeadingPlusSign(
|
|||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T+123.45\n"+
|
"T+123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -446,7 +447,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseSubCategory(t *testing.T)
|
|||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"LTest Category:Sub Category\n"+
|
"LTest Category:Sub Category\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -477,7 +478,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
"D2024-09-02\n"+
|
"D2024-09-02\n"+
|
||||||
"T-234.56\n"+
|
"T-234.56\n"+
|
||||||
"PTest2\n"+
|
"PTest2\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(allNewTransactions))
|
assert.Equal(t, 2, len(allNewTransactions))
|
||||||
@@ -494,7 +495,7 @@ func TestQIFTransactionDataFileParseImportedData_ParseDescription(t *testing.T)
|
|||||||
"D2024-09-02\n"+
|
"D2024-09-02\n"+
|
||||||
"T-234.56\n"+
|
"T-234.56\n"+
|
||||||
"PTest2\n"+
|
"PTest2\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions.WithPayeeAsDescription(), nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions.WithPayeeAsDescription(), nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(allNewTransactions))
|
assert.Equal(t, 2, len(allNewTransactions))
|
||||||
@@ -516,7 +517,7 @@ func TestQIFTransactionDataFileParseImportedData_WithAdditionalOptions(t *testin
|
|||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"PTest2\n"+
|
"PTest2\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -527,7 +528,7 @@ func TestQIFTransactionDataFileParseImportedData_WithAdditionalOptions(t *testin
|
|||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"PTest2\n"+
|
"PTest2\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions.WithPayeeAsTag(), nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions.WithPayeeAsTag(), nil, nil, nil, nil, nil)
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -548,13 +549,13 @@ func TestQIFTransactionDataFileParseImportedData_MissingRequiredFields(t *testin
|
|||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(
|
||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"T-123.45\n"+
|
"T-123.45\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
assert.EqualError(t, err, errs.ErrMissingTransactionTime.Message)
|
||||||
|
|
||||||
// Missing Amount Field
|
// Missing Amount Field
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(
|
||||||
"!Type:Bank\n"+
|
"!Type:Bank\n"+
|
||||||
"D2024-09-01\n"+
|
"D2024-09-01\n"+
|
||||||
"^\n"), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
"^\n"), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package wechat
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/unicode"
|
"golang.org/x/text/encoding/unicode"
|
||||||
"golang.org/x/text/transform"
|
"golang.org/x/text/transform"
|
||||||
@@ -27,7 +28,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the wechat pay transaction csv data
|
// ParseImportedData returns the imported data by parsing the wechat pay transaction csv data
|
||||||
func (c *wechatPayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *wechatPayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
fallback := unicode.UTF8.NewDecoder()
|
fallback := unicode.UTF8.NewDecoder()
|
||||||
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
|
reader := transform.NewReader(bytes.NewReader(data), unicode.BOMOverride(fallback))
|
||||||
|
|
||||||
@@ -58,5 +59,5 @@ func (c *wechatPayTransactionDataCsvFileImporter) ParseImportedData(ctx core.Con
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MinimumValidData(t *testing.T
|
|||||||
"2024-09-01 12:34:56,商户消费,支出,¥123.45,支付成功\n" +
|
"2024-09-01 12:34:56,商户消费,支出,¥123.45,支付成功\n" +
|
||||||
"2024-09-01 23:59:59,零钱充值,/,¥0.05,充值完成\n" +
|
"2024-09-01 23:59:59,零钱充值,/,¥0.05,充值完成\n" +
|
||||||
"2024-09-02 23:59:59,零钱提现,/,¥0.03,提现已到账\n"
|
"2024-09-02 23:59:59,零钱提现,/,¥0.03,提现已到账\n"
|
||||||
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, allNewAccounts, allNewSubExpenseCategories, allNewSubIncomeCategories, allNewSubTransferCategories, allNewTags, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 4, len(allNewTransactions))
|
assert.Equal(t, 4, len(allNewTransactions))
|
||||||
@@ -109,7 +109,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseRefundTransaction(t *tes
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01 01:23:45,xxx-退款,收入,¥0.12,已全额退款\n"
|
"2024-09-01 01:23:45,xxx-退款,收入,¥0.12,已全额退款\n"
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
assert.Equal(t, int64(1234567890), allNewTransactions[0].Uid)
|
||||||
@@ -136,7 +136,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01T01:23:45,二维码收款,收入,¥0.12,已收钱\n"
|
"2024-09-01T01:23:45,二维码收款,收入,¥0.12,已收钱\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
|
|
||||||
data2 := "微信支付账单明细,,,,\n" +
|
data2 := "微信支付账单明细,,,,\n" +
|
||||||
@@ -146,7 +146,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidTime(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"09/01/2024 12:34:56,二维码收款,收入,¥0.12,已收钱\n"
|
"09/01/2024 12:34:56,二维码收款,收入,¥0.12,已收钱\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
assert.EqualError(t, err, errs.ErrTransactionTimeInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidType(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01T01:23:45,xxx,,¥0.12,支付成功\n"
|
"2024-09-01T01:23:45,xxx,,¥0.12,支付成功\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseInvalidAmount(t *testing
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,收入,¥,已收钱\n"
|
"2024-09-01 01:23:45,二维码收款,收入,¥,已收钱\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
assert.EqualError(t, err, errs.ErrAmountInvalid.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),支付方式,当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),支付方式,当前状态\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,/,已收钱\n"
|
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,/,已收钱\n"
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -223,7 +223,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
|
|||||||
"2024-09-01 01:23:45,xxx-退款,收入,¥0.12,test,已全额退款\n"
|
"2024-09-01 01:23:45,xxx-退款,收入,¥0.12,test,已全额退款\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -239,7 +239,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
|
|||||||
"2024-09-01 23:59:59,零钱充值,/,¥0.05,test,充值完成\n"
|
"2024-09-01 23:59:59,零钱充值,/,¥0.05,test,充值完成\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -256,7 +256,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
|
|||||||
"2024-09-02 23:59:59,零钱提现,/,¥0.03,test,提现已到账\n"
|
"2024-09-02 23:59:59,零钱提现,/,¥0.03,test,提现已到账\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -273,7 +273,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseAccountName(t *testing.T
|
|||||||
"2024-09-03 23:59:59,信用卡还款,/,¥0.01,零钱,支付成功\n"
|
"2024-09-03 23:59:59,信用卡还款,/,¥0.01,零钱,支付成功\n"
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -297,7 +297,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态,备注\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态,备注\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱,\"/\"\n"
|
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱,\"/\"\n"
|
||||||
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
@@ -310,7 +310,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" +
|
"交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"foo\"\"bar,\ntest\"\n"
|
"2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"foo\"\"bar,\ntest\"\n"
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment)
|
assert.Equal(t, "foo\"bar,\ntest", allNewTransactions[0].Comment)
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_ParseDescription(t *testing.T
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" +
|
"交易时间,交易类型,商品,收/支,金额(元),当前状态,备注\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"\"\n"
|
"2024-09-01 01:23:45,二维码收款,Test,收入,¥0.12,已收钱,\"\"\n"
|
||||||
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
allNewTransactions, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.Equal(t, 1, len(allNewTransactions))
|
assert.Equal(t, 1, len(allNewTransactions))
|
||||||
assert.Equal(t, "Test", allNewTransactions[0].Comment)
|
assert.Equal(t, "Test", allNewTransactions[0].Comment)
|
||||||
}
|
}
|
||||||
@@ -342,7 +342,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_SkipUnknownTransferTransactio
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
"交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01 23:59:59,/,/,¥0.05,充值完成\n"
|
"2024-09-01 23:59:59,/,/,¥0.05,充值完成\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,10 +357,10 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingFileHeader(t *testing.
|
|||||||
|
|
||||||
data := "交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
data := "交易时间,交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱\n"
|
"2024-09-01 01:23:45,二维码收款,收入,¥0.12,已收钱\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
|
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(""), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
assert.EqualError(t, err, errs.ErrInvalidFileHeader.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +381,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易类型,收/支,金额(元),当前状态\n" +
|
"交易类型,收/支,金额(元),当前状态\n" +
|
||||||
"二维码收款,收入,¥0.12,已收钱\n"
|
"二维码收款,收入,¥0.12,已收钱\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data1), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Category Column
|
// Missing Category Column
|
||||||
@@ -392,7 +392,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,收/支,金额(元),当前状态\n" +
|
"交易时间,收/支,金额(元),当前状态\n" +
|
||||||
"2024-09-01 01:23:45,收入,¥0.12,已收钱\n"
|
"2024-09-01 01:23:45,收入,¥0.12,已收钱\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data2), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Type Column
|
// Missing Type Column
|
||||||
@@ -403,7 +403,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,金额(元),当前状态\n" +
|
"交易时间,交易类型,金额(元),当前状态\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,¥0.12,已收钱\n"
|
"2024-09-01 01:23:45,二维码收款,¥0.12,已收钱\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data3), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Amount Column
|
// Missing Amount Column
|
||||||
@@ -414,7 +414,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,当前状态\n" +
|
"交易时间,交易类型,收/支,当前状态\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,收入,已收钱\n"
|
"2024-09-01 01:23:45,二维码收款,收入,已收钱\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data4), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
|
|
||||||
// Missing Status Column
|
// Missing Status Column
|
||||||
@@ -425,7 +425,7 @@ func TestWeChatPayCsvFileImporterParseImportedData_MissingRequiredColumn(t *test
|
|||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元)\n" +
|
"交易时间,交易类型,收/支,金额(元)\n" +
|
||||||
"2024-09-01 01:23:45,二维码收款,收入,¥0.12\n"
|
"2024-09-01 01:23:45,二维码收款,收入,¥0.12\n"
|
||||||
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err = importer.ParseImportedData(context, user, []byte(data5), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
assert.EqualError(t, err, errs.ErrMissingRequiredFieldInHeaderRow.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,6 +444,6 @@ func TestWeChatPayCsvFileImporterParseImportedData_NoTransactionData(t *testing.
|
|||||||
",,,,\n" +
|
",,,,\n" +
|
||||||
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
"----------------------微信支付账单明细列表--------------------,,,,\n" +
|
||||||
"交易时间,交易类型,收/支,金额(元),当前状态\n"
|
"交易时间,交易类型,收/支,金额(元),当前状态\n"
|
||||||
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), 0, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
_, _, _, _, _, _, err := importer.ParseImportedData(context, user, []byte(data), time.UTC, converter.DefaultImporterOptions, nil, nil, nil, nil, nil)
|
||||||
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
assert.EqualError(t, err, errs.ErrNotFoundTransactionDataInFile.Message)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package wechat
|
package wechat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/converter"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
||||||
"github.com/mayswind/ezbookkeeping/pkg/converters/excel"
|
"github.com/mayswind/ezbookkeeping/pkg/converters/excel"
|
||||||
@@ -21,7 +23,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ParseImportedData returns the imported data by parsing the wechat pay transaction csv data
|
// ParseImportedData returns the imported data by parsing the wechat pay transaction csv data
|
||||||
func (c *wechatPayTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezoneOffset int16, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
func (c *wechatPayTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Context, user *models.User, data []byte, defaultTimezone *time.Location, additionalOptions converter.TransactionDataImporterOptions, accountMap map[string]*models.Account, expenseCategoryMap map[string]map[string]*models.TransactionCategory, incomeCategoryMap map[string]map[string]*models.TransactionCategory, transferCategoryMap map[string]map[string]*models.TransactionCategory, tagMap map[string]*models.TransactionTag) (models.ImportedTransactionSlice, []*models.Account, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionCategory, []*models.TransactionTag, error) {
|
||||||
xlsxDataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, false)
|
xlsxDataTable, err := excel.CreateNewExcelOOXMLFileBasicDataTable(data, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,5 +51,5 @@ func (c *wechatPayTransactionDataXlsxFileImporter) ParseImportedData(ctx core.Co
|
|||||||
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser)
|
transactionDataTable := datatable.CreateNewTransactionDataTableFromCommonDataTable(commonDataTable, wechatPayTransactionSupportedColumns, transactionRowParser)
|
||||||
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping)
|
dataTableImporter := converter.CreateNewSimpleImporterWithTypeNameMapping(wechatPayTransactionTypeNameMapping)
|
||||||
|
|
||||||
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezoneOffset, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
return dataTableImporter.ParseImportedData(ctx, user, transactionDataTable, defaultTimezone, additionalOptions, accountMap, expenseCategoryMap, incomeCategoryMap, transferCategoryMap, tagMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ func (h *mcpAddTransactionToolHandler) createNewTransactionModel(uid int64, addT
|
|||||||
Type: transactionDbType,
|
Type: transactionDbType,
|
||||||
CategoryId: categoryId,
|
CategoryId: categoryId,
|
||||||
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionTime.Unix()),
|
TransactionTime: utils.GetMinTransactionTimeFromUnixTime(transactionTime.Unix()),
|
||||||
TimezoneUtcOffset: utils.GetTimezoneOffsetMinutes(transactionTime.Location()),
|
TimezoneUtcOffset: utils.GetTimezoneOffsetMinutes(transactionTime.Unix(), transactionTime.Location()),
|
||||||
AccountId: sourceAccountId,
|
AccountId: sourceAccountId,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
HideAmount: false,
|
HideAmount: false,
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ func (s *AccountService) GetMaxSubAccountDisplayOrder(c core.Context, uid int64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateAccounts saves a new account model to database
|
// CreateAccounts saves a new account model to database
|
||||||
func (s *AccountService) CreateAccounts(c core.Context, mainAccount *models.Account, mainAccountBalanceTime int64, childrenAccounts []*models.Account, childrenAccountBalanceTimes []int64, utcOffset int16) error {
|
func (s *AccountService) CreateAccounts(c core.Context, mainAccount *models.Account, mainAccountBalanceTime int64, childrenAccounts []*models.Account, childrenAccountBalanceTimes []int64, clientTimezone *time.Location) error {
|
||||||
if mainAccount.Uid <= 0 {
|
if mainAccount.Uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -266,11 +266,14 @@ func (s *AccountService) CreateAccounts(c core.Context, mainAccount *models.Acco
|
|||||||
}
|
}
|
||||||
|
|
||||||
transactionTime := defaultTransactionTime
|
transactionTime := defaultTransactionTime
|
||||||
|
transactionUtcOffset := utils.GetTimezoneOffsetMinutes(now, clientTimezone)
|
||||||
|
|
||||||
if i == 0 && mainAccountBalanceTime > 0 {
|
if i == 0 && mainAccountBalanceTime > 0 {
|
||||||
transactionTime = utils.GetMinTransactionTimeFromUnixTime(mainAccountBalanceTime)
|
transactionTime = utils.GetMinTransactionTimeFromUnixTime(mainAccountBalanceTime)
|
||||||
|
transactionUtcOffset = utils.GetTimezoneOffsetMinutes(mainAccountBalanceTime, clientTimezone)
|
||||||
} else if i > 0 && len(childrenAccountBalanceTimes) > i-1 && childrenAccountBalanceTimes[i-1] > 0 {
|
} else if i > 0 && len(childrenAccountBalanceTimes) > i-1 && childrenAccountBalanceTimes[i-1] > 0 {
|
||||||
transactionTime = utils.GetMinTransactionTimeFromUnixTime(childrenAccountBalanceTimes[i-1])
|
transactionTime = utils.GetMinTransactionTimeFromUnixTime(childrenAccountBalanceTimes[i-1])
|
||||||
|
transactionUtcOffset = utils.GetTimezoneOffsetMinutes(childrenAccountBalanceTimes[i-1], clientTimezone)
|
||||||
} else {
|
} else {
|
||||||
defaultTransactionTime++
|
defaultTransactionTime++
|
||||||
}
|
}
|
||||||
@@ -281,7 +284,7 @@ func (s *AccountService) CreateAccounts(c core.Context, mainAccount *models.Acco
|
|||||||
Deleted: false,
|
Deleted: false,
|
||||||
Type: models.TRANSACTION_DB_TYPE_MODIFY_BALANCE,
|
Type: models.TRANSACTION_DB_TYPE_MODIFY_BALANCE,
|
||||||
TransactionTime: transactionTime,
|
TransactionTime: transactionTime,
|
||||||
TimezoneUtcOffset: utcOffset,
|
TimezoneUtcOffset: transactionUtcOffset,
|
||||||
AccountId: allAccounts[i].AccountId,
|
AccountId: allAccounts[i].AccountId,
|
||||||
Amount: allAccounts[i].Balance,
|
Amount: allAccounts[i].Balance,
|
||||||
RelatedAccountId: allAccounts[i].AccountId,
|
RelatedAccountId: allAccounts[i].AccountId,
|
||||||
@@ -366,7 +369,7 @@ func (s *AccountService) CreateAccounts(c core.Context, mainAccount *models.Acco
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ModifyAccounts saves an existed account model to database
|
// ModifyAccounts saves an existed account model to database
|
||||||
func (s *AccountService) ModifyAccounts(c core.Context, mainAccount *models.Account, updateAccounts []*models.Account, addSubAccounts []*models.Account, addSubAccountBalanceTimes []int64, removeSubAccountIds []int64, utcOffset int16) error {
|
func (s *AccountService) ModifyAccounts(c core.Context, mainAccount *models.Account, updateAccounts []*models.Account, addSubAccounts []*models.Account, addSubAccountBalanceTimes []int64, removeSubAccountIds []int64, clientTimezone *time.Location) error {
|
||||||
if mainAccount.Uid <= 0 {
|
if mainAccount.Uid <= 0 {
|
||||||
return errs.ErrUserIdInvalid
|
return errs.ErrUserIdInvalid
|
||||||
}
|
}
|
||||||
@@ -407,9 +410,11 @@ func (s *AccountService) ModifyAccounts(c core.Context, mainAccount *models.Acco
|
|||||||
}
|
}
|
||||||
|
|
||||||
transactionTime := defaultTransactionTime
|
transactionTime := defaultTransactionTime
|
||||||
|
transactionUtcOffset := utils.GetTimezoneOffsetMinutes(now, clientTimezone)
|
||||||
|
|
||||||
if len(addSubAccountBalanceTimes) > i && addSubAccountBalanceTimes[i] > 0 {
|
if len(addSubAccountBalanceTimes) > i && addSubAccountBalanceTimes[i] > 0 {
|
||||||
transactionTime = utils.GetMinTransactionTimeFromUnixTime(addSubAccountBalanceTimes[i])
|
transactionTime = utils.GetMinTransactionTimeFromUnixTime(addSubAccountBalanceTimes[i])
|
||||||
|
transactionUtcOffset = utils.GetTimezoneOffsetMinutes(addSubAccountBalanceTimes[i], clientTimezone)
|
||||||
} else {
|
} else {
|
||||||
defaultTransactionTime++
|
defaultTransactionTime++
|
||||||
}
|
}
|
||||||
@@ -420,7 +425,7 @@ func (s *AccountService) ModifyAccounts(c core.Context, mainAccount *models.Acco
|
|||||||
Deleted: false,
|
Deleted: false,
|
||||||
Type: models.TRANSACTION_DB_TYPE_MODIFY_BALANCE,
|
Type: models.TRANSACTION_DB_TYPE_MODIFY_BALANCE,
|
||||||
TransactionTime: transactionTime,
|
TransactionTime: transactionTime,
|
||||||
TimezoneUtcOffset: utcOffset,
|
TimezoneUtcOffset: transactionUtcOffset,
|
||||||
AccountId: childAccount.AccountId,
|
AccountId: childAccount.AccountId,
|
||||||
Amount: childAccount.Balance,
|
Amount: childAccount.Balance,
|
||||||
RelatedAccountId: childAccount.AccountId,
|
RelatedAccountId: childAccount.AccountId,
|
||||||
|
|||||||
+15
-10
@@ -224,12 +224,17 @@ func ParseFromLongDateTimeToMaxUnixTime(t string) (time.Time, error) {
|
|||||||
return time.ParseInLocation(longDateTimeFormat, t, timezone)
|
return time.ParseInLocation(longDateTimeFormat, t, timezone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseFromLongDateTime parses a formatted string in long date time format
|
// ParseFromLongDateTimeInFixedUtcOffset parses a formatted string in long date time format
|
||||||
func ParseFromLongDateTime(t string, utcOffset int16) (time.Time, error) {
|
func ParseFromLongDateTimeInFixedUtcOffset(t string, utcOffset int16) (time.Time, error) {
|
||||||
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
||||||
return time.ParseInLocation(longDateTimeFormat, t, timezone)
|
return time.ParseInLocation(longDateTimeFormat, t, timezone)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseFromLongDateTimeInTimeZone parses a formatted string in long date time format
|
||||||
|
func ParseFromLongDateTimeInTimeZone(t string, timezone *time.Location) (time.Time, error) {
|
||||||
|
return time.ParseInLocation(longDateTimeFormat, t, timezone)
|
||||||
|
}
|
||||||
|
|
||||||
// ParseFromLongDateTimeWithTimezone parses a formatted string in long date time format
|
// ParseFromLongDateTimeWithTimezone parses a formatted string in long date time format
|
||||||
func ParseFromLongDateTimeWithTimezone(t string) (time.Time, error) {
|
func ParseFromLongDateTimeWithTimezone(t string) (time.Time, error) {
|
||||||
return time.Parse(longDateTimeWithTimezoneFormat, t)
|
return time.Parse(longDateTimeWithTimezoneFormat, t)
|
||||||
@@ -245,14 +250,14 @@ func ParseFromLongDateTimeWithTimezoneRFC3339Format(t string) (time.Time, error)
|
|||||||
return time.Parse(longDateTimeWithTimezoneRFC3339Format, t)
|
return time.Parse(longDateTimeWithTimezoneRFC3339Format, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseFromLongDateTimeWithoutSecond parses a formatted string in long date time format (no second)
|
// ParseFromLongDateTimeWithoutSecondInFixedUtcOffset parses a formatted string in long date time format (no second) with fixed UTC offset
|
||||||
func ParseFromLongDateTimeWithoutSecond(t string, utcOffset int16) (time.Time, error) {
|
func ParseFromLongDateTimeWithoutSecondInFixedUtcOffset(t string, utcOffset int16) (time.Time, error) {
|
||||||
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
||||||
return time.ParseInLocation(longDateTimeWithoutSecondFormat, t, timezone)
|
return time.ParseInLocation(longDateTimeWithoutSecondFormat, t, timezone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseFromShortDateTime parses a formatted string in short date time format
|
// ParseFromShortDateTimeInFixedUtcOffset parses a formatted string in short date time format with fixed UTC offset
|
||||||
func ParseFromShortDateTime(t string, utcOffset int16) (time.Time, error) {
|
func ParseFromShortDateTimeInFixedUtcOffset(t string, utcOffset int16) (time.Time, error) {
|
||||||
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
||||||
return time.ParseInLocation(shortDateTimeFormat, t, timezone)
|
return time.ParseInLocation(shortDateTimeFormat, t, timezone)
|
||||||
}
|
}
|
||||||
@@ -282,8 +287,8 @@ func IsUnixTimeEqualsYearAndMonth(unixTime int64, timezone *time.Location, year
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTimezoneOffsetMinutes returns offset minutes according specified timezone
|
// GetTimezoneOffsetMinutes returns offset minutes according specified timezone
|
||||||
func GetTimezoneOffsetMinutes(timezone *time.Location) int16 {
|
func GetTimezoneOffsetMinutes(unixTime int64, timezone *time.Location) int16 {
|
||||||
_, tzOffset := time.Now().In(timezone).Zone()
|
_, tzOffset := parseFromUnixTime(unixTime).In(timezone).Zone()
|
||||||
tzMinuteOffset := int16(tzOffset / 60)
|
tzMinuteOffset := int16(tzOffset / 60)
|
||||||
|
|
||||||
return tzMinuteOffset
|
return tzMinuteOffset
|
||||||
@@ -298,8 +303,8 @@ func GetServerTimezoneOffsetMinutes() int16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FormatTimezoneOffset returns "+/-HH:MM" format of timezone
|
// FormatTimezoneOffset returns "+/-HH:MM" format of timezone
|
||||||
func FormatTimezoneOffset(timezone *time.Location) string {
|
func FormatTimezoneOffset(unixTime int64, timezone *time.Location) string {
|
||||||
tzMinutesOffset := GetTimezoneOffsetMinutes(timezone)
|
tzMinutesOffset := GetTimezoneOffsetMinutes(unixTime, timezone)
|
||||||
|
|
||||||
sign := "+"
|
sign := "+"
|
||||||
hourAbsOffset := tzMinutesOffset / 60
|
hourAbsOffset := tzMinutesOffset / 60
|
||||||
|
|||||||
+68
-17
@@ -215,15 +215,36 @@ func TestParseFromLongDateTimeToMaxUnixTime(t *testing.T) {
|
|||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseFromLongDateTime(t *testing.T) {
|
func TestParseFromLongDateTimeInFixedUtcOffset(t *testing.T) {
|
||||||
expectedValue := int64(1617228083)
|
expectedValue := int64(1617228083)
|
||||||
actualTime, err := ParseFromLongDateTime("2021-04-01 06:01:23", 480)
|
actualTime, err := ParseFromLongDateTimeInFixedUtcOffset("2021-04-01 06:01:23", 480)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
actualValue := actualTime.Unix()
|
actualValue := actualTime.Unix()
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseFromLongDateTimeInTimeZone(t *testing.T) {
|
||||||
|
londonLocation, err := time.LoadLocation("Europe/London")
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
|
// during standard time (UTC+0)
|
||||||
|
expectedValue := int64(1577858483)
|
||||||
|
actualTime, err := ParseFromLongDateTimeInTimeZone("2020-01-01 06:01:23", londonLocation)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
|
actualValue := actualTime.Unix()
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
|
// during daylight saving time (UTC+1)
|
||||||
|
expectedValue = int64(1619845283)
|
||||||
|
actualTime, err = ParseFromLongDateTimeInTimeZone("2021-05-01 06:01:23", londonLocation)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
|
actualValue = actualTime.Unix()
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseFromLongDateTimeWithTimezone(t *testing.T) {
|
func TestParseFromLongDateTimeWithTimezone(t *testing.T) {
|
||||||
expectedValue := int64(1617238883)
|
expectedValue := int64(1617238883)
|
||||||
actualTime, err := ParseFromLongDateTimeWithTimezone("2021-04-01 06:01:23+05:00")
|
actualTime, err := ParseFromLongDateTimeWithTimezone("2021-04-01 06:01:23+05:00")
|
||||||
@@ -251,18 +272,18 @@ func TestParseFromLongDateTimeWithTimezoneRFC3339Format(t *testing.T) {
|
|||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseFromLongDateTimeWithoutSecond(t *testing.T) {
|
func TestParseFromLongDateTimeWithoutSecondInFixedUtcOffset(t *testing.T) {
|
||||||
expectedValue := int64(1691947440)
|
expectedValue := int64(1691947440)
|
||||||
actualTime, err := ParseFromLongDateTimeWithoutSecond("2023-08-13 17:24", 0)
|
actualTime, err := ParseFromLongDateTimeWithoutSecondInFixedUtcOffset("2023-08-13 17:24", 0)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
actualValue := actualTime.Unix()
|
actualValue := actualTime.Unix()
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseFromShortDateTime(t *testing.T) {
|
func TestParseFromShortDateTimeInFixedUtcOffset(t *testing.T) {
|
||||||
expectedValue := int64(1617228083)
|
expectedValue := int64(1617228083)
|
||||||
actualTime, err := ParseFromShortDateTime("2021-4-1 6:1:23", 480)
|
actualTime, err := ParseFromShortDateTimeInFixedUtcOffset("2021-4-1 6:1:23", 480)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
actualValue := actualTime.Unix()
|
actualValue := actualTime.Unix()
|
||||||
@@ -312,52 +333,82 @@ func TestIsUnixTimeEqualsYearAndMonth(t *testing.T) {
|
|||||||
assert.Equal(t, false, actualValue)
|
assert.Equal(t, false, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTimezoneOffsetMinutes(t *testing.T) {
|
func TestGetTimezoneOffsetMinutes_FixedTimezone(t *testing.T) {
|
||||||
timezone := time.FixedZone("Test Timezone", 120*60)
|
timezone := time.FixedZone("Test Timezone", 120*60)
|
||||||
expectedValue := int16(120)
|
expectedValue := int16(120)
|
||||||
actualValue := GetTimezoneOffsetMinutes(timezone)
|
actualValue := GetTimezoneOffsetMinutes(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", 345*60)
|
timezone = time.FixedZone("Test Timezone", 345*60)
|
||||||
expectedValue = int16(345)
|
expectedValue = int16(345)
|
||||||
actualValue = GetTimezoneOffsetMinutes(timezone)
|
actualValue = GetTimezoneOffsetMinutes(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", -720*60)
|
timezone = time.FixedZone("Test Timezone", -720*60)
|
||||||
expectedValue = int16(-720)
|
expectedValue = int16(-720)
|
||||||
actualValue = GetTimezoneOffsetMinutes(timezone)
|
actualValue = GetTimezoneOffsetMinutes(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", 0)
|
timezone = time.FixedZone("Test Timezone", 0)
|
||||||
expectedValue = int16(0)
|
expectedValue = int16(0)
|
||||||
actualValue = GetTimezoneOffsetMinutes(timezone)
|
actualValue = GetTimezoneOffsetMinutes(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFormatTimezoneOffset(t *testing.T) {
|
func TestGetTimezoneOffsetMinutes_TimezoneWithDST(t *testing.T) {
|
||||||
|
londonLocation, err := time.LoadLocation("Europe/London")
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
|
// during standard time (UTC+0)
|
||||||
|
expectedValue := int16(0)
|
||||||
|
actualValue := GetTimezoneOffsetMinutes(1577858483, londonLocation) // 2020-01-01 06:01:23 +00:00
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
|
// during daylight saving time (UTC+1)
|
||||||
|
expectedValue = int16(60)
|
||||||
|
actualValue = GetTimezoneOffsetMinutes(1619845283, londonLocation) // 2021-05-01 06:01:23 +01:00
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatTimezoneOffset_FixedTimezone(t *testing.T) {
|
||||||
timezone := time.FixedZone("Test Timezone", 120*60)
|
timezone := time.FixedZone("Test Timezone", 120*60)
|
||||||
expectedValue := "+02:00"
|
expectedValue := "+02:00"
|
||||||
actualValue := FormatTimezoneOffset(timezone)
|
actualValue := FormatTimezoneOffset(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", 345*60)
|
timezone = time.FixedZone("Test Timezone", 345*60)
|
||||||
expectedValue = "+05:45"
|
expectedValue = "+05:45"
|
||||||
actualValue = FormatTimezoneOffset(timezone)
|
actualValue = FormatTimezoneOffset(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", -720*60)
|
timezone = time.FixedZone("Test Timezone", -720*60)
|
||||||
expectedValue = "-12:00"
|
expectedValue = "-12:00"
|
||||||
actualValue = FormatTimezoneOffset(timezone)
|
actualValue = FormatTimezoneOffset(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", -150*60)
|
timezone = time.FixedZone("Test Timezone", -150*60)
|
||||||
expectedValue = "-02:30"
|
expectedValue = "-02:30"
|
||||||
actualValue = FormatTimezoneOffset(timezone)
|
actualValue = FormatTimezoneOffset(time.Now().Unix(), timezone)
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
timezone = time.FixedZone("Test Timezone", 0)
|
timezone = time.FixedZone("Test Timezone", 0)
|
||||||
expectedValue = "+00:00"
|
expectedValue = "+00:00"
|
||||||
actualValue = FormatTimezoneOffset(timezone)
|
actualValue = FormatTimezoneOffset(time.Now().Unix(), timezone)
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatTimezoneOffset_TimezoneWithDST(t *testing.T) {
|
||||||
|
londonLocation, err := time.LoadLocation("Europe/London")
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
|
// during standard time (UTC+0)
|
||||||
|
expectedValue := "+00:00"
|
||||||
|
actualValue := FormatTimezoneOffset(1577858483, londonLocation) // 2020-01-01 06:01:23 +00:00
|
||||||
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
|
|
||||||
|
// during daylight saving time (UTC+1)
|
||||||
|
expectedValue = "+01:00"
|
||||||
|
actualValue = FormatTimezoneOffset(1619845283, londonLocation) // 2021-05-01 06:01:23 +01:00
|
||||||
assert.Equal(t, expectedValue, actualValue)
|
assert.Equal(t, expectedValue, actualValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import type { TransactionReconciliationStatementResponseItem } from '@/models/tr
|
|||||||
import { isArray } from '@/lib/common.ts';
|
import { isArray } from '@/lib/common.ts';
|
||||||
import { sumAmounts } from '@/lib/numeral.ts';
|
import { sumAmounts } from '@/lib/numeral.ts';
|
||||||
import {
|
import {
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
getGregorianCalendarYearAndMonthFromUnixTime,
|
getGregorianCalendarYearAndMonthFromUnixTime,
|
||||||
getYearFirstUnixTimeBySpecifiedUnixTime,
|
getYearFirstUnixTimeBySpecifiedUnixTime,
|
||||||
getQuarterFirstUnixTimeBySpecifiedUnixTime,
|
getQuarterFirstUnixTimeBySpecifiedUnixTime,
|
||||||
@@ -52,11 +53,11 @@ export interface CommonAccountBalanceTrendsChartProps {
|
|||||||
|
|
||||||
export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTrendsChartProps) {
|
export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTrendsChartProps) {
|
||||||
const {
|
const {
|
||||||
formatUnixTimeToShortDate,
|
formatDateTimeToShortDate,
|
||||||
formatUnixTimeToGregorianLikeShortYear,
|
formatDateTimeToGregorianLikeShortYear,
|
||||||
formatUnixTimeToGregorianLikeShortYearMonth,
|
formatDateTimeToGregorianLikeShortYearMonth,
|
||||||
formatUnixTimeToGregorianLikeYearQuarter,
|
formatDateTimeToGregorianLikeYearQuarter,
|
||||||
formatUnixTimeToGregorianLikeFiscalYear
|
formatDateTimeToGregorianLikeFiscalYear
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const dataDateRange = computed<AccountBalanceUnixTimeAndBalanceRange | null>(() => {
|
const dataDateRange = computed<AccountBalanceUnixTimeAndBalanceRange | null>(() => {
|
||||||
@@ -150,19 +151,20 @@ export function useAccountBalanceTrendsChartBase(props: CommonAccountBalanceTren
|
|||||||
|
|
||||||
for (const dateRange of allDateRanges.value) {
|
for (const dateRange of allDateRanges.value) {
|
||||||
const dataItems = dayDataItemsMap[dateRange.minUnixTime];
|
const dataItems = dayDataItemsMap[dateRange.minUnixTime];
|
||||||
|
const minDateTime = parseDateTimeFromUnixTime(dateRange.minUnixTime);
|
||||||
|
|
||||||
let displayDate = '';
|
let displayDate = '';
|
||||||
|
|
||||||
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
||||||
displayDate = formatUnixTimeToGregorianLikeShortYear(dateRange.minUnixTime);
|
displayDate = formatDateTimeToGregorianLikeShortYear(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
||||||
displayDate = formatUnixTimeToGregorianLikeFiscalYear(dateRange.minUnixTime);
|
displayDate = formatDateTimeToGregorianLikeFiscalYear(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type) {
|
||||||
displayDate = formatUnixTimeToGregorianLikeYearQuarter(dateRange.minUnixTime);
|
displayDate = formatDateTimeToGregorianLikeYearQuarter(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||||
displayDate = formatUnixTimeToGregorianLikeShortYearMonth(dateRange.minUnixTime);
|
displayDate = formatDateTimeToGregorianLikeShortYearMonth(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type) {
|
||||||
displayDate = formatUnixTimeToShortDate(dateRange.minUnixTime);
|
displayDate = formatDateTimeToShortDate(minDateTime);
|
||||||
} else {
|
} else {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,23 @@
|
|||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
|
||||||
import { type TimeRangeAndDateType, type PresetDateRange, type UnixTimeRange, type WeekDayValue, DateRange } from '@/core/datetime.ts';
|
import {
|
||||||
|
type DateTime,
|
||||||
|
type UnixTimeRange,
|
||||||
|
type TimeRangeAndDateType,
|
||||||
|
type PresetDateRange,
|
||||||
|
type WeekDayValue,
|
||||||
|
DateRange,
|
||||||
|
} from '@/core/datetime.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getCurrentUnixTime,
|
getCurrentUnixTime,
|
||||||
getLocalDatetimeFromUnixTime,
|
getLocalDatetimeFromUnixTime,
|
||||||
getUnixTimeFromLocalDatetime,
|
getUnixTimeFromLocalDatetime,
|
||||||
getTodayFirstUnixTime,
|
getTodayFirstUnixTime,
|
||||||
getDummyUnixTimeForLocalUsage,
|
getSameDateTimeWithCurrentTimezone,
|
||||||
getActualUnixTimeForStore,
|
getSameDateTimeWithBrowserTimezone,
|
||||||
getTimezoneOffsetMinutes,
|
parseDateTimeFromUnixTime,
|
||||||
getBrowserTimezoneOffsetMinutes,
|
parseDateTimeFromUnixTimeWithBrowserTimezone,
|
||||||
getDateRangeByDateType
|
getDateRangeByDateType
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
@@ -45,23 +52,21 @@ function getDateRangeFromProps(props: CommonDateRangeSelectionProps): { minDate:
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) {
|
export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps) {
|
||||||
const { tt, formatUnixTimeToLongDateTime } = useI18n();
|
const { tt, formatDateTimeToLongDateTime } = useI18n();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const { minDate, maxDate } = getDateRangeFromProps(props);
|
const { minDate, maxDate } = getDateRangeFromProps(props);
|
||||||
|
|
||||||
const dateRange = ref<Date[]>([
|
const dateRange = ref<Date[]>([
|
||||||
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(minDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())),
|
getLocalDatetimeFromSameDateTimeOfUnixTime(minDate),
|
||||||
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(maxDate, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))
|
getLocalDatetimeFromSameDateTimeOfUnixTime(maxDate)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
||||||
const beginDateTime = computed<string>(() => {
|
const beginDateTime = computed<string>(() => {
|
||||||
const actualBeginUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[0] as Date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
|
return formatDateTimeToLongDateTime(getDateTimeFromSameDateTimeOfLocalDatetime(dateRange.value[0] as Date));
|
||||||
return formatUnixTimeToLongDateTime(actualBeginUnixTime);
|
|
||||||
});
|
});
|
||||||
const endDateTime = computed<string>(() => {
|
const endDateTime = computed<string>(() => {
|
||||||
const actualEndUnixTime = getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateRange.value[1] as Date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
|
return formatDateTimeToLongDateTime(getDateTimeFromSameDateTimeOfLocalDatetime(dateRange.value[1] as Date));
|
||||||
return formatUnixTimeToLongDateTime(actualEndUnixTime);
|
|
||||||
});
|
});
|
||||||
const presetRanges = computed<PresetDateRange[]>(() => {
|
const presetRanges = computed<PresetDateRange[]>(() => {
|
||||||
const presetRanges:PresetDateRange[] = [];
|
const presetRanges:PresetDateRange[] = [];
|
||||||
@@ -82,8 +87,8 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
|
|||||||
presetRanges.push({
|
presetRanges.push({
|
||||||
label: tt(dateRangeType.name),
|
label: tt(dateRangeType.name),
|
||||||
value: [
|
value: [
|
||||||
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(dateRange.minTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())),
|
getLocalDatetimeFromSameDateTimeOfUnixTime(dateRange.minTime),
|
||||||
getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(dateRange.maxTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()))
|
getLocalDatetimeFromSameDateTimeOfUnixTime(dateRange.maxTime)
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -91,6 +96,14 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
|
|||||||
return presetRanges;
|
return presetRanges;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getLocalDatetimeFromSameDateTimeOfUnixTime(unixTime: number): Date {
|
||||||
|
return getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(parseDateTimeFromUnixTime(unixTime)).getUnixTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDateTimeFromSameDateTimeOfLocalDatetime(localDatetime: Date): DateTime {
|
||||||
|
return getSameDateTimeWithCurrentTimezone(parseDateTimeFromUnixTimeWithBrowserTimezone(getUnixTimeFromLocalDatetime(localDatetime)));
|
||||||
|
}
|
||||||
|
|
||||||
function getFinalDateRange(): UnixTimeRange | null {
|
function getFinalDateRange(): UnixTimeRange | null {
|
||||||
if (!dateRange.value[0] || !dateRange.value[1]) {
|
if (!dateRange.value[0] || !dateRange.value[1]) {
|
||||||
return null;
|
return null;
|
||||||
@@ -99,16 +112,13 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
|
|||||||
const currentMinDate = dateRange.value[0];
|
const currentMinDate = dateRange.value[0];
|
||||||
const currentMaxDate = dateRange.value[1];
|
const currentMaxDate = dateRange.value[1];
|
||||||
|
|
||||||
let minUnixTime = getUnixTimeFromLocalDatetime(currentMinDate);
|
const minUnixTime = getDateTimeFromSameDateTimeOfLocalDatetime(currentMinDate).getUnixTime();
|
||||||
let maxUnixTime = getUnixTimeFromLocalDatetime(currentMaxDate);
|
const maxUnixTime = getDateTimeFromSameDateTimeOfLocalDatetime(currentMaxDate).getUnixTime();
|
||||||
|
|
||||||
if (minUnixTime < 0 || maxUnixTime < 0) {
|
if (minUnixTime < 0 || maxUnixTime < 0) {
|
||||||
throw new Error('Date is too early');
|
throw new Error('Date is too early');
|
||||||
}
|
}
|
||||||
|
|
||||||
minUnixTime = getActualUnixTimeForStore(minUnixTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
|
|
||||||
maxUnixTime = getActualUnixTimeForStore(maxUnixTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes());
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
minUnixTime,
|
minUnixTime,
|
||||||
maxUnixTime
|
maxUnixTime
|
||||||
@@ -123,6 +133,8 @@ export function useDateRangeSelectionBase(props: CommonDateRangeSelectionProps)
|
|||||||
endDateTime,
|
endDateTime,
|
||||||
presetRanges,
|
presetRanges,
|
||||||
// functions
|
// functions
|
||||||
|
getLocalDatetimeFromSameDateTimeOfUnixTime,
|
||||||
|
getDateTimeFromSameDateTimeOfLocalDatetime,
|
||||||
getFinalDateRange
|
getFinalDateRange
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,15 @@ import { useI18n } from '@/locales/helpers.ts';
|
|||||||
import { type NameValue } from '@/core/base.ts';
|
import { type NameValue } from '@/core/base.ts';
|
||||||
import { NumeralSystem } from '@/core/numeral.ts';
|
import { NumeralSystem } from '@/core/numeral.ts';
|
||||||
|
|
||||||
|
import {
|
||||||
|
getLocalDatetimeFromUnixTime,
|
||||||
|
getUnixTimeFromLocalDatetime,
|
||||||
|
getSameDateTimeWithBrowserTimezone,
|
||||||
|
getSameDateTimeWithTimezoneOffset,
|
||||||
|
parseDateTimeFromUnixTimeWithBrowserTimezone,
|
||||||
|
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||||
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
export interface TimePickerValue {
|
export interface TimePickerValue {
|
||||||
value: string;
|
value: string;
|
||||||
itemsIndex: number;
|
itemsIndex: number;
|
||||||
@@ -30,6 +39,14 @@ export function useDateTimeSelectionBase() {
|
|||||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||||
const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators());
|
const meridiemItems = computed<NameValue[]>(() => getAllMeridiemIndicators());
|
||||||
|
|
||||||
|
function getLocalDatetimeFromSameDateTimeOfUnixTime(unixTime: number, utcOffset: number): Date {
|
||||||
|
return getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(parseDateTimeFromUnixTimeWithTimezoneOffset(unixTime, utcOffset)).getUnixTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUnixTimeFromSameDateTimeOfLocalDatetime(localDatetime: Date, utcOffset: number): number {
|
||||||
|
return getSameDateTimeWithTimezoneOffset(parseDateTimeFromUnixTimeWithBrowserTimezone(getUnixTimeFromLocalDatetime(localDatetime)), utcOffset).getUnixTime();
|
||||||
|
}
|
||||||
|
|
||||||
function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string {
|
function getDisplayTimeValue(value: number, forceTwoDigits: boolean): string {
|
||||||
let textualValue = value.toString();
|
let textualValue = value.toString();
|
||||||
|
|
||||||
@@ -89,6 +106,8 @@ export function useDateTimeSelectionBase() {
|
|||||||
// computed
|
// computed
|
||||||
meridiemItems,
|
meridiemItems,
|
||||||
// functions
|
// functions
|
||||||
|
getLocalDatetimeFromSameDateTimeOfUnixTime,
|
||||||
|
getUnixTimeFromSameDateTimeOfLocalDatetime,
|
||||||
getDisplayTimeValue,
|
getDisplayTimeValue,
|
||||||
generateAllHours,
|
generateAllHours,
|
||||||
generateAllMinutesOrSeconds
|
generateAllMinutesOrSeconds
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
getYear0BasedMonthObjectFromString,
|
getYear0BasedMonthObjectFromString,
|
||||||
getYearMonthStringFromYear0BasedMonthObject,
|
getYearMonthStringFromYear0BasedMonthObject,
|
||||||
getCurrentUnixTime,
|
getCurrentUnixTime,
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
getThisYearFirstUnixTime,
|
getThisYearFirstUnixTime,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
getYearMonthLastUnixTime
|
getYearMonthLastUnixTime
|
||||||
@@ -49,7 +50,7 @@ function getMonthRangeFromProps(props: CommonMonthRangeSelectionProps): { minDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps) {
|
export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps) {
|
||||||
const { formatUnixTimeToGregorianLikeLongYearMonth } = useI18n();
|
const { formatDateTimeToGregorianLikeLongYearMonth } = useI18n();
|
||||||
const { minDate, maxDate } = getMonthRangeFromProps(props);
|
const { minDate, maxDate } = getMonthRangeFromProps(props);
|
||||||
|
|
||||||
const dateRange = ref<Year0BasedMonth[]>([
|
const dateRange = ref<Year0BasedMonth[]>([
|
||||||
@@ -57,8 +58,8 @@ export function useMonthRangeSelectionBase(props: CommonMonthRangeSelectionProps
|
|||||||
maxDate
|
maxDate
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const beginDateTime = computed<string>(() => formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthFirstUnixTime(dateRange.value[0] as Year0BasedMonth)));
|
const beginDateTime = computed<string>(() => formatDateTimeToGregorianLikeLongYearMonth(parseDateTimeFromUnixTime(getYearMonthFirstUnixTime(dateRange.value[0] as Year0BasedMonth))));
|
||||||
const endDateTime = computed<string>(() => formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthLastUnixTime(dateRange.value[1] as Year0BasedMonth)));
|
const endDateTime = computed<string>(() => formatDateTimeToGregorianLikeLongYearMonth(parseDateTimeFromUnixTime(getYearMonthLastUnixTime(dateRange.value[1] as Year0BasedMonth))));
|
||||||
|
|
||||||
function getFinalMonthRange(): { minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | '' } | null {
|
function getFinalMonthRange(): { minYearMonth: TextualYearMonth | '', maxYearMonth: TextualYearMonth | '' } | null {
|
||||||
if (!dateRange.value[0] || !dateRange.value[1]) {
|
if (!dateRange.value[0] || !dateRange.value[1]) {
|
||||||
|
|||||||
@@ -88,9 +88,9 @@ const {
|
|||||||
getCurrentNumeralSystemType,
|
getCurrentNumeralSystemType,
|
||||||
isLongDateMonthAfterYear,
|
isLongDateMonthAfterYear,
|
||||||
isLongTime24HourFormat,
|
isLongTime24HourFormat,
|
||||||
getCalendarDisplayShortYearFromUnixTime,
|
getCalendarDisplayShortYearFromDateTime,
|
||||||
getCalendarDisplayShortMonthFromUnixTime,
|
getCalendarDisplayShortMonthFromDateTime,
|
||||||
getCalendarDisplayDayOfMonthFromUnixTime,
|
getCalendarDisplayDayOfMonthFromDateTime,
|
||||||
getCalendarAlternateDate
|
getCalendarAlternateDate
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -138,21 +138,21 @@ function switchView(viewType: MenuView): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayYear(year: number): string {
|
function getDisplayYear(year: number): string {
|
||||||
return getCalendarDisplayShortYearFromUnixTime(getYearMonthDayDateTime(year, 1, 1).getUnixTime(), actualNumeralSystem.value);
|
return getCalendarDisplayShortYearFromDateTime(getYearMonthDayDateTime(year, 1, 1), actualNumeralSystem.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayMonth(month: number): string {
|
function getDisplayMonth(month: number): string {
|
||||||
if (isArray(dateTime.value)) {
|
if (isArray(dateTime.value)) {
|
||||||
return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0]!.getFullYear(), month + 1, 1).getUnixTime(), actualNumeralSystem.value);
|
return getCalendarDisplayShortMonthFromDateTime(getYearMonthDayDateTime(dateTime.value[0]!.getFullYear(), month + 1, 1), actualNumeralSystem.value);
|
||||||
} else if (dateTime.value) {
|
} else if (dateTime.value) {
|
||||||
return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value.getFullYear(), month + 1, 1).getUnixTime(), actualNumeralSystem.value);
|
return getCalendarDisplayShortMonthFromDateTime(getYearMonthDayDateTime(dateTime.value.getFullYear(), month + 1, 1), actualNumeralSystem.value);
|
||||||
} else {
|
} else {
|
||||||
return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(new Date().getFullYear(), month + 1, 1).getUnixTime(), actualNumeralSystem.value);
|
return getCalendarDisplayShortMonthFromDateTime(getYearMonthDayDateTime(new Date().getFullYear(), month + 1, 1), actualNumeralSystem.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayDay(date: Date): string {
|
function getDisplayDay(date: Date): string {
|
||||||
return getCalendarDisplayDayOfMonthFromUnixTime(getYearMonthDayDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate()).getUnixTime(), actualNumeralSystem.value);
|
return getCalendarDisplayDayOfMonthFromDateTime(getYearMonthDayDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate()), actualNumeralSystem.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
isLongDateMonthAfterYear,
|
isLongDateMonthAfterYear,
|
||||||
getCalendarDisplayShortYearFromUnixTime,
|
getCalendarDisplayShortYearFromDateTime,
|
||||||
getCalendarDisplayShortMonthFromUnixTime
|
getCalendarDisplayShortMonthFromDateTime
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const yearRange = getAllowedYearRange();
|
const yearRange = getAllowedYearRange();
|
||||||
@@ -96,14 +96,14 @@ function getYear0BasedMonthFromMonthSelectionValue(value: MonthSelectionValue):
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayYear(year: number): string {
|
function getDisplayYear(year: number): string {
|
||||||
return getCalendarDisplayShortYearFromUnixTime(getYearMonthDayDateTime(year, 1, 1).getUnixTime());
|
return getCalendarDisplayShortYearFromDateTime(getYearMonthDayDateTime(year, 1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayMonth(month: number): string {
|
function getDisplayMonth(month: number): string {
|
||||||
if (isArray(dateTime.value)) {
|
if (isArray(dateTime.value)) {
|
||||||
return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value[0]!.year, month + 1, 1).getUnixTime());
|
return getCalendarDisplayShortMonthFromDateTime(getYearMonthDayDateTime(dateTime.value[0]!.year, month + 1, 1));
|
||||||
} else {
|
} else {
|
||||||
return getCalendarDisplayShortMonthFromUnixTime(getYearMonthDayDateTime(dateTime.value.year, month + 1, 1).getUnixTime());
|
return getCalendarDisplayShortMonthFromDateTime(getYearMonthDayDateTime(dateTime.value.year, month + 1, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -38,14 +38,7 @@ import type { CalendarAlternateDate, TextualYearMonthDay, WeekDayValue } from '@
|
|||||||
import { INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
import { INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numeral.ts';
|
||||||
|
|
||||||
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
|
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
|
||||||
import {
|
import { getYearMonthDayDateTime } from '@/lib/datetime.ts';
|
||||||
getTimezoneOffsetMinutes,
|
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getUnixTimeFromLocalDatetime,
|
|
||||||
getActualUnixTimeForStore,
|
|
||||||
getYearMonthDayDateTime,
|
|
||||||
parseDateTimeFromUnixTime
|
|
||||||
} from '@/lib/datetime.ts';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: TextualYearMonthDay | '';
|
modelValue: TextualYearMonthDay | '';
|
||||||
@@ -67,7 +60,7 @@ const emit = defineEmits<{
|
|||||||
const {
|
const {
|
||||||
getAllLongWeekdayNames,
|
getAllLongWeekdayNames,
|
||||||
getAllShortWeekdayNames,
|
getAllShortWeekdayNames,
|
||||||
getCalendarDisplayDayOfMonthFromUnixTime,
|
getCalendarDisplayDayOfMonthFromDateTime,
|
||||||
getCalendarAlternateDates,
|
getCalendarAlternateDates,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
@@ -105,8 +98,7 @@ const alternateDates = computed<Record<TextualYearMonthDay, string> | undefined>
|
|||||||
});
|
});
|
||||||
|
|
||||||
function noTransactionInMonthDay(date: Date): boolean {
|
function noTransactionInMonthDay(date: Date): boolean {
|
||||||
const dateTime = parseDateTimeFromUnixTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(date), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
return !props.dailyTotalAmounts || !props.dailyTotalAmounts[date.getDate()];
|
||||||
return !props.dailyTotalAmounts || !props.dailyTotalAmounts[dateTime.getGregorianCalendarDay()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayMonthTotalAmount(amount: number, currency: string | false, symbol: string, incomplete: boolean): string {
|
function getDisplayMonthTotalAmount(amount: number, currency: string | false, symbol: string, incomplete: boolean): string {
|
||||||
@@ -115,7 +107,7 @@ function getDisplayMonthTotalAmount(amount: number, currency: string | false, sy
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayDay(date: Date): string {
|
function getDisplayDay(date: Date): string {
|
||||||
return getCalendarDisplayDayOfMonthFromUnixTime(getYearMonthDayDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate()).getUnixTime());
|
return getCalendarDisplayDayOfMonthFromDateTime(getYearMonthDayDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate()));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -43,13 +43,6 @@ import { type CommonDateRangeSelectionProps, useDateRangeSelectionBase } from '@
|
|||||||
|
|
||||||
import { ThemeType } from '@/core/theme.ts';
|
import { ThemeType } from '@/core/theme.ts';
|
||||||
|
|
||||||
import {
|
|
||||||
getLocalDatetimeFromUnixTime,
|
|
||||||
getDummyUnixTimeForLocalUsage,
|
|
||||||
getTimezoneOffsetMinutes,
|
|
||||||
getBrowserTimezoneOffsetMinutes
|
|
||||||
} from '@/lib/datetime.ts';
|
|
||||||
|
|
||||||
interface DesktopDateRangeSelectionProps extends CommonDateRangeSelectionProps {
|
interface DesktopDateRangeSelectionProps extends CommonDateRangeSelectionProps {
|
||||||
persistent?: boolean;
|
persistent?: boolean;
|
||||||
}
|
}
|
||||||
@@ -64,7 +57,14 @@ const emit = defineEmits<{
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const { tt } = useI18n();
|
const { tt } = useI18n();
|
||||||
const { dateRange, beginDateTime, endDateTime, presetRanges, getFinalDateRange } = useDateRangeSelectionBase(props);
|
const {
|
||||||
|
dateRange,
|
||||||
|
beginDateTime,
|
||||||
|
endDateTime,
|
||||||
|
presetRanges,
|
||||||
|
getLocalDatetimeFromSameDateTimeOfUnixTime,
|
||||||
|
getFinalDateRange
|
||||||
|
} = useDateRangeSelectionBase(props);
|
||||||
|
|
||||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||||
const showState = computed<boolean>({
|
const showState = computed<boolean>({
|
||||||
@@ -94,13 +94,13 @@ function cancel(): void {
|
|||||||
|
|
||||||
watch(() => props.minTime, (newValue) => {
|
watch(() => props.minTime, (newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
dateRange.value[0] = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(newValue, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateRange.value[0] = getLocalDatetimeFromSameDateTimeOfUnixTime(newValue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.maxTime, (newValue) => {
|
watch(() => props.maxTime, (newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
dateRange.value[1] = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(newValue, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateRange.value[1] = getLocalDatetimeFromSameDateTimeOfUnixTime(newValue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -94,12 +94,9 @@ import {
|
|||||||
} from '@/core/datetime.ts';
|
} from '@/core/datetime.ts';
|
||||||
import {
|
import {
|
||||||
getHourIn12HourFormat,
|
getHourIn12HourFormat,
|
||||||
getTimezoneOffsetMinutes,
|
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getLocalDatetimeFromUnixTime,
|
getLocalDatetimeFromUnixTime,
|
||||||
getUnixTimeFromLocalDatetime,
|
getSameDateTimeWithBrowserTimezone,
|
||||||
getActualUnixTimeForStore,
|
parseDateTimeFromUnixTimeWithTimezoneOffset,
|
||||||
getDummyUnixTimeForLocalUsage,
|
|
||||||
parseDateTimeFromKnownDateTimeFormat,
|
parseDateTimeFromKnownDateTimeFormat,
|
||||||
getAMOrPM,
|
getAMOrPM,
|
||||||
getCombinedDateAndTimeValues
|
getCombinedDateAndTimeValues
|
||||||
@@ -108,6 +105,7 @@ import { setChildInputFocus } from '@/lib/ui/desktop.ts';
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: number;
|
modelValue: number;
|
||||||
|
timezoneUtcOffset: number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
label?: string;
|
label?: string;
|
||||||
@@ -124,7 +122,7 @@ const {
|
|||||||
getCurrentNumeralSystemType,
|
getCurrentNumeralSystemType,
|
||||||
parseDateTimeFromLongDateTime,
|
parseDateTimeFromLongDateTime,
|
||||||
parseDateTimeFromShortDateTime,
|
parseDateTimeFromShortDateTime,
|
||||||
formatUnixTimeToLongDateTime
|
formatDateTimeToLongDateTime
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -133,6 +131,8 @@ const {
|
|||||||
isMinuteTwoDigits,
|
isMinuteTwoDigits,
|
||||||
isSecondTwoDigits,
|
isSecondTwoDigits,
|
||||||
isMeridiemIndicatorFirst,
|
isMeridiemIndicatorFirst,
|
||||||
|
getLocalDatetimeFromSameDateTimeOfUnixTime,
|
||||||
|
getUnixTimeFromSameDateTimeOfLocalDatetime,
|
||||||
getDisplayTimeValue,
|
getDisplayTimeValue,
|
||||||
generateAllHours,
|
generateAllHours,
|
||||||
generateAllMinutesOrSeconds
|
generateAllMinutesOrSeconds
|
||||||
@@ -147,10 +147,10 @@ const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType(
|
|||||||
|
|
||||||
const dateTime = computed<Date>({
|
const dateTime = computed<Date>({
|
||||||
get: () => {
|
get: () => {
|
||||||
return getLocalDatetimeFromUnixTime(props.modelValue);
|
return getLocalDatetimeFromSameDateTimeOfUnixTime(props.modelValue, props.timezoneUtcOffset);
|
||||||
},
|
},
|
||||||
set: (value: Date) => {
|
set: (value: Date) => {
|
||||||
const unixTime = getUnixTimeFromLocalDatetime(value);
|
const unixTime = getUnixTimeFromSameDateTimeOfLocalDatetime(value, props.timezoneUtcOffset);
|
||||||
|
|
||||||
if (unixTime < 0) {
|
if (unixTime < 0) {
|
||||||
emit('error', 'Date is too early');
|
emit('error', 'Date is too early');
|
||||||
@@ -161,7 +161,7 @@ const dateTime = computed<Date>({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayTime = computed<string>(() => formatUnixTimeToLongDateTime(getActualUnixTimeForStore(getUnixTimeFromLocalDatetime(dateTime.value), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
|
const displayTime = computed<string>(() => formatDateTimeToLongDateTime(parseDateTimeFromUnixTimeWithTimezoneOffset(props.modelValue, props.timezoneUtcOffset)));
|
||||||
|
|
||||||
const hourItems = computed<TimePickerValue[]>(() => generateAllHours(1, isHourTwoDigits.value));
|
const hourItems = computed<TimePickerValue[]>(() => generateAllHours(1, isHourTwoDigits.value));
|
||||||
const minuteItems = computed<TimePickerValue[]>(() => generateAllMinutesOrSeconds(1, isMinuteTwoDigits.value));
|
const minuteItems = computed<TimePickerValue[]>(() => generateAllMinutesOrSeconds(1, isMinuteTwoDigits.value));
|
||||||
@@ -252,7 +252,7 @@ function onPaste(event: ClipboardEvent): void {
|
|||||||
dt = parseDateTimeFromKnownDateTimeFormat(text, formats[0] as KnownDateTimeFormat);
|
dt = parseDateTimeFromKnownDateTimeFormat(text, formats[0] as KnownDateTimeFormat);
|
||||||
|
|
||||||
if (dt) {
|
if (dt) {
|
||||||
dateTime.value = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(dt.getUnixTime(), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateTime.value = getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(dt).getUnixTime());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,14 +260,14 @@ function onPaste(event: ClipboardEvent): void {
|
|||||||
dt = parseDateTimeFromLongDateTime(text);
|
dt = parseDateTimeFromLongDateTime(text);
|
||||||
|
|
||||||
if (dt) {
|
if (dt) {
|
||||||
dateTime.value = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(dt.getUnixTime(), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateTime.value = getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(dt).getUnixTime());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dt = parseDateTimeFromShortDateTime(text);
|
dt = parseDateTimeFromShortDateTime(text);
|
||||||
|
|
||||||
if (dt) {
|
if (dt) {
|
||||||
dateTime.value = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(dt.getUnixTime(), getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateTime.value = getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(dt).getUnixTime());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import {
|
|||||||
isNumber
|
isNumber
|
||||||
} from '@/lib/common.ts';
|
} from '@/lib/common.ts';
|
||||||
import {
|
import {
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
getYearMonthLastUnixTime,
|
getYearMonthLastUnixTime,
|
||||||
getDateTypeByDateRange,
|
getDateTypeByDateRange,
|
||||||
@@ -95,11 +96,11 @@ const theme = useTheme();
|
|||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
getCurrentLanguageTextDirection,
|
getCurrentLanguageTextDirection,
|
||||||
formatUnixTimeToShortDate,
|
formatDateTimeToShortDate,
|
||||||
formatUnixTimeToGregorianLikeShortYear,
|
formatDateTimeToGregorianLikeShortYear,
|
||||||
formatUnixTimeToGregorianLikeShortYearMonth,
|
formatDateTimeToGregorianLikeShortYearMonth,
|
||||||
formatYearQuarterToGregorianLikeYearQuarter,
|
formatYearQuarterToGregorianLikeYearQuarter,
|
||||||
formatUnixTimeToGregorianLikeFiscalYear,
|
formatDateTimeToGregorianLikeFiscalYear,
|
||||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
@@ -151,16 +152,18 @@ const allDisplayDateRanges = computed<string[]>(() => {
|
|||||||
const allDisplayDateRanges: string[] = [];
|
const allDisplayDateRanges: string[] = [];
|
||||||
|
|
||||||
for (const dateRange of allDateRanges.value) {
|
for (const dateRange of allDateRanges.value) {
|
||||||
|
const minDateTime = parseDateTimeFromUnixTime(dateRange.minUnixTime);
|
||||||
|
|
||||||
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
||||||
allDisplayDateRanges.push(formatUnixTimeToGregorianLikeShortYear(dateRange.minUnixTime));
|
allDisplayDateRanges.push(formatDateTimeToGregorianLikeShortYear(minDateTime));
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type && 'year' in dateRange) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type && 'year' in dateRange) {
|
||||||
allDisplayDateRanges.push(formatUnixTimeToGregorianLikeFiscalYear(dateRange.minUnixTime));
|
allDisplayDateRanges.push(formatDateTimeToGregorianLikeFiscalYear(minDateTime));
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type && 'quarter' in dateRange) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type && 'quarter' in dateRange) {
|
||||||
allDisplayDateRanges.push(formatYearQuarterToGregorianLikeYearQuarter(dateRange.year, dateRange.quarter));
|
allDisplayDateRanges.push(formatYearQuarterToGregorianLikeYearQuarter(dateRange.year, dateRange.quarter));
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||||
allDisplayDateRanges.push(formatUnixTimeToGregorianLikeShortYearMonth(dateRange.minUnixTime));
|
allDisplayDateRanges.push(formatDateTimeToGregorianLikeShortYearMonth(minDateTime));
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type && props.chartMode === 'daily') {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type && props.chartMode === 'daily') {
|
||||||
allDisplayDateRanges.push(formatUnixTimeToShortDate(dateRange.minUnixTime));
|
allDisplayDateRanges.push(formatDateTimeToShortDate(minDateTime));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,13 +45,6 @@ import { type CommonDateRangeSelectionProps, useDateRangeSelectionBase } from '@
|
|||||||
|
|
||||||
import { useEnvironmentsStore } from '@/stores/environment.ts';
|
import { useEnvironmentsStore } from '@/stores/environment.ts';
|
||||||
|
|
||||||
import {
|
|
||||||
getLocalDatetimeFromUnixTime,
|
|
||||||
getDummyUnixTimeForLocalUsage,
|
|
||||||
getTimezoneOffsetMinutes,
|
|
||||||
getBrowserTimezoneOffsetMinutes
|
|
||||||
} from '@/lib/datetime.ts';
|
|
||||||
|
|
||||||
type DateTimePickerType = InstanceType<typeof DateTimePicker>;
|
type DateTimePickerType = InstanceType<typeof DateTimePicker>;
|
||||||
|
|
||||||
const props = defineProps<CommonDateRangeSelectionProps>();
|
const props = defineProps<CommonDateRangeSelectionProps>();
|
||||||
@@ -62,7 +55,14 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const { tt } = useI18n();
|
const { tt } = useI18n();
|
||||||
const { showToast } = useI18nUIComponents();
|
const { showToast } = useI18nUIComponents();
|
||||||
const { dateRange, beginDateTime, endDateTime, presetRanges, getFinalDateRange } = useDateRangeSelectionBase(props);
|
const {
|
||||||
|
dateRange,
|
||||||
|
beginDateTime,
|
||||||
|
endDateTime,
|
||||||
|
presetRanges,
|
||||||
|
getLocalDatetimeFromSameDateTimeOfUnixTime,
|
||||||
|
getFinalDateRange
|
||||||
|
} = useDateRangeSelectionBase(props);
|
||||||
|
|
||||||
const environmentsStore = useEnvironmentsStore();
|
const environmentsStore = useEnvironmentsStore();
|
||||||
|
|
||||||
@@ -91,11 +91,11 @@ function cancel(): void {
|
|||||||
|
|
||||||
function onSheetOpen(): void {
|
function onSheetOpen(): void {
|
||||||
if (props.minTime) {
|
if (props.minTime) {
|
||||||
dateRange.value[0] = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(props.minTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateRange.value[0] = getLocalDatetimeFromSameDateTimeOfUnixTime(props.minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.maxTime) {
|
if (props.maxTime) {
|
||||||
dateRange.value[1] = getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(props.maxTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
dateRange.value[1] = getLocalDatetimeFromSameDateTimeOfUnixTime(props.maxTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.dispatchEvent(new Event('resize')); // fix vue-datepicker preset max-width
|
window.dispatchEvent(new Event('resize')); // fix vue-datepicker preset max-width
|
||||||
|
|||||||
@@ -111,9 +111,7 @@ import { NumeralSystem } from '@/core/numeral.ts';
|
|||||||
import { isDefined } from '@/lib/common.ts';
|
import { isDefined } from '@/lib/common.ts';
|
||||||
import {
|
import {
|
||||||
getHourIn12HourFormat,
|
getHourIn12HourFormat,
|
||||||
getLocalDatetimeFromUnixTime,
|
|
||||||
getCurrentUnixTime,
|
getCurrentUnixTime,
|
||||||
getUnixTimeFromLocalDatetime,
|
|
||||||
getAMOrPM,
|
getAMOrPM,
|
||||||
getCombinedDateAndTimeValues
|
getCombinedDateAndTimeValues
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
@@ -122,6 +120,7 @@ type DateTimePickerType = InstanceType<typeof DateTimePicker>;
|
|||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: number;
|
modelValue: number;
|
||||||
|
timezoneUtcOffset: number;
|
||||||
initMode?: string;
|
initMode?: string;
|
||||||
show: boolean;
|
show: boolean;
|
||||||
}>();
|
}>();
|
||||||
@@ -144,6 +143,8 @@ const {
|
|||||||
isSecondTwoDigits,
|
isSecondTwoDigits,
|
||||||
isMeridiemIndicatorFirst,
|
isMeridiemIndicatorFirst,
|
||||||
meridiemItems,
|
meridiemItems,
|
||||||
|
getLocalDatetimeFromSameDateTimeOfUnixTime,
|
||||||
|
getUnixTimeFromSameDateTimeOfLocalDatetime,
|
||||||
getDisplayTimeValue,
|
getDisplayTimeValue,
|
||||||
generateAllHours,
|
generateAllHours,
|
||||||
generateAllMinutesOrSeconds
|
generateAllMinutesOrSeconds
|
||||||
@@ -160,7 +161,7 @@ let resetTimePickerItemPositionItemsLastOffsetTop: number | undefined = undefine
|
|||||||
let resetTimePickerItemPositionCheckedFrames: number | undefined = undefined;
|
let resetTimePickerItemPositionCheckedFrames: number | undefined = undefined;
|
||||||
|
|
||||||
const mode = ref<string>(props.initMode || 'time');
|
const mode = ref<string>(props.initMode || 'time');
|
||||||
const dateTime = ref<Date>(getLocalDatetimeFromUnixTime(props.modelValue || getCurrentUnixTime()));
|
const dateTime = ref<Date>(getLocalDatetimeFromSameDateTimeOfUnixTime(props.modelValue || getCurrentUnixTime(), props.timezoneUtcOffset));
|
||||||
const timePickerContainerHeight = ref<number | undefined>(undefined);
|
const timePickerContainerHeight = ref<number | undefined>(undefined);
|
||||||
const timePickerItemHeight = ref<number | undefined>(undefined);
|
const timePickerItemHeight = ref<number | undefined>(undefined);
|
||||||
|
|
||||||
@@ -213,7 +214,7 @@ function switchMode(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setCurrentTime(): void {
|
function setCurrentTime(): void {
|
||||||
dateTime.value = getLocalDatetimeFromUnixTime(getCurrentUnixTime());
|
dateTime.value = getLocalDatetimeFromSameDateTimeOfUnixTime(getCurrentUnixTime(), props.timezoneUtcOffset);
|
||||||
|
|
||||||
if (mode.value === 'time') {
|
if (mode.value === 'time') {
|
||||||
scrollAllTimeSelectedItems();
|
scrollAllTimeSelectedItems();
|
||||||
@@ -225,7 +226,7 @@ function confirm(): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unixTime = getUnixTimeFromLocalDatetime(dateTime.value);
|
const unixTime = getUnixTimeFromSameDateTimeOfLocalDatetime(dateTime.value, props.timezoneUtcOffset);
|
||||||
|
|
||||||
if (unixTime < 0) {
|
if (unixTime < 0) {
|
||||||
showToast('Date is too early');
|
showToast('Date is too early');
|
||||||
@@ -420,7 +421,7 @@ function onSheetOpen(): void {
|
|||||||
mode.value = props.initMode || 'time';
|
mode.value = props.initMode || 'time';
|
||||||
|
|
||||||
if (props.modelValue) {
|
if (props.modelValue) {
|
||||||
dateTime.value = getLocalDatetimeFromUnixTime(props.modelValue);
|
dateTime.value = getLocalDatetimeFromSameDateTimeOfUnixTime(props.modelValue, props.timezoneUtcOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode.value === 'time') {
|
if (mode.value === 'time') {
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ import {
|
|||||||
isNumber
|
isNumber
|
||||||
} from '@/lib/common.ts';
|
} from '@/lib/common.ts';
|
||||||
import {
|
import {
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
getYearMonthLastUnixTime,
|
getYearMonthLastUnixTime,
|
||||||
getDateTypeByDateRange,
|
getDateTypeByDateRange,
|
||||||
@@ -200,11 +201,11 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
formatUnixTimeToShortDate,
|
formatDateTimeToShortDate,
|
||||||
formatUnixTimeToGregorianLikeShortYear,
|
formatDateTimeToGregorianLikeShortYear,
|
||||||
formatUnixTimeToGregorianLikeShortYearMonth,
|
formatDateTimeToGregorianLikeShortYearMonth,
|
||||||
formatYearQuarterToGregorianLikeYearQuarter,
|
formatYearQuarterToGregorianLikeYearQuarter,
|
||||||
formatUnixTimeToGregorianLikeFiscalYear,
|
formatDateTimeToGregorianLikeFiscalYear,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -324,18 +325,19 @@ const allDisplayDataItems = computed<TrendsBarChartData>(() => {
|
|||||||
dateRangeKey = `${dateRange.year}-${dateRange.month}-${dateRange.day}`;
|
dateRangeKey = `${dateRange.year}-${dateRange.month}-${dateRange.day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const minDateTime = parseDateTimeFromUnixTime(dateRange.minUnixTime);
|
||||||
let displayDateRange = '';
|
let displayDateRange = '';
|
||||||
|
|
||||||
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
if (props.dateAggregationType === ChartDateAggregationType.Year.type) {
|
||||||
displayDateRange = formatUnixTimeToGregorianLikeShortYear(dateRange.minUnixTime);
|
displayDateRange = formatDateTimeToGregorianLikeShortYear(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.FiscalYear.type) {
|
||||||
displayDateRange = formatUnixTimeToGregorianLikeFiscalYear(dateRange.minUnixTime);
|
displayDateRange = formatDateTimeToGregorianLikeFiscalYear(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type && 'quarter' in dateRange) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Quarter.type && 'quarter' in dateRange) {
|
||||||
displayDateRange = formatYearQuarterToGregorianLikeYearQuarter(dateRange.year, dateRange.quarter);
|
displayDateRange = formatYearQuarterToGregorianLikeYearQuarter(dateRange.year, dateRange.quarter);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Month.type) {
|
||||||
displayDateRange = formatUnixTimeToGregorianLikeShortYearMonth(dateRange.minUnixTime);
|
displayDateRange = formatDateTimeToGregorianLikeShortYearMonth(minDateTime);
|
||||||
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type && props.chartMode === 'daily') {
|
} else if (props.dateAggregationType === ChartDateAggregationType.Day.type && props.chartMode === 'daily') {
|
||||||
displayDateRange = formatUnixTimeToShortDate(dateRange.minUnixTime);
|
displayDateRange = formatDateTimeToShortDate(minDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataItems = allDateRangeItemsMap[dateRangeKey] || [];
|
const dataItems = allDateRangeItemsMap[dateRangeKey] || [];
|
||||||
|
|||||||
+90
-27
@@ -69,7 +69,31 @@ interface DateTimeFormatResult {
|
|||||||
hasNumeral?: boolean;
|
hasNumeral?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type DateTimeTokenFormatFunction = (d: MomentDateTime, options: DateTimeFormatOptions) => DateTimeFormatResult
|
type DateTimeTokenFormatFunction = (d: MomentDateTime, options: DateTimeFormatOptions) => DateTimeFormatResult;
|
||||||
|
|
||||||
|
const westernmostTimezoneUtcOffset: number = -720; // Etc/GMT+12 (UTC-12:00)
|
||||||
|
const easternmostTimezoneUtcOffset: number = 840; // Pacific/Kiritimati (UTC+14:00)
|
||||||
|
|
||||||
|
function getFixedTimezoneName(utcOffset: number): string {
|
||||||
|
return `Fixed/Timezone${utcOffset}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
(function initFixedTimezone(): void {
|
||||||
|
for (let utcOffset = westernmostTimezoneUtcOffset; utcOffset <= easternmostTimezoneUtcOffset; utcOffset += 15) {
|
||||||
|
const timezoneName = getFixedTimezoneName(utcOffset);
|
||||||
|
|
||||||
|
if (moment.tz.zone(timezoneName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
moment.tz.add(moment.tz.pack({
|
||||||
|
name: timezoneName,
|
||||||
|
abbrs: [`FIX${utcOffset}`],
|
||||||
|
offsets: [-utcOffset],
|
||||||
|
untils: [0]
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
class MomentDateTime implements DateTime {
|
class MomentDateTime implements DateTime {
|
||||||
private static readonly tokenFormatFuncs: Record<string, DateTimeTokenFormatFunction> = {
|
private static readonly tokenFormatFuncs: Record<string, DateTimeTokenFormatFunction> = {
|
||||||
@@ -501,28 +525,29 @@ export function getUtcOffsetByUtcOffsetMinutes(utcOffsetMinutes: number): string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTimezoneOffset(timezone?: string): string {
|
export function getTimezoneOffset(unixTime: number, timezone?: string): string {
|
||||||
return getUtcOffsetByUtcOffsetMinutes(getTimezoneOffsetMinutes(timezone));
|
return getUtcOffsetByUtcOffsetMinutes(getTimezoneOffsetMinutes(unixTime, timezone));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTimezoneOffsetMinutes(timezone?: string): number {
|
export function getTimezoneOffsetMinutes(unixTime: number, timezone?: string): number {
|
||||||
if (timezone) {
|
if (timezone) {
|
||||||
return moment().tz(timezone).utcOffset();
|
return moment.unix(unixTime).tz(timezone).utcOffset();
|
||||||
} else {
|
} else {
|
||||||
return moment().utcOffset();
|
return moment.unix(unixTime).utcOffset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBrowserTimezoneOffset(): string {
|
export function getBrowserTimezoneOffset(unixTime: number): string {
|
||||||
return getUtcOffsetByUtcOffsetMinutes(getBrowserTimezoneOffsetMinutes());
|
return getUtcOffsetByUtcOffsetMinutes(getBrowserTimezoneOffsetMinutes(unixTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBrowserTimezoneOffsetMinutes(): number {
|
export function getBrowserTimezoneOffsetMinutes(unixTime: number): number {
|
||||||
return -new Date().getTimezoneOffset();
|
const date = getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(parseDateTimeFromUnixTime(unixTime)).getUnixTime());
|
||||||
|
return -date.getTimezoneOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function guessTimezoneName(): string {
|
export function getBrowserTimezoneName(): string {
|
||||||
return moment.tz.guess(true);
|
return new Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocalDatetimeFromUnixTime(unixTime: number): Date {
|
export function getLocalDatetimeFromUnixTime(unixTime: number): Date {
|
||||||
@@ -533,12 +558,46 @@ export function getUnixTimeFromLocalDatetime(datetime: Date): number {
|
|||||||
return Math.floor(datetime.getTime() / 1000);
|
return Math.floor(datetime.getTime() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getActualUnixTimeForStore(unixTime: number, utcOffset: number, currentUtcOffset: number): number {
|
export function getSameDateTimeWithCurrentTimezone(dateTime: DateTime): DateTime {
|
||||||
return unixTime - (utcOffset - currentUtcOffset) * 60;
|
const newDateTime = moment().set({
|
||||||
|
year: dateTime.getGregorianCalendarYear(),
|
||||||
|
month: dateTime.getGregorianCalendarMonth() - 1,
|
||||||
|
date: dateTime.getGregorianCalendarDay(),
|
||||||
|
hour: dateTime.getHour(),
|
||||||
|
minute: dateTime.getMinute(),
|
||||||
|
second: dateTime.getSecond(),
|
||||||
|
millisecond: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
return MomentDateTime.of(newDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDummyUnixTimeForLocalUsage(unixTime: number, utcOffset: number, currentUtcOffset: number): number {
|
export function getSameDateTimeWithBrowserTimezone(dateTime: DateTime): DateTime {
|
||||||
return unixTime + (utcOffset - currentUtcOffset) * 60;
|
const newDateTime = moment().tz(getBrowserTimezoneName()).set({
|
||||||
|
year: dateTime.getGregorianCalendarYear(),
|
||||||
|
month: dateTime.getGregorianCalendarMonth() - 1,
|
||||||
|
date: dateTime.getGregorianCalendarDay(),
|
||||||
|
hour: dateTime.getHour(),
|
||||||
|
minute: dateTime.getMinute(),
|
||||||
|
second: dateTime.getSecond(),
|
||||||
|
millisecond: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return MomentDateTime.of(newDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSameDateTimeWithTimezoneOffset(dateTime: DateTime, utcOffset: number): DateTime {
|
||||||
|
const newDateTime = moment().tz(getFixedTimezoneName(utcOffset)).set({
|
||||||
|
year: dateTime.getGregorianCalendarYear(),
|
||||||
|
month: dateTime.getGregorianCalendarMonth() - 1,
|
||||||
|
date: dateTime.getGregorianCalendarDay(),
|
||||||
|
hour: dateTime.getHour(),
|
||||||
|
minute: dateTime.getMinute(),
|
||||||
|
second: dateTime.getSecond(),
|
||||||
|
millisecond: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
return MomentDateTime.of(newDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentDateTime(): DateTime {
|
export function getCurrentDateTime(): DateTime {
|
||||||
@@ -554,18 +613,18 @@ export function getYearMonthDayDateTime(year: number, month: number, day: number
|
|||||||
return MomentDateTime.of(date);
|
return MomentDateTime.of(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseDateTimeFromUnixTime(unixTime: number, utcOffset?: number, currentUtcOffset?: number): DateTime {
|
export function parseDateTimeFromUnixTime(unixTime: number): DateTime {
|
||||||
if (isNumber(utcOffset)) {
|
|
||||||
if (!isNumber(currentUtcOffset)) {
|
|
||||||
currentUtcOffset = getTimezoneOffsetMinutes();
|
|
||||||
}
|
|
||||||
|
|
||||||
unixTime = getDummyUnixTimeForLocalUsage(unixTime, utcOffset, currentUtcOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return MomentDateTime.of(moment.unix(unixTime));
|
return MomentDateTime.of(moment.unix(unixTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function parseDateTimeFromUnixTimeWithBrowserTimezone(unixTime: number): DateTime {
|
||||||
|
return MomentDateTime.of(moment.unix(unixTime).tz(getBrowserTimezoneName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseDateTimeFromUnixTimeWithTimezoneOffset(unixTime: number, utcOffset: number): DateTime {
|
||||||
|
return MomentDateTime.of(moment.unix(unixTime).tz(getFixedTimezoneName(utcOffset)));
|
||||||
|
}
|
||||||
|
|
||||||
export function parseDateTimeFromKnownDateTimeFormat(dateTime: string, format: KnownDateTimeFormat): DateTime | undefined {
|
export function parseDateTimeFromKnownDateTimeFormat(dateTime: string, format: KnownDateTimeFormat): DateTime | undefined {
|
||||||
const m = moment(dateTime, format.format);
|
const m = moment(dateTime, format.format);
|
||||||
|
|
||||||
@@ -586,8 +645,12 @@ export function parseDateTimeFromString(dateTime: string, format: string): DateT
|
|||||||
return MomentDateTime.of(m);
|
return MomentDateTime.of(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatUnixTime(unixTime: number, format: string, options: DateTimeFormatOptions, utcOffset?: number, currentUtcOffset?: number): string {
|
export function formatDateTime(dateTime: DateTime, format: string, options: DateTimeFormatOptions): string {
|
||||||
return parseDateTimeFromUnixTime(unixTime, utcOffset, currentUtcOffset).format(format, options);
|
return dateTime.format(format, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatUnixTime(unixTime: number, format: string, options: DateTimeFormatOptions): string {
|
||||||
|
return parseDateTimeFromUnixTime(unixTime).format(format, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function formatCurrentTime(format: string, options: DateTimeFormatOptions): string {
|
export function formatCurrentTime(format: string, options: DateTimeFormatOptions): string {
|
||||||
|
|||||||
+4
-3
@@ -178,7 +178,8 @@ import {
|
|||||||
} from './server_settings.ts';
|
} from './server_settings.ts';
|
||||||
import {
|
import {
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
guessTimezoneName
|
getBrowserTimezoneName,
|
||||||
|
getCurrentUnixTime
|
||||||
} from './datetime.ts';
|
} from './datetime.ts';
|
||||||
import { generateRandomUUID } from './misc.ts';
|
import { generateRandomUUID } from './misc.ts';
|
||||||
import { getBasePath } from './web.ts';
|
import { getBasePath } from './web.ts';
|
||||||
@@ -208,12 +209,12 @@ axios.interceptors.request.use((config: ApiRequestConfig) => {
|
|||||||
config.headers.Authorization = `Bearer ${token}`;
|
config.headers.Authorization = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.headers['X-Timezone-Offset'] = getTimezoneOffsetMinutes();
|
config.headers['X-Timezone-Offset'] = getTimezoneOffsetMinutes(getCurrentUnixTime());
|
||||||
|
|
||||||
let timezoneName = getTimeZone();
|
let timezoneName = getTimeZone();
|
||||||
|
|
||||||
if (!timezoneName || timezoneName.trim().length < 1) {
|
if (!timezoneName || timezoneName.trim().length < 1) {
|
||||||
timezoneName = guessTimezoneName();
|
timezoneName = getBrowserTimezoneName();
|
||||||
}
|
}
|
||||||
|
|
||||||
config.headers['X-Timezone-Name'] = timezoneName;
|
config.headers['X-Timezone-Name'] = timezoneName;
|
||||||
|
|||||||
+5
-10
@@ -11,8 +11,7 @@ import {
|
|||||||
isNumber
|
isNumber
|
||||||
} from './common.ts';
|
} from './common.ts';
|
||||||
import {
|
import {
|
||||||
getBrowserTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes
|
||||||
getDummyUnixTimeForLocalUsage
|
|
||||||
} from './datetime.ts';
|
} from './datetime.ts';
|
||||||
import {
|
import {
|
||||||
categoryTypeToTransactionType,
|
categoryTypeToTransactionType,
|
||||||
@@ -33,9 +32,10 @@ export interface SetTransactionOptions {
|
|||||||
comment?: string;
|
comment?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setTransactionModelByTransaction(transaction: Transaction, transaction2: Transaction | null | undefined, allCategories: Record<number, TransactionCategory[]>, allCategoriesMap: Record<string, TransactionCategory>, allVisibleAccounts: Account[], allAccountsMap: Record<string, Account>, allTagsMap: Record<string, TransactionTag>, defaultAccountId: string, options: SetTransactionOptions, setContextData: boolean, convertContextTime: boolean): void {
|
export function setTransactionModelByTransaction(transaction: Transaction, transaction2: Transaction | null | undefined, allCategories: Record<number, TransactionCategory[]>, allCategoriesMap: Record<string, TransactionCategory>, allVisibleAccounts: Account[], allAccountsMap: Record<string, Account>, allTagsMap: Record<string, TransactionTag>, defaultAccountId: string, options: SetTransactionOptions, setContextData: boolean): void {
|
||||||
if (isDefined(options.time)) {
|
if (isDefined(options.time)) {
|
||||||
transaction.time = options.time;
|
transaction.time = options.time;
|
||||||
|
transaction.utcOffset = getTimezoneOffsetMinutes(transaction.time, transaction.timeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.type && options.categoryId && options.categoryId !== '0' && allCategoriesMap[options.categoryId]) {
|
if (!options.type && options.categoryId && options.categoryId !== '0' && allCategoriesMap[options.categoryId]) {
|
||||||
@@ -172,14 +172,9 @@ export function setTransactionModelByTransaction(transaction: Transaction, trans
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (setContextData) {
|
if (setContextData) {
|
||||||
transaction.utcOffset = transaction2.utcOffset;
|
transaction.time = transaction2.time;
|
||||||
transaction.timeZone = transaction2.timeZone;
|
transaction.timeZone = transaction2.timeZone;
|
||||||
|
transaction.utcOffset = transaction2.utcOffset;
|
||||||
if (convertContextTime) {
|
|
||||||
transaction.time = getDummyUnixTimeForLocalUsage(transaction2.time, transaction.utcOffset, getBrowserTimezoneOffsetMinutes());
|
|
||||||
} else {
|
|
||||||
transaction.time = transaction2.time;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.sourceAccountId = transaction2.sourceAccountId;
|
transaction.sourceAccountId = transaction2.sourceAccountId;
|
||||||
|
|||||||
+37
-45
@@ -187,6 +187,7 @@ import {
|
|||||||
formatCurrentTime,
|
formatCurrentTime,
|
||||||
formatGregorianCalendarYearDashMonthDashDay,
|
formatGregorianCalendarYearDashMonthDashDay,
|
||||||
formatGregorianCalendarMonthDashDay,
|
formatGregorianCalendarMonthDashDay,
|
||||||
|
formatDateTime,
|
||||||
formatUnixTime,
|
formatUnixTime,
|
||||||
getBrowserTimezoneOffset,
|
getBrowserTimezoneOffset,
|
||||||
getBrowserTimezoneOffsetMinutes,
|
getBrowserTimezoneOffsetMinutes,
|
||||||
@@ -202,7 +203,7 @@ import {
|
|||||||
getTimeDifferenceHoursAndMinutes,
|
getTimeDifferenceHoursAndMinutes,
|
||||||
getTimezoneOffset,
|
getTimezoneOffset,
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
guessTimezoneName,
|
getBrowserTimezoneName,
|
||||||
isDateRangeMatchFullMonths,
|
isDateRangeMatchFullMonths,
|
||||||
isDateRangeMatchFullYears,
|
isDateRangeMatchFullYears,
|
||||||
isPM
|
isPM
|
||||||
@@ -1159,20 +1160,20 @@ export function useI18n() {
|
|||||||
return allRecentMonthDateRanges;
|
return allRecentMonthDateRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllTimezones(includeSystemDefault?: boolean): LocalizedTimezoneInfo[] {
|
function getAllTimezones(unixTime: number, includeSystemDefault?: boolean): LocalizedTimezoneInfo[] {
|
||||||
const numeralSystem = getCurrentNumeralSystemType();
|
const numeralSystem = getCurrentNumeralSystemType();
|
||||||
const defaultTimezoneOffset = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getBrowserTimezoneOffset());
|
const defaultTimezoneOffset = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getBrowserTimezoneOffset(unixTime));
|
||||||
const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes();
|
const defaultTimezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes(unixTime);
|
||||||
const allTimezoneInfos: LocalizedTimezoneInfo[] = [];
|
const allTimezoneInfos: LocalizedTimezoneInfo[] = [];
|
||||||
|
|
||||||
for (const timezoneInfo of ALL_TIMEZONES) {
|
for (const timezoneInfo of ALL_TIMEZONES) {
|
||||||
const utcOffset = (timezoneInfo.timezoneName !== UTC_TIMEZONE.timezoneName ? numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(timezoneInfo.timezoneName)) : '');
|
const utcOffset = (timezoneInfo.timezoneName !== UTC_TIMEZONE.timezoneName ? numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(unixTime, timezoneInfo.timezoneName)) : '');
|
||||||
const displayName = t(`timezone.${timezoneInfo.displayName}`);
|
const displayName = t(`timezone.${timezoneInfo.displayName}`);
|
||||||
|
|
||||||
allTimezoneInfos.push({
|
allTimezoneInfos.push({
|
||||||
name: timezoneInfo.timezoneName,
|
name: timezoneInfo.timezoneName,
|
||||||
utcOffset: utcOffset,
|
utcOffset: utcOffset,
|
||||||
utcOffsetMinutes: getTimezoneOffsetMinutes(timezoneInfo.timezoneName),
|
utcOffsetMinutes: getTimezoneOffsetMinutes(unixTime, timezoneInfo.timezoneName),
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
displayNameWithUtcOffset: `(UTC${utcOffset}) ${displayName}`
|
displayNameWithUtcOffset: `(UTC${utcOffset}) ${displayName}`
|
||||||
});
|
});
|
||||||
@@ -1206,7 +1207,7 @@ export function useI18n() {
|
|||||||
|
|
||||||
function getAllTimezoneTypesUsedForStatistics(currentTimezone?: string): TypeAndDisplayName[] {
|
function getAllTimezoneTypesUsedForStatistics(currentTimezone?: string): TypeAndDisplayName[] {
|
||||||
const numeralSystem = getCurrentNumeralSystemType();
|
const numeralSystem = getCurrentNumeralSystemType();
|
||||||
const currentTimezoneOffset = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(currentTimezone));
|
const currentTimezoneOffset = numeralSystem.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(getCurrentUnixTime(), currentTimezone));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -1789,12 +1790,11 @@ export function useI18n() {
|
|||||||
return formatGregorianCalendarMonthDashDay(monthDay, getLocalizedLongMonthDayFormat(), getDateTimeFormatOptions({ calendarType: gregorianLikeCalendarType, numeralSystem: numeralSystem }));
|
return formatGregorianCalendarMonthDashDay(monthDay, getLocalizedLongMonthDayFormat(), getDateTimeFormatOptions({ calendarType: gregorianLikeCalendarType, numeralSystem: numeralSystem }));
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatUnixTimeToGregorianLikeYearQuarter(unixTime: number): string {
|
function formatDateTimeToGregorianLikeYearQuarter(dateTime: DateTime): string {
|
||||||
const gregorianLikeCalendarType = getGregorianLikeCalendarType();
|
const gregorianLikeCalendarType = getGregorianLikeCalendarType();
|
||||||
const dateTimeFormatOptions = getDateTimeFormatOptions({ calendarType: gregorianLikeCalendarType });
|
const dateTimeFormatOptions = getDateTimeFormatOptions({ calendarType: gregorianLikeCalendarType });
|
||||||
const date = parseDateTimeFromUnixTime(unixTime);
|
const year = dateTime.getLocalizedCalendarYear(dateTimeFormatOptions);
|
||||||
const year = date.getLocalizedCalendarYear(dateTimeFormatOptions);
|
const quarter = dateTime.getLocalizedCalendarQuarter(dateTimeFormatOptions);
|
||||||
const quarter = date.getLocalizedCalendarQuarter(dateTimeFormatOptions);
|
|
||||||
return formatYearQuarter(year, quarter);
|
return formatYearQuarter(year, quarter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1887,9 +1887,9 @@ export function useI18n() {
|
|||||||
return `${displayStartTime} ~ ${displayEndTime}`;
|
return `${displayStartTime} ~ ${displayEndTime}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTimezoneDifferenceDisplayText(utcOffset: number): string {
|
function getTimezoneDifferenceDisplayText(unixTime: number, utcOffset: number): string {
|
||||||
const numeralSystem = getCurrentNumeralSystemType();
|
const numeralSystem = getCurrentNumeralSystemType();
|
||||||
const defaultTimezoneOffset = getTimezoneOffsetMinutes();
|
const defaultTimezoneOffset = getTimezoneOffsetMinutes(unixTime);
|
||||||
const offsetTime = getTimeDifferenceHoursAndMinutes(utcOffset - defaultTimezoneOffset);
|
const offsetTime = getTimeDifferenceHoursAndMinutes(utcOffset - defaultTimezoneOffset);
|
||||||
|
|
||||||
if (utcOffset > defaultTimezoneOffset) {
|
if (utcOffset > defaultTimezoneOffset) {
|
||||||
@@ -2284,19 +2284,11 @@ export function useI18n() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setTimeZone(timezone: string): void {
|
function setTimeZone(timezone: string): void {
|
||||||
let timezoneOffsetMinutes = getBrowserTimezoneOffsetMinutes();
|
|
||||||
|
|
||||||
if (timezone) {
|
if (timezone) {
|
||||||
timezoneOffsetMinutes = getTimezoneOffsetMinutes(timezone);
|
moment.tz.setDefault(timezone);
|
||||||
|
} else {
|
||||||
|
moment.tz.setDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
moment.tz.add(moment.tz.pack({
|
|
||||||
name: 'Fixed/Timezone',
|
|
||||||
abbrs: ['FIX'],
|
|
||||||
offsets: [-timezoneOffsetMinutes],
|
|
||||||
untils: [0]
|
|
||||||
}));
|
|
||||||
moment.tz.setDefault('Fixed/Timezone');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function initLocale(lastUserLanguage?: string, timezone?: string): LocaleDefaultSettings | null {
|
function initLocale(lastUserLanguage?: string, timezone?: string): LocaleDefaultSettings | null {
|
||||||
@@ -2317,7 +2309,7 @@ export function useI18n() {
|
|||||||
logger.info(`Current timezone is ${timezone}`);
|
logger.info(`Current timezone is ${timezone}`);
|
||||||
setTimeZone(timezone);
|
setTimeZone(timezone);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`No timezone is set, use browser default ${getTimezoneOffset()} (maybe ${guessTimezoneName()})`);
|
logger.info(`No timezone is set, use browser default ${getTimezoneOffset(getCurrentUnixTime())} (${getBrowserTimezoneName()})`);
|
||||||
setTimeZone('');
|
setTimeZone('');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2423,36 +2415,36 @@ export function useI18n() {
|
|||||||
isLongTimeMinuteTwoDigits,
|
isLongTimeMinuteTwoDigits,
|
||||||
isLongTimeSecondTwoDigits,
|
isLongTimeSecondTwoDigits,
|
||||||
// format date time (by calendar display type) functions
|
// format date time (by calendar display type) functions
|
||||||
getCalendarDisplayShortYearFromUnixTime: (unixTime: number, numeralSystem?: NumeralSystem, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortYearFormat(), getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType, numeralSystem: numeralSystem }), utcOffset, currentUtcOffset),
|
getCalendarDisplayShortYearFromDateTime: (dateTime: DateTime, numeralSystem?: NumeralSystem) => formatDateTime(dateTime, getLocalizedShortYearFormat(), getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType, numeralSystem: numeralSystem })),
|
||||||
getCalendarDisplayShortMonthFromUnixTime: (unixTime: number, numeralSystem?: NumeralSystem, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, 'MMM', getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType, numeralSystem: numeralSystem }), utcOffset, currentUtcOffset),
|
getCalendarDisplayShortMonthFromDateTime: (dateTime: DateTime, numeralSystem?: NumeralSystem) => formatDateTime(dateTime, 'MMM', getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType, numeralSystem: numeralSystem })),
|
||||||
getCalendarDisplayDayOfMonthFromUnixTime: (unixTime: number, numeralSystem?: NumeralSystem, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDayFormat(), getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType, numeralSystem: numeralSystem }), utcOffset, currentUtcOffset),
|
getCalendarDisplayDayOfMonthFromDateTime: (dateTime: DateTime, numeralSystem?: NumeralSystem) => formatDateTime(dateTime, getLocalizedShortDayFormat(), getDateTimeFormatOptions({ calendarType: getCurrentCalendarDisplayType().primaryCalendarType, numeralSystem: numeralSystem })),
|
||||||
// format date time (by date display type) functions
|
// format date time (by date display type) functions
|
||||||
parseDateTimeFromLongDateTime: (dateTime: string) => parseDateTimeFromString(dateTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat()),
|
parseDateTimeFromLongDateTime: (dateTime: string) => parseDateTimeFromString(dateTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat()),
|
||||||
parseDateTimeFromShortDateTime: (dateTime: string) => parseDateTimeFromString(dateTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat()),
|
parseDateTimeFromShortDateTime: (dateTime: string) => parseDateTimeFromString(dateTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat()),
|
||||||
formatUnixTimeToLongDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToLongDateTime: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedLongDateFormat() + ' ' + getLocalizedLongTimeFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToShortDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToShortDateTime: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedShortDateFormat() + ' ' + getLocalizedShortTimeFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToLongDate: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongDateFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToLongDate: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedLongDateFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToShortDate: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortDateFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToShortDate: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedShortDateFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToLongMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongMonthDayFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToLongMonthDay: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedLongMonthDayFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToShortMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortMonthDayFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToShortMonthDay: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedShortMonthDayFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToLongTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToLongTime: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedLongTimeFormat(), getDateTimeFormatOptions()),
|
||||||
formatUnixTimeToShortTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortTimeFormat(), getDateTimeFormatOptions(), utcOffset, currentUtcOffset),
|
formatDateTimeToShortTime: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedShortTimeFormat(), getDateTimeFormatOptions()),
|
||||||
formatGregorianTextualYearMonthDayToLongDate: (date: TextualYearMonthDay) => formatGregorianCalendarYearDashMonthDashDay(date, getLocalizedLongDateFormat(), getDateTimeFormatOptions()),
|
formatGregorianTextualYearMonthDayToLongDate: (date: TextualYearMonthDay) => formatGregorianCalendarYearDashMonthDashDay(date, getLocalizedLongDateFormat(), getDateTimeFormatOptions()),
|
||||||
// format date time (Gregorian calendar and Gregorian-like calendar) functions
|
// format date time (Gregorian calendar and Gregorian-like calendar) functions
|
||||||
formatUnixTimeToGregorianLikeLongYear: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongYearFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianLikeLongYear: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedLongYearFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() })),
|
||||||
formatUnixTimeToGregorianLikeShortYear: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortYearFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianLikeShortYear: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedShortYearFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() })),
|
||||||
formatUnixTimeToGregorianLikeLongYearMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongYearMonthFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianLikeLongYearMonth: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedLongYearMonthFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() })),
|
||||||
formatUnixTimeToGregorianLikeShortYearMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortYearMonthFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianLikeShortYearMonth: (dateTime: DateTime) => formatDateTime(dateTime, getLocalizedShortYearMonthFormat(), getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() })),
|
||||||
formatUnixTimeToGregorianLikeLongMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, 'MMMM', getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianLikeLongMonth: (dateTime: DateTime) => formatDateTime(dateTime, 'MMMM', getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() })),
|
||||||
formatUnixTimeToGregorianLikeShortMonth: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, 'MMM', getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianLikeShortMonth: (dateTime: DateTime) => formatDateTime(dateTime, 'MMM', getDateTimeFormatOptions({ calendarType: getGregorianLikeCalendarType() })),
|
||||||
formatGregorianTextualMonthDayToGregorianLikeLongMonthDay,
|
formatGregorianTextualMonthDayToGregorianLikeLongMonthDay,
|
||||||
formatUnixTimeToGregorianLikeYearQuarter,
|
formatDateTimeToGregorianLikeYearQuarter,
|
||||||
formatYearQuarterToGregorianLikeYearQuarter,
|
formatYearQuarterToGregorianLikeYearQuarter,
|
||||||
formatUnixTimeToGregorianLikeFiscalYear,
|
formatDateTimeToGregorianLikeFiscalYear: (dateTime: DateTime) => formatUnixTimeToGregorianLikeFiscalYear(dateTime.getUnixTime()),
|
||||||
formatGregorianYearToGregorianLikeFiscalYear,
|
formatGregorianYearToGregorianLikeFiscalYear,
|
||||||
formatFiscalYearStartToGregorianLikeLongMonth,
|
formatFiscalYearStartToGregorianLikeLongMonth,
|
||||||
// format date time (Gregorian calendar) functions
|
// format date time (Gregorian calendar) functions
|
||||||
formatUnixTimeToGregorianDefaultDateTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, KnownDateTimeFormat.DefaultDateTime.format, getDateTimeFormatOptions({ numeralSystem: NumeralSystem.WesternArabicNumerals, calendarType: CalendarType.Gregorian }), utcOffset, currentUtcOffset),
|
formatDateTimeToGregorianDefaultDateTime: (dateTime: DateTime) => formatDateTime(dateTime, KnownDateTimeFormat.DefaultDateTime.format, getDateTimeFormatOptions({ numeralSystem: NumeralSystem.WesternArabicNumerals, calendarType: CalendarType.Gregorian })),
|
||||||
// other format date time functions
|
// other format date time functions
|
||||||
formatDateRange,
|
formatDateRange,
|
||||||
getTimezoneDifferenceDisplayText,
|
getTimezoneDifferenceDisplayText,
|
||||||
|
|||||||
+18
-19
@@ -226,11 +226,11 @@ export class Transaction implements TransactionInfoResponse {
|
|||||||
this._displayDayOfWeek = displayDayOfWeek;
|
this._displayDayOfWeek = displayDayOfWeek;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toCreateRequest(clientSessionId: string, actualTime?: number): TransactionCreateRequest {
|
public toCreateRequest(clientSessionId: string): TransactionCreateRequest {
|
||||||
return {
|
return {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
categoryId: this.getCategoryId(),
|
categoryId: this.getCategoryId(),
|
||||||
time: actualTime ? actualTime : this.time,
|
time: this.time,
|
||||||
utcOffset: this.utcOffset,
|
utcOffset: this.utcOffset,
|
||||||
sourceAccountId: this.sourceAccountId,
|
sourceAccountId: this.sourceAccountId,
|
||||||
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
||||||
@@ -245,7 +245,7 @@ export class Transaction implements TransactionInfoResponse {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public toModifyRequest(actualTime?: number): TransactionModifyRequest {
|
public toModifyRequest(): TransactionModifyRequest {
|
||||||
let categoryId = this.getCategoryId();
|
let categoryId = this.getCategoryId();
|
||||||
|
|
||||||
if (this.type === TransactionType.ModifyBalance) {
|
if (this.type === TransactionType.ModifyBalance) {
|
||||||
@@ -255,7 +255,7 @@ export class Transaction implements TransactionInfoResponse {
|
|||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
categoryId: categoryId,
|
categoryId: categoryId,
|
||||||
time: actualTime ? actualTime : this.time,
|
time: this.time,
|
||||||
utcOffset: this.utcOffset,
|
utcOffset: this.utcOffset,
|
||||||
sourceAccountId: this.sourceAccountId,
|
sourceAccountId: this.sourceAccountId,
|
||||||
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
destinationAccountId: this.type === TransactionType.Transfer ? this.destinationAccountId : '0',
|
||||||
@@ -677,20 +677,20 @@ export const ALL_TRANSACTION_AMOUNTS_REQUEST_TYPE = [
|
|||||||
|
|
||||||
export type TransactionAmountsRequestType = typeof ALL_TRANSACTION_AMOUNTS_REQUEST_TYPE[number];
|
export type TransactionAmountsRequestType = typeof ALL_TRANSACTION_AMOUNTS_REQUEST_TYPE[number];
|
||||||
|
|
||||||
export const LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES: PartialRecord<TransactionAmountsRequestType, number> = {
|
export const LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES: TransactionAmountsRequestType[] = [
|
||||||
'monthBeforeLast10Months': 11,
|
'monthBeforeLast10Months',
|
||||||
'monthBeforeLast9Months': 10,
|
'monthBeforeLast9Months',
|
||||||
'monthBeforeLast8Months': 9,
|
'monthBeforeLast8Months',
|
||||||
'monthBeforeLast7Months': 8,
|
'monthBeforeLast7Months',
|
||||||
'monthBeforeLast6Months': 7,
|
'monthBeforeLast6Months',
|
||||||
'monthBeforeLast5Months': 6,
|
'monthBeforeLast5Months',
|
||||||
'monthBeforeLast4Months': 5,
|
'monthBeforeLast4Months',
|
||||||
'monthBeforeLast3Months': 4,
|
'monthBeforeLast3Months',
|
||||||
'monthBeforeLast2Months': 3,
|
'monthBeforeLast2Months',
|
||||||
'monthBeforeLastMonth': 2,
|
'monthBeforeLastMonth',
|
||||||
'lastMonth': 1,
|
'lastMonth',
|
||||||
'thisMonth': 0
|
'thisMonth'
|
||||||
};
|
];
|
||||||
|
|
||||||
export interface TransactionAmountsRequestParams extends PartialRecord<TransactionAmountsRequestType, StartEndTime> {
|
export interface TransactionAmountsRequestParams extends PartialRecord<TransactionAmountsRequestType, StartEndTime> {
|
||||||
readonly useTransactionTimezone: boolean;
|
readonly useTransactionTimezone: boolean;
|
||||||
@@ -1009,7 +1009,6 @@ export interface TransactionOverviewResponseItem {
|
|||||||
|
|
||||||
export interface TransactionMonthlyIncomeAndExpenseData {
|
export interface TransactionMonthlyIncomeAndExpenseData {
|
||||||
readonly monthStartTime: number;
|
readonly monthStartTime: number;
|
||||||
readonly monthsBeforeCurrentMonth: number;
|
|
||||||
readonly incomeAmount: number;
|
readonly incomeAmount: number;
|
||||||
readonly expenseAmount: number;
|
readonly expenseAmount: number;
|
||||||
readonly incompleteIncomeAmount: boolean;
|
readonly incompleteIncomeAmount: boolean;
|
||||||
|
|||||||
@@ -53,12 +53,7 @@ import {
|
|||||||
splitItemsToMap,
|
splitItemsToMap,
|
||||||
countSplitItems
|
countSplitItems
|
||||||
} from '@/lib/common.ts';
|
} from '@/lib/common.ts';
|
||||||
import {
|
import { parseDateTimeFromUnixTimeWithTimezoneOffset } from '@/lib/datetime.ts';
|
||||||
getTimezoneOffsetMinutes,
|
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getActualUnixTimeForStore,
|
|
||||||
parseDateTimeFromUnixTime
|
|
||||||
} from '@/lib/datetime.ts';
|
|
||||||
import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts';
|
import { getAmountWithDecimalNumberCount } from '@/lib/numeral.ts';
|
||||||
import { getCurrencyFraction } from '@/lib/currency.ts';
|
import { getCurrencyFraction } from '@/lib/currency.ts';
|
||||||
import { getFirstVisibleCategoryId } from '@/lib/category.ts';
|
import { getFirstVisibleCategoryId } from '@/lib/category.ts';
|
||||||
@@ -185,14 +180,13 @@ export const useTransactionsStore = defineStore('transactions', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (transactionPageWrapper.items && transactionPageWrapper.items.length) {
|
if (transactionPageWrapper.items && transactionPageWrapper.items.length) {
|
||||||
const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone);
|
|
||||||
let currentMonthListIndex = -1;
|
let currentMonthListIndex = -1;
|
||||||
let currentMonthList: TransactionMonthList | null = null;
|
let currentMonthList: TransactionMonthList | null = null;
|
||||||
|
|
||||||
for (const [item, index] of itemAndIndex(transactionPageWrapper.items)) {
|
for (const [item, index] of itemAndIndex(transactionPageWrapper.items)) {
|
||||||
fillTransactionObject(item, currentUtcOffset);
|
fillTransactionObject(item);
|
||||||
|
|
||||||
const transactionTime = parseDateTimeFromUnixTime(item.time, item.utcOffset, currentUtcOffset);
|
const transactionTime = parseDateTimeFromUnixTimeWithTimezoneOffset(item.time, item.utcOffset);
|
||||||
const transactionYear = transactionTime.getGregorianCalendarYear();
|
const transactionYear = transactionTime.getGregorianCalendarYear();
|
||||||
const transactionMonth = transactionTime.getGregorianCalendarMonth();
|
const transactionMonth = transactionTime.getGregorianCalendarMonth();
|
||||||
const transactionYearDashMonth = transactionTime.getGregorianCalendarYearDashMonth();
|
const transactionYearDashMonth = transactionTime.getGregorianCalendarYearDashMonth();
|
||||||
@@ -264,8 +258,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateTransactionInTransactionList({ currentTransaction, defaultCurrency }: { currentTransaction: Transaction, defaultCurrency: string }): void {
|
function updateTransactionInTransactionList({ currentTransaction, defaultCurrency }: { currentTransaction: Transaction, defaultCurrency: string }): void {
|
||||||
const currentUtcOffset = getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone);
|
const transactionTime = parseDateTimeFromUnixTimeWithTimezoneOffset(currentTransaction.time, currentTransaction.utcOffset);
|
||||||
const transactionTime = parseDateTimeFromUnixTime(currentTransaction.time, currentTransaction.utcOffset, currentUtcOffset);
|
|
||||||
const transactionYear = transactionTime.getGregorianCalendarYear();
|
const transactionYear = transactionTime.getGregorianCalendarYear();
|
||||||
const transactionMonth = transactionTime.getGregorianCalendarMonth();
|
const transactionMonth = transactionTime.getGregorianCalendarMonth();
|
||||||
|
|
||||||
@@ -276,7 +269,7 @@ export const useTransactionsStore = defineStore('transactions', () => {
|
|||||||
|
|
||||||
for (const [transaction, transactionIndex] of itemAndIndex(transactionMonthList.items)) {
|
for (const [transaction, transactionIndex] of itemAndIndex(transactionMonthList.items)) {
|
||||||
if (transaction.id === currentTransaction.id) {
|
if (transaction.id === currentTransaction.id) {
|
||||||
fillTransactionObject(currentTransaction, currentUtcOffset);
|
fillTransactionObject(currentTransaction);
|
||||||
|
|
||||||
if (transactionYear !== transactionMonthList.year ||
|
if (transactionYear !== transactionMonthList.year ||
|
||||||
transactionMonth !== transactionMonthList.month ||
|
transactionMonth !== transactionMonthList.month ||
|
||||||
@@ -445,12 +438,12 @@ export const useTransactionsStore = defineStore('transactions', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillTransactionObject(transaction: Transaction, currentUtcOffset: number): void {
|
function fillTransactionObject(transaction: Transaction): void {
|
||||||
if (!transaction) {
|
if (!transaction) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentUtcOffset);
|
const transactionTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
transaction.setDisplayDate(transactionTime.getGregorianCalendarYearDashMonthDashDay(), transactionTime.getGregorianCalendarDay(), transactionTime.getWeekDay());
|
transaction.setDisplayDate(transactionTime.getGregorianCalendarYearDashMonthDashDay(), transactionTime.getGregorianCalendarDay(), transactionTime.getWeekDay());
|
||||||
|
|
||||||
if (transaction.sourceAccountId) {
|
if (transaction.sourceAccountId) {
|
||||||
@@ -1026,7 +1019,6 @@ export const useTransactionsStore = defineStore('transactions', () => {
|
|||||||
|
|
||||||
function saveTransaction({ transaction, defaultCurrency, isEdit, clientSessionId }: { transaction: Transaction, defaultCurrency: string, isEdit: boolean, clientSessionId: string }): Promise<Transaction> {
|
function saveTransaction({ transaction, defaultCurrency, isEdit, clientSessionId }: { transaction: Transaction, defaultCurrency: string, isEdit: boolean, clientSessionId: string }): Promise<Transaction> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const actualTime = getActualUnixTimeForStore(transaction.time, transaction.utcOffset, getBrowserTimezoneOffsetMinutes());
|
|
||||||
let promise: ApiResponsePromise<TransactionInfoResponse>;
|
let promise: ApiResponsePromise<TransactionInfoResponse>;
|
||||||
|
|
||||||
if (transaction.type !== TransactionType.Expense &&
|
if (transaction.type !== TransactionType.Expense &&
|
||||||
@@ -1041,9 +1033,9 @@ export const useTransactionsStore = defineStore('transactions', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isEdit) {
|
if (!isEdit) {
|
||||||
promise = services.addTransaction(transaction.toCreateRequest(clientSessionId, actualTime));
|
promise = services.addTransaction(transaction.toCreateRequest(clientSessionId));
|
||||||
} else {
|
} else {
|
||||||
promise = services.modifyTransaction(transaction.toModifyRequest(actualTime));
|
promise = services.modifyTransaction(transaction.toModifyRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
promise.then(response => {
|
promise.then(response => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import type { VersionInfo } from '@/core/version.ts';
|
|||||||
|
|
||||||
import type { LatestExchangeRateResponse } from '@/models/exchange_rate.ts';
|
import type { LatestExchangeRateResponse } from '@/models/exchange_rate.ts';
|
||||||
|
|
||||||
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
import { getMapProvider } from '@/lib/server_settings.ts';
|
import { getMapProvider } from '@/lib/server_settings.ts';
|
||||||
import { getMapWebsite } from '@/lib/map/index.ts';
|
import { getMapWebsite } from '@/lib/map/index.ts';
|
||||||
import { getLicense, getThirdPartyLicenses } from '@/lib/licenses.ts';
|
import { getLicense, getThirdPartyLicenses } from '@/lib/licenses.ts';
|
||||||
@@ -16,7 +17,7 @@ import { formatDisplayVersion, getClientDisplayVersion, getClientBuildTime } fro
|
|||||||
import { clearBrowserCaches } from '@/lib/ui/common.ts';
|
import { clearBrowserCaches } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
export function useAboutPageBase() {
|
export function useAboutPageBase() {
|
||||||
const { tt, formatUnixTimeToLongDateTime } = useI18n();
|
const { tt, formatDateTimeToLongDateTime } = useI18n();
|
||||||
|
|
||||||
const systemsStore = useSystemsStore();
|
const systemsStore = useSystemsStore();
|
||||||
const exchangeRatesStore = useExchangeRatesStore();
|
const exchangeRatesStore = useExchangeRatesStore();
|
||||||
@@ -41,7 +42,8 @@ export function useAboutPageBase() {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatUnixTimeToLongDateTime(parseInt(time));
|
const buildDateTime = parseDateTimeFromUnixTime(parseInt(time));
|
||||||
|
return formatDateTimeToLongDateTime(buildDateTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
const exchangeRatesData = computed<LatestExchangeRateResponse | undefined>(() => exchangeRatesStore.latestExchangeRates.data);
|
const exchangeRatesData = computed<LatestExchangeRateResponse | undefined>(() => exchangeRatesStore.latestExchangeRates.data);
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import type {
|
|||||||
} from '@/models/exchange_rate.ts';
|
} from '@/models/exchange_rate.ts';
|
||||||
|
|
||||||
import { getExchangedAmountByRate } from '@/lib/numeral.ts';
|
import { getExchangedAmountByRate } from '@/lib/numeral.ts';
|
||||||
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
|
|
||||||
export function useExchangeRatesPageBase() {
|
export function useExchangeRatesPageBase() {
|
||||||
const { getAllDisplayExchangeRates, formatUnixTimeToLongDate, parseAmountFromWesternArabicNumerals } = useI18n();
|
const { getAllDisplayExchangeRates, formatDateTimeToLongDate, parseAmountFromWesternArabicNumerals } = useI18n();
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const exchangeRatesStore = useExchangeRatesStore();
|
const exchangeRatesStore = useExchangeRatesStore();
|
||||||
@@ -27,8 +28,12 @@ export function useExchangeRatesPageBase() {
|
|||||||
const isUserCustomExchangeRates = computed<boolean>(() => exchangeRatesStore.isUserCustomExchangeRates);
|
const isUserCustomExchangeRates = computed<boolean>(() => exchangeRatesStore.isUserCustomExchangeRates);
|
||||||
|
|
||||||
const exchangeRatesDataUpdateTime = computed<string>(() => {
|
const exchangeRatesDataUpdateTime = computed<string>(() => {
|
||||||
const exchangeRatesLastUpdateTime = exchangeRatesStore.exchangeRatesLastUpdateTime;
|
if (!exchangeRatesStore.exchangeRatesLastUpdateTime) {
|
||||||
return exchangeRatesLastUpdateTime ? formatUnixTimeToLongDate(exchangeRatesLastUpdateTime) : '';
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const exchangeRatesLastUpdateTime = parseDateTimeFromUnixTime(exchangeRatesStore.exchangeRatesLastUpdateTime);
|
||||||
|
return formatDateTimeToLongDate(exchangeRatesLastUpdateTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
const availableExchangeRates = computed<LocalizedLatestExchangeRate[]>(() => {
|
const availableExchangeRates = computed<LocalizedLatestExchangeRate[]>(() => {
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ import type {
|
|||||||
TransactionOverviewResponseItem
|
TransactionOverviewResponseItem
|
||||||
} from '@/models/transaction.ts';
|
} from '@/models/transaction.ts';
|
||||||
|
|
||||||
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
|
|
||||||
export function useHomePageBase() {
|
export function useHomePageBase() {
|
||||||
const {
|
const {
|
||||||
formatUnixTimeToLongDate,
|
formatDateTimeToLongDate,
|
||||||
formatUnixTimeToLongMonthDay,
|
formatDateTimeToLongMonthDay,
|
||||||
formatUnixTimeToGregorianLikeLongYear,
|
formatDateTimeToGregorianLikeLongYear,
|
||||||
formatUnixTimeToGregorianLikeLongMonth,
|
formatDateTimeToGregorianLikeLongMonth,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -57,19 +59,19 @@ export function useHomePageBase() {
|
|||||||
const displayDateRange = computed<TransactionOverviewDisplayTime>(() => {
|
const displayDateRange = computed<TransactionOverviewDisplayTime>(() => {
|
||||||
return {
|
return {
|
||||||
today: {
|
today: {
|
||||||
displayTime: formatUnixTimeToLongDate(overviewStore.transactionDataRange.today.startTime),
|
displayTime: formatDateTimeToLongDate(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.today.startTime)),
|
||||||
},
|
},
|
||||||
thisWeek: {
|
thisWeek: {
|
||||||
startTime: formatUnixTimeToLongMonthDay(overviewStore.transactionDataRange.thisWeek.startTime),
|
startTime: formatDateTimeToLongMonthDay(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.thisWeek.startTime)),
|
||||||
endTime: formatUnixTimeToLongMonthDay(overviewStore.transactionDataRange.thisWeek.endTime)
|
endTime: formatDateTimeToLongMonthDay(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.thisWeek.endTime))
|
||||||
},
|
},
|
||||||
thisMonth: {
|
thisMonth: {
|
||||||
displayTime: formatUnixTimeToGregorianLikeLongMonth(overviewStore.transactionDataRange.thisMonth.startTime),
|
displayTime: formatDateTimeToGregorianLikeLongMonth(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.thisMonth.startTime)),
|
||||||
startTime: formatUnixTimeToLongMonthDay(overviewStore.transactionDataRange.thisMonth.startTime),
|
startTime: formatDateTimeToLongMonthDay(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.thisMonth.startTime)),
|
||||||
endTime: formatUnixTimeToLongMonthDay(overviewStore.transactionDataRange.thisMonth.endTime)
|
endTime: formatDateTimeToLongMonthDay(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.thisMonth.endTime))
|
||||||
},
|
},
|
||||||
thisYear: {
|
thisYear: {
|
||||||
displayTime: formatUnixTimeToGregorianLikeLongYear(overviewStore.transactionDataRange.thisYear.startTime)
|
displayTime: formatDateTimeToGregorianLikeLongYear(parseDateTimeFromUnixTime(overviewStore.transactionDataRange.thisYear.startTime))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ import { AccountCategory, AccountType } from '@/core/account.ts';
|
|||||||
import type { LocalizedAccountCategory } from '@/core/account.ts';
|
import type { LocalizedAccountCategory } from '@/core/account.ts';
|
||||||
import { Account } from '@/models/account.ts';
|
import { Account } from '@/models/account.ts';
|
||||||
|
|
||||||
import { getCurrentUnixTime } from '@/lib/datetime.ts';
|
import { isDefined } from '@/lib/common.ts';
|
||||||
|
import {
|
||||||
|
getTimezoneOffsetMinutes,
|
||||||
|
getSameDateTimeWithCurrentTimezone,
|
||||||
|
parseDateTimeFromUnixTimeWithBrowserTimezone,
|
||||||
|
getCurrentUnixTime
|
||||||
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
export interface DayAndDisplayName {
|
export interface DayAndDisplayName {
|
||||||
readonly day: number;
|
readonly day: number;
|
||||||
@@ -25,7 +31,7 @@ export function useAccountEditPageBase() {
|
|||||||
const clientSessionId = ref<string>('');
|
const clientSessionId = ref<string>('');
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const submitting = ref<boolean>(false);
|
const submitting = ref<boolean>(false);
|
||||||
const account = ref<Account>(Account.createNewAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTime()));
|
const account = ref<Account>(Account.createNewAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTimeForNewAccount()));
|
||||||
const subAccounts = ref<Account[]>([]);
|
const subAccounts = ref<Account[]>([]);
|
||||||
|
|
||||||
const title = computed<string>(() => {
|
const title = computed<string>(() => {
|
||||||
@@ -89,6 +95,18 @@ export function useAccountEditPageBase() {
|
|||||||
|
|
||||||
const isAccountSupportCreditCardStatementDate = computed<boolean>(() => account.value && account.value.category === AccountCategory.CreditCard.type);
|
const isAccountSupportCreditCardStatementDate = computed<boolean>(() => account.value && account.value.category === AccountCategory.CreditCard.type);
|
||||||
|
|
||||||
|
function getCurrentUnixTimeForNewAccount(): number {
|
||||||
|
return getSameDateTimeWithCurrentTimezone(parseDateTimeFromUnixTimeWithBrowserTimezone(getCurrentUnixTime())).getUnixTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultTimezoneOffsetMinutes(account: Account): number {
|
||||||
|
if (!account.balanceTime) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTimezoneOffsetMinutes(account.balanceTime);
|
||||||
|
}
|
||||||
|
|
||||||
function getAccountCreditCardStatementDate(statementDate?: number): string | null {
|
function getAccountCreditCardStatementDate(statementDate?: number): string | null {
|
||||||
for (const item of allAvailableMonthDays.value) {
|
for (const item of allAvailableMonthDays.value) {
|
||||||
if (item.day === statementDate) {
|
if (item.day === statementDate) {
|
||||||
@@ -99,6 +117,23 @@ export function useAccountEditPageBase() {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAccountBalanceTime(account: Account, balanceTime: number): void {
|
||||||
|
if (!isDefined(account.balanceTime)) {
|
||||||
|
account.balanceTime = balanceTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldUtcOffset = getTimezoneOffsetMinutes(account.balanceTime);
|
||||||
|
const newUtcOffset = getTimezoneOffsetMinutes(balanceTime);
|
||||||
|
|
||||||
|
if (oldUtcOffset === newUtcOffset) {
|
||||||
|
account.balanceTime = balanceTime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
account.balanceTime = balanceTime - (newUtcOffset - oldUtcOffset) * 60;
|
||||||
|
}
|
||||||
|
|
||||||
function getInputEmptyProblemMessage(account: Account, isSubAccount: boolean): string | null {
|
function getInputEmptyProblemMessage(account: Account, isSubAccount: boolean): string | null {
|
||||||
if (!isSubAccount && !account.category) {
|
if (!isSubAccount && !account.category) {
|
||||||
return 'Account category cannot be blank';
|
return 'Account category cannot be blank';
|
||||||
@@ -122,7 +157,7 @@ export function useAccountEditPageBase() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const subAccount = account.value.createNewSubAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTime());
|
const subAccount = account.value.createNewSubAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTimeForNewAccount());
|
||||||
subAccounts.value.push(subAccount);
|
subAccounts.value.push(subAccount);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -133,7 +168,7 @@ export function useAccountEditPageBase() {
|
|||||||
|
|
||||||
if (newAccount.subAccounts && newAccount.subAccounts.length > 0) {
|
if (newAccount.subAccounts && newAccount.subAccounts.length > 0) {
|
||||||
for (const oldSubAccount of newAccount.subAccounts) {
|
for (const oldSubAccount of newAccount.subAccounts) {
|
||||||
const subAccount: Account = account.value.createNewSubAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTime());
|
const subAccount: Account = account.value.createNewSubAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTimeForNewAccount());
|
||||||
subAccount.fillFrom(oldSubAccount);
|
subAccount.fillFrom(oldSubAccount);
|
||||||
|
|
||||||
subAccounts.value.push(subAccount);
|
subAccounts.value.push(subAccount);
|
||||||
@@ -163,7 +198,10 @@ export function useAccountEditPageBase() {
|
|||||||
allAvailableMonthDays,
|
allAvailableMonthDays,
|
||||||
isAccountSupportCreditCardStatementDate,
|
isAccountSupportCreditCardStatementDate,
|
||||||
// functions
|
// functions
|
||||||
|
getCurrentUnixTimeForNewAccount,
|
||||||
|
getDefaultTimezoneOffsetMinutes,
|
||||||
getAccountCreditCardStatementDate,
|
getAccountCreditCardStatementDate,
|
||||||
|
updateAccountBalanceTime,
|
||||||
isNewAccount,
|
isNewAccount,
|
||||||
addSubAccount,
|
addSubAccount,
|
||||||
setAccount
|
setAccount
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { ref, computed } from 'vue';
|
|||||||
|
|
||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
|
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useAccountsStore } from '@/stores/account.ts';
|
import { useAccountsStore } from '@/stores/account.ts';
|
||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
@@ -25,7 +24,8 @@ import { replaceAll } from '@/lib/common.ts';
|
|||||||
import {
|
import {
|
||||||
getUtcOffsetByUtcOffsetMinutes,
|
getUtcOffsetByUtcOffsetMinutes,
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
parseDateTimeFromUnixTime
|
parseDateTimeFromUnixTime,
|
||||||
|
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
export function useReconciliationStatementPageBase() {
|
export function useReconciliationStatementPageBase() {
|
||||||
@@ -33,15 +33,14 @@ export function useReconciliationStatementPageBase() {
|
|||||||
tt,
|
tt,
|
||||||
getAllAccountBalanceTrendChartTypes,
|
getAllAccountBalanceTrendChartTypes,
|
||||||
getAllStatisticsDateAggregationTypesWithShortName,
|
getAllStatisticsDateAggregationTypesWithShortName,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
formatUnixTimeToLongDate,
|
formatDateTimeToLongDate,
|
||||||
formatUnixTimeToShortTime,
|
formatDateTimeToShortTime,
|
||||||
formatUnixTimeToGregorianDefaultDateTime,
|
formatDateTimeToGregorianDefaultDateTime,
|
||||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const accountsStore = useAccountsStore();
|
const accountsStore = useAccountsStore();
|
||||||
const transactionCategoriesStore = useTransactionCategoriesStore();
|
const transactionCategoriesStore = useTransactionCategoriesStore();
|
||||||
@@ -53,7 +52,6 @@ export function useReconciliationStatementPageBase() {
|
|||||||
|
|
||||||
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
||||||
const fiscalYearStart = computed<number>(() => userStore.currentUserFiscalYearStart);
|
const fiscalYearStart = computed<number>(() => userStore.currentUserFiscalYearStart);
|
||||||
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
|
|
||||||
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
||||||
|
|
||||||
const allChartTypes = computed<TypeAndDisplayName[]>(() => getAllAccountBalanceTrendChartTypes());
|
const allChartTypes = computed<TypeAndDisplayName[]>(() => getAllAccountBalanceTrendChartTypes());
|
||||||
@@ -79,11 +77,13 @@ export function useReconciliationStatementPageBase() {
|
|||||||
const allCategoriesMap = computed<Record<string, TransactionCategory>>(() => transactionCategoriesStore.allTransactionCategoriesMap);
|
const allCategoriesMap = computed<Record<string, TransactionCategory>>(() => transactionCategoriesStore.allTransactionCategoriesMap);
|
||||||
|
|
||||||
const displayStartDateTime = computed<string>(() => {
|
const displayStartDateTime = computed<string>(() => {
|
||||||
return formatUnixTimeToLongDateTime(startTime.value);
|
const dateTime = parseDateTimeFromUnixTime(startTime.value);
|
||||||
|
return formatDateTimeToLongDateTime(dateTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayEndDateTime = computed<string>(() => {
|
const displayEndDateTime = computed<string>(() => {
|
||||||
return formatUnixTimeToLongDateTime(endTime.value);
|
const dateTime = parseDateTimeFromUnixTime(endTime.value);
|
||||||
|
return formatDateTimeToLongDateTime(dateTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayTotalInflows = computed<string>(() => {
|
const displayTotalInflows = computed<string>(() => {
|
||||||
@@ -160,15 +160,22 @@ export function useReconciliationStatementPageBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayDateTime(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
function getDisplayDateTime(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
||||||
return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
|
return formatDateTimeToLongDateTime(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayDate(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
function getDisplayDate(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
||||||
return formatUnixTimeToLongDate(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
|
return formatDateTimeToLongDate(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTime(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
function getDisplayTime(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
||||||
return formatUnixTimeToShortTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
|
return formatDateTimeToShortTime(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameAsDefaultTimezoneOffsetMinutes(transaction: TransactionReconciliationStatementResponseItemWithInfo): boolean {
|
||||||
|
return transaction.utcOffset === getTimezoneOffsetMinutes(transaction.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTimezone(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
function getDisplayTimezone(transaction: TransactionReconciliationStatementResponseItemWithInfo): string {
|
||||||
@@ -227,7 +234,7 @@ export function useReconciliationStatementPageBase() {
|
|||||||
|
|
||||||
const transactions = reconciliationStatements.value?.transactions ?? [];
|
const transactions = reconciliationStatements.value?.transactions ?? [];
|
||||||
const rows = transactions.map(transaction => {
|
const rows = transactions.map(transaction => {
|
||||||
const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value).getUnixTime();
|
const transactionTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
const type = getDisplayTransactionType(transaction);
|
const type = getDisplayTransactionType(transaction);
|
||||||
let categoryName = transaction.categoryName;
|
let categoryName = transaction.categoryName;
|
||||||
let displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount);
|
let displayAmount = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(transaction.sourceAmount);
|
||||||
@@ -260,7 +267,7 @@ export function useReconciliationStatementPageBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
formatUnixTimeToGregorianDefaultDateTime(transactionTime),
|
formatDateTimeToGregorianDefaultDateTime(transactionTime),
|
||||||
type,
|
type,
|
||||||
categoryName,
|
categoryName,
|
||||||
displayAmount,
|
displayAmount,
|
||||||
@@ -282,7 +289,6 @@ export function useReconciliationStatementPageBase() {
|
|||||||
// computed states
|
// computed states
|
||||||
firstDayOfWeek,
|
firstDayOfWeek,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
currentTimezoneOffsetMinutes,
|
|
||||||
defaultCurrency,
|
defaultCurrency,
|
||||||
allChartTypes,
|
allChartTypes,
|
||||||
allDateAggregationTypes,
|
allDateAggregationTypes,
|
||||||
@@ -303,6 +309,7 @@ export function useReconciliationStatementPageBase() {
|
|||||||
getDisplayDateTime,
|
getDisplayDateTime,
|
||||||
getDisplayDate,
|
getDisplayDate,
|
||||||
getDisplayTime,
|
getDisplayTime,
|
||||||
|
isSameAsDefaultTimezoneOffsetMinutes,
|
||||||
getDisplayTimezone,
|
getDisplayTimezone,
|
||||||
getDisplaySourceAmount,
|
getDisplaySourceAmount,
|
||||||
getDisplayDestinationAmount,
|
getDisplayDestinationAmount,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { CategoryType } from '@/core/category.ts';
|
|||||||
import type { Account } from '@/models/account.ts';
|
import type { Account } from '@/models/account.ts';
|
||||||
|
|
||||||
import { isObjectEmpty } from '@/lib/common.ts';
|
import { isObjectEmpty } from '@/lib/common.ts';
|
||||||
|
import { getCurrentUnixTime } from '@/lib/datetime.ts';
|
||||||
|
|
||||||
export function useAppSettingPageBase() {
|
export function useAppSettingPageBase() {
|
||||||
const { tt, getAllTimezones, getAllTimezoneTypesUsedForStatistics, getAllCurrencySortingTypes, setTimeZone } = useI18n();
|
const { tt, getAllTimezones, getAllTimezoneTypesUsedForStatistics, getAllCurrencySortingTypes, setTimeZone } = useI18n();
|
||||||
@@ -37,7 +38,7 @@ export function useAppSettingPageBase() {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
const allTimezones = computed<LocalizedTimezoneInfo[]>(() => getAllTimezones(true));
|
const allTimezones = computed<LocalizedTimezoneInfo[]>(() => getAllTimezones(getCurrentUnixTime(), true));
|
||||||
const allTimezoneTypesUsedForStatistics = computed<TypeAndDisplayName[]>(() => getAllTimezoneTypesUsedForStatistics());
|
const allTimezoneTypesUsedForStatistics = computed<TypeAndDisplayName[]>(() => getAllTimezoneTypesUsedForStatistics());
|
||||||
const allCurrencySortingTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencySortingTypes());
|
const allCurrencySortingTypes = computed<TypeAndDisplayName[]>(() => getAllCurrencySortingTypes());
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ import type {
|
|||||||
} from '@/models/transaction.ts';
|
} from '@/models/transaction.ts';
|
||||||
|
|
||||||
import { limitText, findNameByType, findDisplayNameByType } from '@/lib/common.ts';
|
import { limitText, findNameByType, findDisplayNameByType } from '@/lib/common.ts';
|
||||||
import { getYearMonthFirstUnixTime, getYearMonthLastUnixTime } from '@/lib/datetime.ts';
|
import {
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
|
getYearMonthFirstUnixTime,
|
||||||
|
getYearMonthLastUnixTime
|
||||||
|
} from '@/lib/datetime.ts';
|
||||||
import { getDisplayColor, getCategoryDisplayColor, getAccountDisplayColor } from '@/lib/color.ts';
|
import { getDisplayColor, getCategoryDisplayColor, getAccountDisplayColor } from '@/lib/color.ts';
|
||||||
|
|
||||||
export function useStatisticsTransactionPageBase() {
|
export function useStatisticsTransactionPageBase() {
|
||||||
@@ -37,8 +41,8 @@ export function useStatisticsTransactionPageBase() {
|
|||||||
getAllDateRanges,
|
getAllDateRanges,
|
||||||
getAllStatisticsSortingTypes,
|
getAllStatisticsSortingTypes,
|
||||||
getAllStatisticsDateAggregationTypes,
|
getAllStatisticsDateAggregationTypes,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
formatUnixTimeToGregorianLikeLongYearMonth,
|
formatDateTimeToGregorianLikeLongYearMonth,
|
||||||
formatDateRange,
|
formatDateRange,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
@@ -88,11 +92,11 @@ export function useStatisticsTransactionPageBase() {
|
|||||||
|
|
||||||
const queryStartTime = computed<string>(() => {
|
const queryStartTime = computed<string>(() => {
|
||||||
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
||||||
return formatUnixTimeToLongDateTime(query.value.categoricalChartStartTime);
|
return formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.categoricalChartStartTime));
|
||||||
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
|
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
|
||||||
return formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthFirstUnixTime(query.value.trendChartStartYearMonth));
|
return formatDateTimeToGregorianLikeLongYearMonth(parseDateTimeFromUnixTime(getYearMonthFirstUnixTime(query.value.trendChartStartYearMonth)));
|
||||||
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
|
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
|
||||||
return formatUnixTimeToLongDateTime(query.value.assetTrendsChartStartTime);
|
return formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.assetTrendsChartStartTime));
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -100,11 +104,11 @@ export function useStatisticsTransactionPageBase() {
|
|||||||
|
|
||||||
const queryEndTime = computed<string>(() => {
|
const queryEndTime = computed<string>(() => {
|
||||||
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis) {
|
||||||
return formatUnixTimeToLongDateTime(query.value.categoricalChartEndTime);
|
return formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.categoricalChartEndTime));
|
||||||
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
|
} else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis) {
|
||||||
return formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthLastUnixTime(query.value.trendChartEndYearMonth));
|
return formatDateTimeToGregorianLikeLongYearMonth(parseDateTimeFromUnixTime(getYearMonthLastUnixTime(query.value.trendChartEndYearMonth)));
|
||||||
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
|
} else if (analysisType.value === StatisticsAnalysisType.AssetTrends) {
|
||||||
return formatUnixTimeToLongDateTime(query.value.assetTrendsChartEndTime);
|
return formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.assetTrendsChartEndTime));
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ import {
|
|||||||
import {
|
import {
|
||||||
getUtcOffsetByUtcOffsetMinutes,
|
getUtcOffsetByUtcOffsetMinutes,
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
|
getSameDateTimeWithCurrentTimezone,
|
||||||
|
parseDateTimeFromUnixTimeWithBrowserTimezone,
|
||||||
getCurrentUnixTime
|
getCurrentUnixTime
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
@@ -92,14 +94,14 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
const transaction = ref<Transaction | TransactionTemplate>(createNewTransactionModel(transactionDefaultType));
|
const transaction = ref<Transaction | TransactionTemplate>(createNewTransactionModel(transactionDefaultType));
|
||||||
|
|
||||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||||
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
|
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(transaction.value.time));
|
||||||
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
|
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
|
||||||
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
||||||
const defaultAccountId = computed<string>(() => userStore.currentUserDefaultAccountId);
|
const defaultAccountId = computed<string>(() => userStore.currentUserDefaultAccountId);
|
||||||
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
||||||
const coordinateDisplayType = computed<number>(() => userStore.currentUserCoordinateDisplayType);
|
const coordinateDisplayType = computed<number>(() => userStore.currentUserCoordinateDisplayType);
|
||||||
|
|
||||||
const allTimezones = computed<LocalizedTimezoneInfo[]>(() => getAllTimezones(true));
|
const allTimezones = computed<LocalizedTimezoneInfo[]>(() => getAllTimezones(transaction.value.time, true));
|
||||||
const allAccounts = computed<Account[]>(() => accountsStore.allPlainAccounts);
|
const allAccounts = computed<Account[]>(() => accountsStore.allPlainAccounts);
|
||||||
const allVisibleAccounts = computed<Account[]>(() => accountsStore.allVisiblePlainAccounts);
|
const allVisibleAccounts = computed<Account[]>(() => accountsStore.allVisiblePlainAccounts);
|
||||||
const allAccountsMap = computed<Record<string, Account>>(() => accountsStore.allAccountsMap);
|
const allAccountsMap = computed<Record<string, Account>>(() => accountsStore.allAccountsMap);
|
||||||
@@ -274,7 +276,7 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
});
|
});
|
||||||
|
|
||||||
const transactionTimezoneTimeDifference = computed<string>(() => {
|
const transactionTimezoneTimeDifference = computed<string>(() => {
|
||||||
return getTimezoneDifferenceDisplayText(transaction.value.utcOffset);
|
return getTimezoneDifferenceDisplayText(transaction.value.time, transaction.value.utcOffset);
|
||||||
});
|
});
|
||||||
|
|
||||||
const geoLocationStatusInfo = computed<string>(() => {
|
const geoLocationStatusInfo = computed<string>(() => {
|
||||||
@@ -331,8 +333,12 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
return !!inputEmptyProblemMessage.value;
|
return !!inputEmptyProblemMessage.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getCurrentUnixTimeForNewTransaction(): number {
|
||||||
|
return getSameDateTimeWithCurrentTimezone(parseDateTimeFromUnixTimeWithBrowserTimezone(getCurrentUnixTime())).getUnixTime();
|
||||||
|
}
|
||||||
|
|
||||||
function createNewTransactionModel(transactionType?: number): Transaction | TransactionTemplate {
|
function createNewTransactionModel(transactionType?: number): Transaction | TransactionTemplate {
|
||||||
const now: number = getCurrentUnixTime();
|
const now: number = getCurrentUnixTimeForNewTransaction();
|
||||||
const currentTimezone: string = settingsStore.appSettings.timeZone;
|
const currentTimezone: string = settingsStore.appSettings.timeZone;
|
||||||
|
|
||||||
let defaultType: TransactionType = TransactionType.Expense;
|
let defaultType: TransactionType = TransactionType.Expense;
|
||||||
@@ -343,7 +349,7 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
defaultType = TransactionType.Transfer;
|
defaultType = TransactionType.Transfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
let newTransaction: Transaction | TransactionTemplate = Transaction.createNewTransaction(defaultType, now, currentTimezone, getTimezoneOffsetMinutes(currentTimezone));
|
let newTransaction: Transaction | TransactionTemplate = Transaction.createNewTransaction(defaultType, now, currentTimezone, getTimezoneOffsetMinutes(now, currentTimezone));
|
||||||
|
|
||||||
if (type === TransactionEditPageType.Template) {
|
if (type === TransactionEditPageType.Template) {
|
||||||
newTransaction = TransactionTemplate.createNewTransactionTemplate(newTransaction);
|
newTransaction = TransactionTemplate.createNewTransactionTemplate(newTransaction);
|
||||||
@@ -352,6 +358,25 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
return newTransaction;
|
return newTransaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTransactionTime(newTime: number): void {
|
||||||
|
transaction.value.time = newTime;
|
||||||
|
updateTransactionTimezone(transaction.value.timeZone ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTransactionTimezone(timezoneName: string): void {
|
||||||
|
const oldUtcOffset = transaction.value.utcOffset;
|
||||||
|
|
||||||
|
for (const timezone of allTimezones.value) {
|
||||||
|
if (timezone.name === timezoneName) {
|
||||||
|
transaction.value.timeZone = timezone.name;
|
||||||
|
transaction.value.utcOffset = timezone.utcOffsetMinutes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.value.time = transaction.value.time - (transaction.value.utcOffset - oldUtcOffset) * 60;
|
||||||
|
}
|
||||||
|
|
||||||
function swapTransactionData(swapAccount: boolean, swapAmount: boolean): void {
|
function swapTransactionData(swapAccount: boolean, swapAmount: boolean): void {
|
||||||
if (swapAccount) {
|
if (swapAccount) {
|
||||||
const oldSourceAccountId = transaction.value.sourceAccountId;
|
const oldSourceAccountId = transaction.value.sourceAccountId;
|
||||||
@@ -396,15 +421,6 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => transaction.value.timeZone, (newValue) => {
|
|
||||||
for (const timezone of allTimezones.value) {
|
|
||||||
if (timezone.name === newValue) {
|
|
||||||
transaction.value.utcOffset = timezone.utcOffsetMinutes;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// constants
|
// constants
|
||||||
isSupportGeoLocation,
|
isSupportGeoLocation,
|
||||||
@@ -460,6 +476,8 @@ export function useTransactionEditPageBase(type: TransactionEditPageType, initMo
|
|||||||
inputIsEmpty,
|
inputIsEmpty,
|
||||||
// functions
|
// functions
|
||||||
createNewTransactionModel,
|
createNewTransactionModel,
|
||||||
|
updateTransactionTime,
|
||||||
|
updateTransactionTimezone,
|
||||||
swapTransactionData,
|
swapTransactionData,
|
||||||
getDisplayAmount,
|
getDisplayAmount,
|
||||||
getTransactionPictureUrl
|
getTransactionPictureUrl
|
||||||
|
|||||||
@@ -23,13 +23,12 @@ import { type Transaction, TransactionTagFilter } from '@/models/transaction.ts'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
getUtcOffsetByUtcOffsetMinutes,
|
getUtcOffsetByUtcOffsetMinutes,
|
||||||
getTimezoneOffset,
|
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getLocalDatetimeFromUnixTime,
|
getLocalDatetimeFromUnixTime,
|
||||||
getDummyUnixTimeForLocalUsage,
|
getSameDateTimeWithBrowserTimezone,
|
||||||
getCurrentDateTime,
|
getCurrentDateTime,
|
||||||
parseDateTimeFromUnixTime,
|
parseDateTimeFromUnixTime,
|
||||||
|
parseDateTimeFromUnixTimeWithTimezoneOffset,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
isDateRangeMatchOneMonth
|
isDateRangeMatchOneMonth
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
@@ -76,10 +75,10 @@ export function useTransactionListPageBase() {
|
|||||||
tt,
|
tt,
|
||||||
getAllDateRanges,
|
getAllDateRanges,
|
||||||
getCurrentNumeralSystemType,
|
getCurrentNumeralSystemType,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
formatUnixTimeToLongDate,
|
formatDateTimeToLongDate,
|
||||||
formatUnixTimeToShortTime,
|
formatDateTimeToShortTime,
|
||||||
formatUnixTimeToGregorianLikeLongYearMonth,
|
formatDateTimeToGregorianLikeLongYearMonth,
|
||||||
formatDateRange,
|
formatDateRange,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
@@ -98,7 +97,6 @@ export function useTransactionListPageBase() {
|
|||||||
const currentCalendarDate = ref<TextualYearMonthDay | ''>('');
|
const currentCalendarDate = ref<TextualYearMonthDay | ''>('');
|
||||||
|
|
||||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||||
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
|
|
||||||
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
const firstDayOfWeek = computed<WeekDayValue>(() => userStore.currentUserFirstDayOfWeek);
|
||||||
const fiscalYearStart = computed<number>(() => userStore.currentUserFiscalYearStart);
|
const fiscalYearStart = computed<number>(() => userStore.currentUserFiscalYearStart);
|
||||||
const defaultCurrency = computed<string>(() => getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccountsMap.value, queryAllFilterAccountIds.value, userStore.currentUserDefaultCurrency));
|
const defaultCurrency = computed<string>(() => getUnifiedSelectedAccountsCurrencyOrDefaultCurrency(allAccountsMap.value, queryAllFilterAccountIds.value, userStore.currentUserDefaultCurrency));
|
||||||
@@ -161,8 +159,8 @@ export function useTransactionListPageBase() {
|
|||||||
|
|
||||||
return formatDateRange(query.value.dateType, query.value.minTime, query.value.maxTime);
|
return formatDateRange(query.value.dateType, query.value.minTime, query.value.maxTime);
|
||||||
});
|
});
|
||||||
const queryMinTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.minTime));
|
const queryMinTime = computed<string>(() => formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.minTime)));
|
||||||
const queryMaxTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.maxTime));
|
const queryMaxTime = computed<string>(() => formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.maxTime)));
|
||||||
const queryMonthlyData = computed<boolean>(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime));
|
const queryMonthlyData = computed<boolean>(() => isDateRangeMatchOneMonth(query.value.minTime, query.value.maxTime));
|
||||||
const queryMonth = computed<Year0BasedMonth>(() => {
|
const queryMonth = computed<Year0BasedMonth>(() => {
|
||||||
if (!query.value.minTime || !query.value.maxTime) {
|
if (!query.value.minTime || !query.value.maxTime) {
|
||||||
@@ -235,8 +233,8 @@ export function useTransactionListPageBase() {
|
|||||||
return displayAmount.join(' ~ ');
|
return displayAmount.join(' ~ ');
|
||||||
});
|
});
|
||||||
|
|
||||||
const transactionCalendarMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(query.value.minTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
|
const transactionCalendarMinDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(parseDateTimeFromUnixTime(query.value.minTime)).getUnixTime()));
|
||||||
const transactionCalendarMaxDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getDummyUnixTimeForLocalUsage(query.value.maxTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes())));
|
const transactionCalendarMaxDate = computed<Date>(() => getLocalDatetimeFromUnixTime(getSameDateTimeWithBrowserTimezone(parseDateTimeFromUnixTime(query.value.maxTime)).getUnixTime()));
|
||||||
|
|
||||||
const currentMonthTransactionData = computed<TransactionMonthList | null>(() => {
|
const currentMonthTransactionData = computed<TransactionMonthList | null>(() => {
|
||||||
const allTransactions = transactionsStore.transactions;
|
const allTransactions = transactionsStore.transactions;
|
||||||
@@ -284,6 +282,10 @@ export function useTransactionListPageBase() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSameAsDefaultTimezoneOffsetMinutes(transaction: Transaction): boolean {
|
||||||
|
return transaction.utcOffset === getTimezoneOffsetMinutes(transaction.time);
|
||||||
|
}
|
||||||
|
|
||||||
function formatAmount(amount: number, hideAmount: boolean, currencyCode: string): string {
|
function formatAmount(amount: number, hideAmount: boolean, currencyCode: string): string {
|
||||||
if (hideAmount) {
|
if (hideAmount) {
|
||||||
return formatAmountToLocalizedNumeralsWithCurrency(DISPLAY_HIDDEN_AMOUNT, currencyCode);
|
return formatAmountToLocalizedNumeralsWithCurrency(DISPLAY_HIDDEN_AMOUNT, currencyCode);
|
||||||
@@ -293,15 +295,18 @@ export function useTransactionListPageBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTime(transaction: Transaction): string {
|
function getDisplayTime(transaction: Transaction): string {
|
||||||
return formatUnixTimeToShortTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
|
return formatDateTimeToShortTime(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayLongDate(transaction: Transaction): string {
|
function getDisplayLongDate(transaction: Transaction): string {
|
||||||
return formatUnixTimeToLongDate(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
|
return formatDateTimeToLongDate(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayLongYearMonth(transactionMonthList: TransactionMonthList): string {
|
function getDisplayLongYearMonth(transactionMonthList: TransactionMonthList): string {
|
||||||
return formatUnixTimeToGregorianLikeLongYearMonth(getYearMonthFirstUnixTime(transactionMonthList.yearDashMonth));
|
const yearMonthDateTime = parseDateTimeFromUnixTime(getYearMonthFirstUnixTime(transactionMonthList.yearDashMonth));
|
||||||
|
return formatDateTimeToGregorianLikeLongYearMonth(yearMonthDateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTimezone(transaction: Transaction): string {
|
function getDisplayTimezone(transaction: Transaction): string {
|
||||||
@@ -310,8 +315,10 @@ export function useTransactionListPageBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTimeInDefaultTimezone(transaction: Transaction): string {
|
function getDisplayTimeInDefaultTimezone(transaction: Transaction): string {
|
||||||
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(settingsStore.appSettings.timeZone));
|
const timezoneOffsetMinutes = getTimezoneOffsetMinutes(transaction.time);
|
||||||
return `${formatUnixTimeToLongDateTime(transaction.time)} (UTC${utcOffset})`;
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, timezoneOffsetMinutes);
|
||||||
|
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getUtcOffsetByUtcOffsetMinutes(timezoneOffsetMinutes));
|
||||||
|
return `${formatDateTimeToLongDateTime(dateTime)} (UTC${utcOffset})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayAmount(transaction: Transaction): string {
|
function getDisplayAmount(transaction: Transaction): string {
|
||||||
@@ -372,7 +379,6 @@ export function useTransactionListPageBase() {
|
|||||||
customMaxDatetime,
|
customMaxDatetime,
|
||||||
currentCalendarDate,
|
currentCalendarDate,
|
||||||
// computed states
|
// computed states
|
||||||
currentTimezoneOffsetMinutes,
|
|
||||||
firstDayOfWeek,
|
firstDayOfWeek,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
defaultCurrency,
|
defaultCurrency,
|
||||||
@@ -410,6 +416,7 @@ export function useTransactionListPageBase() {
|
|||||||
canAddTransaction,
|
canAddTransaction,
|
||||||
// functions
|
// functions
|
||||||
hasSubCategoryInQuery,
|
hasSubCategoryInQuery,
|
||||||
|
isSameAsDefaultTimezoneOffsetMinutes,
|
||||||
getDisplayTime,
|
getDisplayTime,
|
||||||
getDisplayLongDate,
|
getDisplayLongDate,
|
||||||
getDisplayLongYearMonth,
|
getDisplayLongYearMonth,
|
||||||
|
|||||||
@@ -202,12 +202,10 @@ import { useAccountsStore } from '@/stores/account.ts';
|
|||||||
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
import { useTransactionCategoriesStore } from '@/stores/transactionCategory.ts';
|
||||||
import { useOverviewStore } from '@/stores/overview.ts';
|
import { useOverviewStore } from '@/stores/overview.ts';
|
||||||
|
|
||||||
import { entries } from '@/core/base.ts';
|
|
||||||
import { type NumeralSystem } from '@/core/numeral.ts';
|
import { type NumeralSystem } from '@/core/numeral.ts';
|
||||||
import { DateRange } from '@/core/datetime.ts';
|
import { DateRange } from '@/core/datetime.ts';
|
||||||
import { ThemeType } from '@/core/theme.ts';
|
import { ThemeType } from '@/core/theme.ts';
|
||||||
import {
|
import {
|
||||||
type TransactionAmountsRequestType,
|
|
||||||
type TransactionMonthlyIncomeAndExpenseData,
|
type TransactionMonthlyIncomeAndExpenseData,
|
||||||
LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES
|
LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES
|
||||||
} from '@/models/transaction.ts';
|
} from '@/models/transaction.ts';
|
||||||
@@ -280,8 +278,7 @@ const monthlyIncomeAndExpenseData = computed<TransactionMonthlyIncomeAndExpenseD
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [type, monthDiff] of entries(LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES)) {
|
for (const amountRequestType of LATEST_12MONTHS_TRANSACTION_AMOUNTS_REQUEST_TYPES) {
|
||||||
const amountRequestType = type as TransactionAmountsRequestType;
|
|
||||||
const dateRange = overviewStore.transactionDataRange[amountRequestType];
|
const dateRange = overviewStore.transactionDataRange[amountRequestType];
|
||||||
|
|
||||||
if (!dateRange) {
|
if (!dateRange) {
|
||||||
@@ -292,7 +289,6 @@ const monthlyIncomeAndExpenseData = computed<TransactionMonthlyIncomeAndExpenseD
|
|||||||
|
|
||||||
data.push({
|
data.push({
|
||||||
monthStartTime: dateRange.startTime,
|
monthStartTime: dateRange.startTime,
|
||||||
monthsBeforeCurrentMonth: monthDiff,
|
|
||||||
incomeAmount: item?.incomeAmount || 0,
|
incomeAmount: item?.incomeAmount || 0,
|
||||||
expenseAmount: item?.expenseAmount || 0,
|
expenseAmount: item?.expenseAmount || 0,
|
||||||
incompleteIncomeAmount: item ? item.incompleteIncomeAmount : true,
|
incompleteIncomeAmount: item ? item.incompleteIncomeAmount : true,
|
||||||
|
|||||||
@@ -145,7 +145,9 @@
|
|||||||
<date-time-select
|
<date-time-select
|
||||||
:disabled="loading || submitting"
|
:disabled="loading || submitting"
|
||||||
:label="tt('Balance Time')"
|
:label="tt('Balance Time')"
|
||||||
v-model="selectedAccount.balanceTime"
|
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(selectedAccount)"
|
||||||
|
:model-value="selectedAccount.balanceTime"
|
||||||
|
@update:model-value="updateAccountBalanceTime(selectedAccount, $event)"
|
||||||
@error="onShowDateTimeError" />
|
@error="onShowDateTimeError" />
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="12">
|
<v-col cols="12" md="12">
|
||||||
@@ -210,7 +212,6 @@ import { ALL_ACCOUNT_COLORS } from '@/consts/color.ts';
|
|||||||
import { Account } from '@/models/account.ts';
|
import { Account } from '@/models/account.ts';
|
||||||
|
|
||||||
import { isNumber } from '@/lib/common.ts';
|
import { isNumber } from '@/lib/common.ts';
|
||||||
import { getCurrentUnixTime } from '@/lib/datetime.ts';
|
|
||||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -242,6 +243,9 @@ const {
|
|||||||
allAccountTypes,
|
allAccountTypes,
|
||||||
allAvailableMonthDays,
|
allAvailableMonthDays,
|
||||||
isAccountSupportCreditCardStatementDate,
|
isAccountSupportCreditCardStatementDate,
|
||||||
|
getCurrentUnixTimeForNewAccount,
|
||||||
|
getDefaultTimezoneOffsetMinutes,
|
||||||
|
updateAccountBalanceTime,
|
||||||
isNewAccount,
|
isNewAccount,
|
||||||
addSubAccount,
|
addSubAccount,
|
||||||
setAccount
|
setAccount
|
||||||
@@ -275,7 +279,7 @@ const accountAmountTitle = computed<string>(() => {
|
|||||||
|
|
||||||
const isAccountModified = computed<boolean>(() => {
|
const isAccountModified = computed<boolean>(() => {
|
||||||
if (!editAccountId.value) {
|
if (!editAccountId.value) {
|
||||||
return !account.value.equals(Account.createNewAccount(userStore.currentUserDefaultCurrency, account.value.balanceTime ?? getCurrentUnixTime()));
|
return !account.value.equals(Account.createNewAccount(userStore.currentUserDefaultCurrency, account.value.balanceTime ?? getCurrentUnixTimeForNewAccount()));
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -289,7 +293,7 @@ function open(options?: { id?: string, currentAccount?: Account, category?: numb
|
|||||||
loading.value = true;
|
loading.value = true;
|
||||||
submitting.value = false;
|
submitting.value = false;
|
||||||
|
|
||||||
const newAccount = Account.createNewAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTime());
|
const newAccount = Account.createNewAccount(userStore.currentUserDefaultCurrency, getCurrentUnixTimeForNewAccount());
|
||||||
account.value.fillFrom(newAccount);
|
account.value.fillFrom(newAccount);
|
||||||
subAccounts.value = [];
|
subAccounts.value = [];
|
||||||
currentAccountIndex.value = -1;
|
currentAccountIndex.value = -1;
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
<template #item.time="{ item }">
|
<template #item.time="{ item }">
|
||||||
<span>{{ getDisplayDateTime(item) }}</span>
|
<span>{{ getDisplayDateTime(item) }}</span>
|
||||||
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
|
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
|
||||||
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
|
v-if="!isSameAsDefaultTimezoneOffsetMinutes(item)">{{ getDisplayTimezone(item) }}</v-chip>
|
||||||
</template>
|
</template>
|
||||||
<template #item.type="{ item }">
|
<template #item.type="{ item }">
|
||||||
<v-chip label variant="outlined" size="x-small"
|
<v-chip label variant="outlined" size="x-small"
|
||||||
@@ -323,7 +323,6 @@ const {
|
|||||||
startTime,
|
startTime,
|
||||||
endTime,
|
endTime,
|
||||||
reconciliationStatements,
|
reconciliationStatements,
|
||||||
currentTimezoneOffsetMinutes,
|
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
allChartTypes,
|
allChartTypes,
|
||||||
allDateAggregationTypes,
|
allDateAggregationTypes,
|
||||||
@@ -341,6 +340,7 @@ const {
|
|||||||
setReconciliationStatements,
|
setReconciliationStatements,
|
||||||
getDisplayTransactionType,
|
getDisplayTransactionType,
|
||||||
getDisplayDateTime,
|
getDisplayDateTime,
|
||||||
|
isSameAsDefaultTimezoneOffsetMinutes,
|
||||||
getDisplayTimezone,
|
getDisplayTimezone,
|
||||||
getDisplaySourceAmount,
|
getDisplaySourceAmount,
|
||||||
getDisplayDestinationAmount,
|
getDisplayDestinationAmount,
|
||||||
|
|||||||
@@ -151,9 +151,10 @@ import {
|
|||||||
} from '@/models/transaction.ts';
|
} from '@/models/transaction.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
getShiftedDateRangeAndDateType,
|
getShiftedDateRangeAndDateType,
|
||||||
getDateTypeByDateRange,
|
getDateTypeByDateRange,
|
||||||
getDateRangeByDateType,
|
getDateRangeByDateType
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -188,7 +189,7 @@ const {
|
|||||||
tt,
|
tt,
|
||||||
getAllDateRanges,
|
getAllDateRanges,
|
||||||
getCurrentNumeralSystemType,
|
getCurrentNumeralSystemType,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
formatDateRange
|
formatDateRange
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -221,8 +222,8 @@ const filteredTransactions = computed<TransactionInsightDataItem[]>(() => explor
|
|||||||
const allDateRanges = computed<LocalizedDateRange[]>(() => getAllDateRanges(DateRangeScene.InsightsExplore, true));
|
const allDateRanges = computed<LocalizedDateRange[]>(() => getAllDateRanges(DateRangeScene.InsightsExplore, true));
|
||||||
const canShiftDateRange = computed<boolean>(() => query.value.dateRangeType !== DateRange.All.type);
|
const canShiftDateRange = computed<boolean>(() => query.value.dateRangeType !== DateRange.All.type);
|
||||||
const displayQueryDateRangeName = computed<string>(() => formatDateRange(query.value.dateRangeType, query.value.startTime, query.value.endTime));
|
const displayQueryDateRangeName = computed<string>(() => formatDateRange(query.value.dateRangeType, query.value.startTime, query.value.endTime));
|
||||||
const displayQueryStartTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.startTime));
|
const displayQueryStartTime = computed<string>(() => formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.startTime)));
|
||||||
const displayQueryEndTime = computed<string>(() => formatUnixTimeToLongDateTime(query.value.endTime));
|
const displayQueryEndTime = computed<string>(() => formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(query.value.endTime)));
|
||||||
|
|
||||||
const allTabs = computed<{ name: string, value: ExplorePageTabType }[]>(() => {
|
const allTabs = computed<{ name: string, value: ExplorePageTabType }[]>(() => {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<template #item.time="{ item }">
|
<template #item.time="{ item }">
|
||||||
<span>{{ getDisplayDateTime(item) }}</span>
|
<span>{{ getDisplayDateTime(item) }}</span>
|
||||||
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
|
<v-chip class="ms-1" variant="flat" color="secondary" size="x-small"
|
||||||
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
|
v-if="!isSameAsDefaultTimezoneOffsetMinutes(item)">{{ getDisplayTimezone(item) }}</v-chip>
|
||||||
</template>
|
</template>
|
||||||
<template #item.type="{ item }">
|
<template #item.type="{ item }">
|
||||||
<v-chip label variant="outlined" size="x-small"
|
<v-chip label variant="outlined" size="x-small"
|
||||||
@@ -76,7 +76,6 @@ import { ref, computed } from 'vue';
|
|||||||
|
|
||||||
import { useI18n } from '@/locales/helpers.ts';
|
import { useI18n } from '@/locales/helpers.ts';
|
||||||
|
|
||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
|
||||||
import { useUserStore } from '@/stores/user.ts';
|
import { useUserStore } from '@/stores/user.ts';
|
||||||
import { useExploresStore } from '@/stores/explore.ts';
|
import { useExploresStore } from '@/stores/explore.ts';
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
getUtcOffsetByUtcOffsetMinutes,
|
getUtcOffsetByUtcOffsetMinutes,
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
parseDateTimeFromUnixTime
|
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -109,19 +108,17 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
formatUnixTimeToGregorianDefaultDateTime,
|
formatDateTimeToGregorianDefaultDateTime,
|
||||||
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const exploresStore = useExploresStore();
|
const exploresStore = useExploresStore();
|
||||||
|
|
||||||
const currentPage = ref<number>(1);
|
const currentPage = ref<number>(1);
|
||||||
|
|
||||||
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
|
|
||||||
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
||||||
|
|
||||||
const filteredTransactions = computed<TransactionInsightDataItem[]>(() => exploresStore.filteredTransactions);
|
const filteredTransactions = computed<TransactionInsightDataItem[]>(() => exploresStore.filteredTransactions);
|
||||||
@@ -163,7 +160,12 @@ const dataTableHeaders = computed<object[]>(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getDisplayDateTime(transaction: TransactionInsightDataItem): string {
|
function getDisplayDateTime(transaction: TransactionInsightDataItem): string {
|
||||||
return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
|
return formatDateTimeToLongDateTime(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameAsDefaultTimezoneOffsetMinutes(transaction: TransactionInsightDataItem): boolean {
|
||||||
|
return transaction.utcOffset === getTimezoneOffsetMinutes(transaction.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTimezone(transaction: TransactionInsightDataItem): string {
|
function getDisplayTimezone(transaction: TransactionInsightDataItem): string {
|
||||||
@@ -234,7 +236,7 @@ function buildExportResults(): { headers: string[], data: string[][] } | undefin
|
|||||||
],
|
],
|
||||||
data: filteredTransactions.value
|
data: filteredTransactions.value
|
||||||
.map(transaction => {
|
.map(transaction => {
|
||||||
const transactionTime = parseDateTimeFromUnixTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value).getUnixTime();
|
const transactionTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset);
|
||||||
const type = getDisplayTransactionType(transaction);
|
const type = getDisplayTransactionType(transaction);
|
||||||
|
|
||||||
let categoryName = transaction.secondaryCategoryName;
|
let categoryName = transaction.secondaryCategoryName;
|
||||||
@@ -254,7 +256,7 @@ function buildExportResults(): { headers: string[], data: string[][] } | undefin
|
|||||||
const description = transaction.comment || '';
|
const description = transaction.comment || '';
|
||||||
|
|
||||||
return [
|
return [
|
||||||
formatUnixTimeToGregorianDefaultDateTime(transactionTime),
|
formatDateTimeToGregorianDefaultDateTime(transactionTime),
|
||||||
type,
|
type,
|
||||||
categoryName,
|
categoryName,
|
||||||
displayAmount,
|
displayAmount,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import { DISPLAY_HIDDEN_AMOUNT, INCOMPLETE_AMOUNT_SUFFIX } from '@/consts/numera
|
|||||||
|
|
||||||
import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts';
|
import { type TransactionMonthlyIncomeAndExpenseData } from '@/models/transaction.ts';
|
||||||
|
|
||||||
import { getUnixTimeBeforeUnixTime, getThisMonthFirstUnixTime } from '@/lib/datetime.ts';
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
import { getExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { getExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
|
|
||||||
export interface MonthlyIncomeAndExpenseCardClickEvent {
|
export interface MonthlyIncomeAndExpenseCardClickEvent {
|
||||||
@@ -64,7 +64,7 @@ const emit = defineEmits<{
|
|||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
getCurrentLanguageTextDirection,
|
getCurrentLanguageTextDirection,
|
||||||
formatUnixTimeToGregorianLikeShortMonth,
|
formatDateTimeToGregorianLikeShortMonth,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -98,11 +98,9 @@ const chartOptions = computed<object>(() => {
|
|||||||
const expenseIncomeAmountColor = getExpenseAndIncomeAmountColor(userStore.currentUserExpenseAmountColor, userStore.currentUserIncomeAmountColor, props.isDarkMode);
|
const expenseIncomeAmountColor = getExpenseAndIncomeAmountColor(userStore.currentUserExpenseAmountColor, userStore.currentUserIncomeAmountColor, props.isDarkMode);
|
||||||
|
|
||||||
if (props.data) {
|
if (props.data) {
|
||||||
const currentMonthFirstUnixTime = getThisMonthFirstUnixTime();
|
|
||||||
|
|
||||||
for (const item of props.data) {
|
for (const item of props.data) {
|
||||||
const monthFirstUnixTime = getUnixTimeBeforeUnixTime(currentMonthFirstUnixTime, item.monthsBeforeCurrentMonth, 'months');
|
const monthStartDateTime = parseDateTimeFromUnixTime(item.monthStartTime);
|
||||||
const monthShortName = formatUnixTimeToGregorianLikeShortMonth(monthFirstUnixTime);
|
const monthShortName = formatDateTimeToGregorianLikeShortMonth(monthStartDateTime);
|
||||||
|
|
||||||
monthNames.push(monthShortName);
|
monthNames.push(monthShortName);
|
||||||
incomeAmounts.push(item.incomeAmount);
|
incomeAmounts.push(item.incomeAmount);
|
||||||
|
|||||||
@@ -534,8 +534,8 @@
|
|||||||
<td class="transaction-table-column-time">
|
<td class="transaction-table-column-time">
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<span>{{ getDisplayTime(transaction) }}</span>
|
<span>{{ getDisplayTime(transaction) }}</span>
|
||||||
<span class="text-caption" v-if="transaction.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(transaction) }}</span>
|
<span class="text-caption" v-if="!isSameAsDefaultTimezoneOffsetMinutes(transaction)">{{ getDisplayTimezone(transaction) }}</span>
|
||||||
<v-tooltip activator="parent" v-if="transaction.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimeInDefaultTimezone(transaction) }}</v-tooltip>
|
<v-tooltip activator="parent" v-if="!isSameAsDefaultTimezoneOffsetMinutes(transaction)">{{ getDisplayTimeInDefaultTimezone(transaction) }}</v-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="transaction-table-column-category">
|
<td class="transaction-table-column-category">
|
||||||
@@ -691,8 +691,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
getCurrentUnixTime,
|
getCurrentUnixTime,
|
||||||
parseDateTimeFromUnixTime,
|
parseDateTimeFromUnixTime,
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getActualUnixTimeForStore,
|
|
||||||
getDayFirstUnixTimeBySpecifiedUnixTime,
|
getDayFirstUnixTimeBySpecifiedUnixTime,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
getYearMonthLastUnixTime,
|
getYearMonthLastUnixTime,
|
||||||
@@ -775,7 +773,6 @@ const {
|
|||||||
customMinDatetime,
|
customMinDatetime,
|
||||||
customMaxDatetime,
|
customMaxDatetime,
|
||||||
currentCalendarDate,
|
currentCalendarDate,
|
||||||
currentTimezoneOffsetMinutes,
|
|
||||||
firstDayOfWeek,
|
firstDayOfWeek,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
defaultCurrency,
|
defaultCurrency,
|
||||||
@@ -809,6 +806,7 @@ const {
|
|||||||
transactionCalendarMaxDate,
|
transactionCalendarMaxDate,
|
||||||
currentMonthTransactionData,
|
currentMonthTransactionData,
|
||||||
hasSubCategoryInQuery,
|
hasSubCategoryInQuery,
|
||||||
|
isSameAsDefaultTimezoneOffsetMinutes,
|
||||||
canAddTransaction,
|
canAddTransaction,
|
||||||
getDisplayTime,
|
getDisplayTime,
|
||||||
getDisplayLongDate,
|
getDisplayLongDate,
|
||||||
@@ -1234,7 +1232,7 @@ function changePageType(type: number): void {
|
|||||||
function changeDateFilter(dateRange: TimeRangeAndDateType | number | null): void {
|
function changeDateFilter(dateRange: TimeRangeAndDateType | number | null): void {
|
||||||
if (dateRange === DateRange.Custom.type || (isObject(dateRange) && dateRange.dateType === DateRange.Custom.type && !dateRange.minTime && !dateRange.maxTime)) { // Custom
|
if (dateRange === DateRange.Custom.type || (isObject(dateRange) && dateRange.dateType === DateRange.Custom.type && !dateRange.minTime && !dateRange.maxTime)) { // Custom
|
||||||
if (!query.value.minTime || !query.value.maxTime) {
|
if (!query.value.minTime || !query.value.maxTime) {
|
||||||
customMaxDatetime.value = getActualUnixTimeForStore(getCurrentUnixTime(), currentTimezoneOffsetMinutes.value, getBrowserTimezoneOffsetMinutes());
|
customMaxDatetime.value = getCurrentUnixTime();
|
||||||
customMinDatetime.value = getDayFirstUnixTimeBySpecifiedUnixTime(customMaxDatetime.value);
|
customMinDatetime.value = getDayFirstUnixTimeBySpecifiedUnixTime(customMaxDatetime.value);
|
||||||
} else {
|
} else {
|
||||||
customMaxDatetime.value = query.value.maxTime;
|
customMaxDatetime.value = query.value.maxTime;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
<template #item.time="{ item }">
|
<template #item.time="{ item }">
|
||||||
<span>{{ getDisplayDateTime(item) }}</span>
|
<span>{{ getDisplayDateTime(item) }}</span>
|
||||||
<v-chip class="ms-1" variant="flat" color="grey" size="x-small"
|
<v-chip class="ms-1" variant="flat" color="grey" size="x-small"
|
||||||
v-if="item.utcOffset !== currentTimezoneOffsetMinutes">{{ getDisplayTimezone(item) }}</v-chip>
|
v-if="!isSameAsDefaultTimezoneOffsetMinutes(item)">{{ getDisplayTimezone(item) }}</v-chip>
|
||||||
</template>
|
</template>
|
||||||
<template #item.type="{ value }">
|
<template #item.type="{ value }">
|
||||||
<v-chip label color="secondary" variant="outlined" size="x-small" v-if="value === TransactionType.ModifyBalance">{{ tt('Modify Balance') }}</v-chip>
|
<v-chip label color="secondary" variant="outlined" size="x-small" v-if="value === TransactionType.ModifyBalance">{{ tt('Modify Balance') }}</v-chip>
|
||||||
@@ -427,7 +427,9 @@ import {
|
|||||||
} from '@/lib/common.ts';
|
} from '@/lib/common.ts';
|
||||||
import {
|
import {
|
||||||
getUtcOffsetByUtcOffsetMinutes,
|
getUtcOffsetByUtcOffsetMinutes,
|
||||||
getTimezoneOffsetMinutes
|
getTimezoneOffsetMinutes,
|
||||||
|
parseDateTimeFromUnixTime,
|
||||||
|
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
import { formatCoordinate } from '@/lib/coordinate.ts';
|
import { formatCoordinate } from '@/lib/coordinate.ts';
|
||||||
import {
|
import {
|
||||||
@@ -495,7 +497,7 @@ const props = defineProps<{
|
|||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
getCurrentNumeralSystemType,
|
getCurrentNumeralSystemType,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency,
|
formatAmountToLocalizedNumeralsWithCurrency,
|
||||||
getCategorizedAccountsWithDisplayBalance
|
getCategorizedAccountsWithDisplayBalance
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
@@ -536,7 +538,6 @@ const currentDescriptionFilterValue = ref<string | null>(null);
|
|||||||
|
|
||||||
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||||
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
|
const showAccountBalance = computed<boolean>(() => settingsStore.appSettings.showAccountBalance);
|
||||||
const currentTimezoneOffsetMinutes = computed<number>(() => getTimezoneOffsetMinutes(settingsStore.appSettings.timeZone));
|
|
||||||
|
|
||||||
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
const defaultCurrency = computed<string>(() => userStore.currentUserDefaultCurrency);
|
||||||
const coordinateDisplayType = computed<number>(() => userStore.currentUserCoordinateDisplayType);
|
const coordinateDisplayType = computed<number>(() => userStore.currentUserCoordinateDisplayType);
|
||||||
@@ -1129,8 +1130,8 @@ const displayFilterCustomDateRange = computed<string>(() => {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const minDisplayTime = formatUnixTimeToLongDateTime(filters.value.minDatetime);
|
const minDisplayTime = formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(filters.value.minDatetime));
|
||||||
const maxDisplayTime = formatUnixTimeToLongDateTime(filters.value.maxDatetime);
|
const maxDisplayTime = formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(filters.value.maxDatetime));
|
||||||
|
|
||||||
return `${minDisplayTime} - ${maxDisplayTime}`
|
return `${minDisplayTime} - ${maxDisplayTime}`
|
||||||
});
|
});
|
||||||
@@ -1272,7 +1273,12 @@ function isTagValid(tagIds: string[], tagIndex: number): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayDateTime(transaction: ImportTransaction): string {
|
function getDisplayDateTime(transaction: ImportTransaction): string {
|
||||||
return formatUnixTimeToLongDateTime(transaction.time, transaction.utcOffset, currentTimezoneOffsetMinutes.value);
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.time, transaction.utcOffset)
|
||||||
|
return formatDateTimeToLongDateTime(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameAsDefaultTimezoneOffsetMinutes(transaction: ImportTransaction): boolean {
|
||||||
|
return transaction.utcOffset === getTimezoneOffsetMinutes(transaction.time);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayTimezone(transaction: ImportTransaction): string {
|
function getDisplayTimezone(transaction: ImportTransaction): string {
|
||||||
|
|||||||
+5
-2
@@ -54,7 +54,10 @@ import { KnownFileType } from '@/core/file.ts';
|
|||||||
import type { ImportTransactionRequest, ImportTransactionRequestItem } from '@/models/imported_transaction.ts';
|
import type { ImportTransactionRequest, ImportTransactionRequestItem } from '@/models/imported_transaction.ts';
|
||||||
|
|
||||||
import { isDefined } from '@/lib/common.ts';
|
import { isDefined } from '@/lib/common.ts';
|
||||||
import { getBrowserTimezoneOffsetMinutes } from '@/lib/datetime.ts';
|
import {
|
||||||
|
getTimezoneOffsetMinutes,
|
||||||
|
getCurrentUnixTime
|
||||||
|
} from '@/lib/datetime.ts';
|
||||||
import {
|
import {
|
||||||
openTextFileContent,
|
openTextFileContent,
|
||||||
startDownloadFile
|
startDownloadFile
|
||||||
@@ -121,7 +124,7 @@ function parse(row, index) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
time: row[0], // ${tt('sample.importTransactionCustomScript.fieldTimeDescription')}
|
time: row[0], // ${tt('sample.importTransactionCustomScript.fieldTimeDescription')}
|
||||||
utcOffset: '${getBrowserTimezoneOffsetMinutes()}', // ${tt('sample.importTransactionCustomScript.fieldUtcOffsetDescription')}
|
utcOffset: '${getTimezoneOffsetMinutes(getCurrentUnixTime())}', // ${tt('sample.importTransactionCustomScript.fieldUtcOffsetDescription')}
|
||||||
type: TransactionType.Expense, // ${tt('sample.importTransactionCustomScript.fieldTypeDescription')}
|
type: TransactionType.Expense, // ${tt('sample.importTransactionCustomScript.fieldTypeDescription')}
|
||||||
categoryName: row[4], // ${tt('sample.importTransactionCustomScript.fieldCategoryNameDescription')}
|
categoryName: row[4], // ${tt('sample.importTransactionCustomScript.fieldCategoryNameDescription')}
|
||||||
sourceAccountName: row[5], // ${tt('sample.importTransactionCustomScript.fieldSourceAccountNameDescription')}
|
sourceAccountName: row[5], // ${tt('sample.importTransactionCustomScript.fieldSourceAccountNameDescription')}
|
||||||
|
|||||||
@@ -250,7 +250,9 @@
|
|||||||
:readonly="mode === TransactionEditPageMode.View"
|
:readonly="mode === TransactionEditPageMode.View"
|
||||||
:disabled="loading || submitting || (mode === TransactionEditPageMode.Edit && transaction.type === TransactionType.ModifyBalance)"
|
:disabled="loading || submitting || (mode === TransactionEditPageMode.Edit && transaction.type === TransactionType.ModifyBalance)"
|
||||||
:label="tt('Transaction Time')"
|
:label="tt('Transaction Time')"
|
||||||
v-model="transaction.time"
|
:timezone-utc-offset="transaction.utcOffset"
|
||||||
|
:model-value="transaction.time"
|
||||||
|
@update:model-value="updateTransactionTime"
|
||||||
@error="onShowDateTimeError" />
|
@error="onShowDateTimeError" />
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="6" v-if="type === TransactionEditPageType.Template && transaction instanceof TransactionTemplate && transaction.templateType === TemplateType.Schedule.type">
|
<v-col cols="12" md="6" v-if="type === TransactionEditPageType.Template && transaction instanceof TransactionTemplate && transaction.templateType === TemplateType.Schedule.type">
|
||||||
@@ -274,7 +276,8 @@
|
|||||||
:placeholder="!transaction.timeZone && transaction.timeZone !== '' ? `(${transactionDisplayTimezone}) ${transactionTimezoneTimeDifference}` : tt('Timezone')"
|
:placeholder="!transaction.timeZone && transaction.timeZone !== '' ? `(${transactionDisplayTimezone}) ${transactionTimezoneTimeDifference}` : tt('Timezone')"
|
||||||
:items="allTimezones"
|
:items="allTimezones"
|
||||||
:no-data-text="tt('No results')"
|
:no-data-text="tt('No results')"
|
||||||
v-model="transaction.timeZone"
|
:model-value="transaction.timeZone"
|
||||||
|
@update:model-value="updateTransactionTimezone"
|
||||||
>
|
>
|
||||||
<template #selection="{ item }">
|
<template #selection="{ item }">
|
||||||
<span class="text-truncate" v-if="transaction.timeZone || transaction.timeZone === ''">
|
<span class="text-truncate" v-if="transaction.timeZone || transaction.timeZone === ''">
|
||||||
@@ -642,6 +645,8 @@ const {
|
|||||||
inputEmptyProblemMessage,
|
inputEmptyProblemMessage,
|
||||||
inputIsEmpty,
|
inputIsEmpty,
|
||||||
createNewTransactionModel,
|
createNewTransactionModel,
|
||||||
|
updateTransactionTime,
|
||||||
|
updateTransactionTimezone,
|
||||||
swapTransactionData,
|
swapTransactionData,
|
||||||
getTransactionPictureUrl
|
getTransactionPictureUrl
|
||||||
} = useTransactionEditPageBase(props.type);
|
} = useTransactionEditPageBase(props.type);
|
||||||
@@ -714,7 +719,7 @@ const isTransactionModified = computed<boolean>(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function setTransaction(newTransaction: Transaction | null, options: SetTransactionOptions, setContextData: boolean, convertContextTime: boolean): void {
|
function setTransaction(newTransaction: Transaction | null, options: SetTransactionOptions, setContextData: boolean): void {
|
||||||
setTransactionModelByTransaction(
|
setTransactionModelByTransaction(
|
||||||
transaction.value,
|
transaction.value,
|
||||||
newTransaction,
|
newTransaction,
|
||||||
@@ -735,8 +740,7 @@ function setTransaction(newTransaction: Transaction | null, options: SetTransact
|
|||||||
tagIds: options.tagIds,
|
tagIds: options.tagIds,
|
||||||
comment: options.comment
|
comment: options.comment
|
||||||
},
|
},
|
||||||
setContextData,
|
setContextData
|
||||||
convertContextTime
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,7 +762,7 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
|||||||
initTagIds.value = options.tagIds;
|
initTagIds.value = options.tagIds;
|
||||||
|
|
||||||
const newTransaction = createNewTransactionModel(options.type);
|
const newTransaction = createNewTransactionModel(options.type);
|
||||||
setTransaction(newTransaction, options, true, false);
|
setTransaction(newTransaction, options, true);
|
||||||
|
|
||||||
const promises: Promise<unknown>[] = [
|
const promises: Promise<unknown>[] = [
|
||||||
accountsStore.loadAllAccounts({ force: false }),
|
accountsStore.loadAllAccounts({ force: false }),
|
||||||
@@ -769,7 +773,7 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
|||||||
if (props.type === TransactionEditPageType.Transaction) {
|
if (props.type === TransactionEditPageType.Transaction) {
|
||||||
if (options && options.id) {
|
if (options && options.id) {
|
||||||
if (options.currentTransaction) {
|
if (options.currentTransaction) {
|
||||||
setTransaction(options.currentTransaction, options, true, true);
|
setTransaction(options.currentTransaction, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
mode.value = TransactionEditPageMode.View;
|
mode.value = TransactionEditPageMode.View;
|
||||||
@@ -781,10 +785,10 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
|||||||
editId.value = null;
|
editId.value = null;
|
||||||
|
|
||||||
if (options.template) {
|
if (options.template) {
|
||||||
setTransaction(options.template, options, false, false);
|
setTransaction(options.template, options, false);
|
||||||
addByTemplateId.value = options.template.id;
|
addByTemplateId.value = options.template.id;
|
||||||
} else if (!options.noTransactionDraft && (settingsStore.appSettings.autoSaveTransactionDraft === 'enabled' || settingsStore.appSettings.autoSaveTransactionDraft === 'confirmation') && transactionsStore.transactionDraft) {
|
} else if (!options.noTransactionDraft && (settingsStore.appSettings.autoSaveTransactionDraft === 'enabled' || settingsStore.appSettings.autoSaveTransactionDraft === 'confirmation') && transactionsStore.transactionDraft) {
|
||||||
setTransaction(Transaction.ofDraft(transactionsStore.transactionDraft), options, false, false);
|
setTransaction(Transaction.ofDraft(transactionsStore.transactionDraft), options, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsStore.appSettings.autoGetCurrentGeoLocation
|
if (settingsStore.appSettings.autoGetCurrentGeoLocation
|
||||||
@@ -809,7 +813,7 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
|||||||
|
|
||||||
if (options && options.id) {
|
if (options && options.id) {
|
||||||
if (options.currentTemplate) {
|
if (options.currentTemplate) {
|
||||||
setTransaction(options.currentTemplate, options, false, false);
|
setTransaction(options.currentTemplate, options, false);
|
||||||
(transaction.value as TransactionTemplate).fillFrom(options.currentTemplate);
|
(transaction.value as TransactionTemplate).fillFrom(options.currentTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -850,11 +854,11 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
|||||||
|
|
||||||
if (props.type === TransactionEditPageType.Transaction && options && options.id && responses[3] && responses[3] instanceof Transaction) {
|
if (props.type === TransactionEditPageType.Transaction && options && options.id && responses[3] && responses[3] instanceof Transaction) {
|
||||||
const transaction: Transaction = responses[3];
|
const transaction: Transaction = responses[3];
|
||||||
setTransaction(transaction, options, true, true);
|
setTransaction(transaction, options, true);
|
||||||
originalTransactionEditable.value = transaction.editable;
|
originalTransactionEditable.value = transaction.editable;
|
||||||
} else if (props.type === TransactionEditPageType.Template && options && options.id && responses[3] && responses[3] instanceof TransactionTemplate) {
|
} else if (props.type === TransactionEditPageType.Template && options && options.id && responses[3] && responses[3] instanceof TransactionTemplate) {
|
||||||
const template: TransactionTemplate = responses[3];
|
const template: TransactionTemplate = responses[3];
|
||||||
setTransaction(template, options, false, false);
|
setTransaction(template, options, false);
|
||||||
|
|
||||||
if (!(transaction.value instanceof TransactionTemplate)) {
|
if (!(transaction.value instanceof TransactionTemplate)) {
|
||||||
transaction.value = TransactionTemplate.createNewTransactionTemplate(transaction.value);
|
transaction.value = TransactionTemplate.createNewTransactionTemplate(transaction.value);
|
||||||
@@ -862,7 +866,7 @@ function open(options: TransactionEditOptions): Promise<TransactionEditResponse
|
|||||||
|
|
||||||
(transaction.value as TransactionTemplate).fillFrom(template);
|
(transaction.value as TransactionTemplate).fillFrom(template);
|
||||||
} else {
|
} else {
|
||||||
setTransaction(null, options, true, true);
|
setTransaction(null, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -1003,7 +1007,7 @@ function duplicate(withTime?: boolean, withGeoLocation?: boolean): void {
|
|||||||
if (!withTime) {
|
if (!withTime) {
|
||||||
transaction.value.time = getCurrentUnixTime();
|
transaction.value.time = getCurrentUnixTime();
|
||||||
transaction.value.timeZone = settingsStore.appSettings.timeZone;
|
transaction.value.timeZone = settingsStore.appSettings.timeZone;
|
||||||
transaction.value.utcOffset = getTimezoneOffsetMinutes(transaction.value.timeZone);
|
transaction.value.utcOffset = getTimezoneOffsetMinutes(transaction.value.time, transaction.value.timeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!withGeoLocation) {
|
if (!withGeoLocation) {
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ import { type UserExternalAuthInfoResponse } from '@/models/user_external_auth.t
|
|||||||
import { type TokenInfoResponse, SessionDeviceType, SessionInfo } from '@/models/token.ts';
|
import { type TokenInfoResponse, SessionDeviceType, SessionInfo } from '@/models/token.ts';
|
||||||
|
|
||||||
import { isEquals } from '@/lib/common.ts';
|
import { isEquals } from '@/lib/common.ts';
|
||||||
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
import { parseSessionInfo } from '@/lib/session.ts';
|
import { parseSessionInfo } from '@/lib/session.ts';
|
||||||
import {
|
import {
|
||||||
isAPITokenEnabled,
|
isAPITokenEnabled,
|
||||||
@@ -253,7 +254,7 @@ class DesktopPageLinkedThirdPartyLogin {
|
|||||||
this.externalAuthType = externalAuthInfoResponse.externalAuthType;
|
this.externalAuthType = externalAuthInfoResponse.externalAuthType;
|
||||||
this.linked = externalAuthInfoResponse.linked;
|
this.linked = externalAuthInfoResponse.linked;
|
||||||
this.externalUsername = externalAuthInfoResponse.externalUsername ? externalAuthInfoResponse.externalUsername : '-';
|
this.externalUsername = externalAuthInfoResponse.externalUsername ? externalAuthInfoResponse.externalUsername : '-';
|
||||||
this.createdAt = externalAuthInfoResponse.createdAt ? formatUnixTimeToLongDateTime(externalAuthInfoResponse.createdAt) : '-';
|
this.createdAt = externalAuthInfoResponse.createdAt ? formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(externalAuthInfoResponse.createdAt)) : '-';
|
||||||
|
|
||||||
if (externalAuthInfoResponse.externalAuthCategory === 'oauth2') {
|
if (externalAuthInfoResponse.externalAuthCategory === 'oauth2') {
|
||||||
this.displayName = getLocalizedOAuth2ProviderName(externalAuthInfoResponse.externalAuthType, getOIDCCustomDisplayNames());
|
this.displayName = getLocalizedOAuth2ProviderName(externalAuthInfoResponse.externalAuthType, getOIDCCustomDisplayNames());
|
||||||
@@ -277,7 +278,7 @@ class DesktopPageSessionInfo extends SessionInfo {
|
|||||||
public constructor(sessionInfo: SessionInfo) {
|
public constructor(sessionInfo: SessionInfo) {
|
||||||
super(sessionInfo.tokenId, sessionInfo.isCurrent, sessionInfo.deviceType, sessionInfo.deviceInfo, sessionInfo.deviceName, sessionInfo.lastSeen);
|
super(sessionInfo.tokenId, sessionInfo.isCurrent, sessionInfo.deviceType, sessionInfo.deviceInfo, sessionInfo.deviceName, sessionInfo.lastSeen);
|
||||||
this.icon = this.getTokenIcon(sessionInfo.deviceType);
|
this.icon = this.getTokenIcon(sessionInfo.deviceType);
|
||||||
this.lastSeenDateTime = sessionInfo.lastSeen ? formatUnixTimeToLongDateTime(sessionInfo.lastSeen) : '-';
|
this.lastSeenDateTime = sessionInfo.lastSeen ? formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(sessionInfo.lastSeen)) : '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTokenIcon(deviceType: SessionDeviceType): string {
|
private getTokenIcon(deviceType: SessionDeviceType): string {
|
||||||
@@ -306,7 +307,7 @@ type SnackBarType = InstanceType<typeof SnackBar>;
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
formatUnixTimeToLongDateTime,
|
formatDateTimeToLongDateTime,
|
||||||
getLocalizedOAuth2ProviderName,
|
getLocalizedOAuth2ProviderName,
|
||||||
setLanguage
|
setLanguage
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ import { useUserStore } from '@/stores/user.ts';
|
|||||||
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
import { useExchangeRatesStore } from '@/stores/exchangeRates.ts';
|
||||||
|
|
||||||
import { findNameByValue } from '@/lib/common.ts';
|
import { findNameByValue } from '@/lib/common.ts';
|
||||||
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
import { getClientDisplayVersion, getDesktopVersionPath } from '@/lib/version.ts';
|
import { getClientDisplayVersion, getDesktopVersionPath } from '@/lib/version.ts';
|
||||||
import { isUserScheduledTransactionEnabled } from '@/lib/server_settings.ts';
|
import { isUserScheduledTransactionEnabled } from '@/lib/server_settings.ts';
|
||||||
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
import { setExpenseAndIncomeAmountColor } from '@/lib/ui/common.ts';
|
||||||
@@ -137,7 +138,7 @@ const props = defineProps<{
|
|||||||
f7router: Router.Router;
|
f7router: Router.Router;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { tt, formatUnixTimeToLongDate, initLocale } = useI18n();
|
const { tt, formatDateTimeToLongDate, initLocale } = useI18n();
|
||||||
const { showToast, showConfirm } = useI18nUIComponents();
|
const { showToast, showConfirm } = useI18nUIComponents();
|
||||||
const { allThemes, allTimezones, timeZone, isAutoUpdateExchangeRatesData, showAccountBalance } = useAppSettingPageBase();
|
const { allThemes, allTimezones, timeZone, isAutoUpdateExchangeRatesData, showAccountBalance } = useAppSettingPageBase();
|
||||||
|
|
||||||
@@ -197,8 +198,12 @@ const isEnableAnimate = computed<boolean>({
|
|||||||
const isEnableApplicationLock = computed<boolean>(() => settingsStore.appSettings.applicationLock);
|
const isEnableApplicationLock = computed<boolean>(() => settingsStore.appSettings.applicationLock);
|
||||||
|
|
||||||
const exchangeRatesLastUpdateDate = computed<string>(() => {
|
const exchangeRatesLastUpdateDate = computed<string>(() => {
|
||||||
const exchangeRatesLastUpdateTime = exchangeRatesStore.exchangeRatesLastUpdateTime;
|
if (!exchangeRatesStore.exchangeRatesLastUpdateTime) {
|
||||||
return exchangeRatesLastUpdateTime ? formatUnixTimeToLongDate(exchangeRatesLastUpdateTime) : '';
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const exchangeRatesLastUpdateTime = parseDateTimeFromUnixTime(exchangeRatesStore.exchangeRatesLastUpdateTime);
|
||||||
|
return formatDateTimeToLongDate(exchangeRatesLastUpdateTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
function switchToDesktopVersion(): void {
|
function switchToDesktopVersion(): void {
|
||||||
|
|||||||
@@ -233,8 +233,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<date-time-selection-sheet :init-mode="accountContext.balanceDateTimeSheetMode"
|
<date-time-selection-sheet :init-mode="accountContext.balanceDateTimeSheetMode"
|
||||||
|
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(account)"
|
||||||
|
:model-value="account.balanceTime"
|
||||||
v-model:show="accountContext.showBalanceDateTimeSheet"
|
v-model:show="accountContext.showBalanceDateTimeSheet"
|
||||||
v-model="account.balanceTime">
|
@update:model-value="updateAccountBalanceTime(account, $event)">
|
||||||
</date-time-selection-sheet>
|
</date-time-selection-sheet>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -475,8 +477,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<date-time-selection-sheet :init-mode="subAccountContexts[idx]!.balanceDateTimeSheetMode"
|
<date-time-selection-sheet :init-mode="subAccountContexts[idx]!.balanceDateTimeSheetMode"
|
||||||
|
:timezone-utc-offset="getDefaultTimezoneOffsetMinutes(subAccount)"
|
||||||
|
:model-value="subAccount.balanceTime"
|
||||||
v-model:show="subAccountContexts[idx]!.showBalanceDateTimeSheet"
|
v-model:show="subAccountContexts[idx]!.showBalanceDateTimeSheet"
|
||||||
v-model="subAccount.balanceTime">
|
@update:model-value="updateAccountBalanceTime(subAccount, $event)">
|
||||||
</date-time-selection-sheet>
|
</date-time-selection-sheet>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -538,8 +542,7 @@ import { isDefined, findDisplayNameByType } from '@/lib/common.ts';
|
|||||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||||
import {
|
import {
|
||||||
getTimezoneOffsetMinutes,
|
getTimezoneOffsetMinutes,
|
||||||
getBrowserTimezoneOffsetMinutes,
|
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||||
getActualUnixTimeForStore
|
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
|
|
||||||
interface AccountContext {
|
interface AccountContext {
|
||||||
@@ -561,8 +564,8 @@ const {
|
|||||||
tt,
|
tt,
|
||||||
getAllCurrencies,
|
getAllCurrencies,
|
||||||
getCurrencyName,
|
getCurrencyName,
|
||||||
formatUnixTimeToLongDate,
|
formatDateTimeToLongDate,
|
||||||
formatUnixTimeToLongTime,
|
formatDateTimeToLongTime,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -582,7 +585,9 @@ const {
|
|||||||
allAccountTypes,
|
allAccountTypes,
|
||||||
allAvailableMonthDays,
|
allAvailableMonthDays,
|
||||||
isAccountSupportCreditCardStatementDate,
|
isAccountSupportCreditCardStatementDate,
|
||||||
|
getDefaultTimezoneOffsetMinutes,
|
||||||
getAccountCreditCardStatementDate,
|
getAccountCreditCardStatementDate,
|
||||||
|
updateAccountBalanceTime,
|
||||||
isNewAccount,
|
isNewAccount,
|
||||||
addSubAccount,
|
addSubAccount,
|
||||||
setAccount
|
setAccount
|
||||||
@@ -621,7 +626,8 @@ function formatAccountBalanceDate(account: Account): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatUnixTimeToLongDate(getActualUnixTimeForStore(account.balanceTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(account.balanceTime, getTimezoneOffsetMinutes(account.balanceTime));
|
||||||
|
return formatDateTimeToLongDate(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatAccountBalanceTime(account: Account): string {
|
function formatAccountBalanceTime(account: Account): string {
|
||||||
@@ -629,7 +635,8 @@ function formatAccountBalanceTime(account: Account): string {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatUnixTimeToLongTime(getActualUnixTimeForStore(account.balanceTime, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(account.balanceTime, getTimezoneOffsetMinutes(account.balanceTime));
|
||||||
|
return formatDateTimeToLongTime(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(): void {
|
function init(): void {
|
||||||
|
|||||||
@@ -51,10 +51,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div v-if="dateRange.isUserCustomRange && queryDateRangeType === dateRange.type && startTime && endTime">
|
<div v-if="dateRange.isUserCustomRange && queryDateRangeType === dateRange.type && startTime && endTime">
|
||||||
<span>{{ displayStartTime }}</span>
|
<span>{{ displayStartDateTime }}</span>
|
||||||
<span> - </span>
|
<span> - </span>
|
||||||
<br/>
|
<br/>
|
||||||
<span>{{ displayEndTime }}</span>
|
<span>{{ displayEndDateTime }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
<div class="transaction-footer display-flex justify-content-space-between">
|
<div class="transaction-footer display-flex justify-content-space-between">
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
<span>{{ getDisplayTime(item.transaction) }}</span>
|
<span>{{ getDisplayTime(item.transaction) }}</span>
|
||||||
<span v-if="item.transaction.utcOffset !== currentTimezoneOffsetMinutes">{{ `(${getDisplayTimezone(item.transaction)})` }}</span>
|
<span style="margin-inline-start: 4px" v-if="!isSameAsDefaultTimezoneOffsetMinutes(item.transaction)">{{ `(${getDisplayTimezone(item.transaction)})` }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="account-balance flex-shrink-1">
|
<div class="account-balance flex-shrink-1">
|
||||||
<span>{{ isCurrentLiabilityAccount ? tt('Outstanding Balance') : tt('Balance') }}</span>
|
<span>{{ isCurrentLiabilityAccount ? tt('Outstanding Balance') : tt('Balance') }}</span>
|
||||||
@@ -388,7 +388,6 @@ const {
|
|||||||
tt,
|
tt,
|
||||||
getCurrentLanguageTextDirection,
|
getCurrentLanguageTextDirection,
|
||||||
getAllDateRanges,
|
getAllDateRanges,
|
||||||
formatUnixTimeToLongDateTime,
|
|
||||||
formatNumberToLocalizedNumerals
|
formatNumberToLocalizedNumerals
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
@@ -402,7 +401,6 @@ const {
|
|||||||
firstDayOfWeek,
|
firstDayOfWeek,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
allDateAggregationTypes,
|
allDateAggregationTypes,
|
||||||
currentTimezoneOffsetMinutes,
|
|
||||||
isCurrentLiabilityAccount,
|
isCurrentLiabilityAccount,
|
||||||
currentAccount,
|
currentAccount,
|
||||||
currentAccountCurrency,
|
currentAccountCurrency,
|
||||||
@@ -416,6 +414,7 @@ const {
|
|||||||
setReconciliationStatements,
|
setReconciliationStatements,
|
||||||
getDisplayDate,
|
getDisplayDate,
|
||||||
getDisplayTime,
|
getDisplayTime,
|
||||||
|
isSameAsDefaultTimezoneOffsetMinutes,
|
||||||
getDisplayTimezone,
|
getDisplayTimezone,
|
||||||
getDisplaySourceAmount,
|
getDisplaySourceAmount,
|
||||||
getDisplayDestinationAmount,
|
getDisplayDestinationAmount,
|
||||||
@@ -446,8 +445,6 @@ const virtualDataItems = ref<ReconciliationStatementVirtualListData>({
|
|||||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||||
const validQuery = computed(() => currentAccount.value && currentAccount.value.type === AccountType.SingleAccount.type);
|
const validQuery = computed(() => currentAccount.value && currentAccount.value.type === AccountType.SingleAccount.type);
|
||||||
const allAvailableDateRanges = computed(() => getAllDateRanges(DateRangeScene.Normal, true, !!accountsStore.getAccountStatementDate(accountId.value)));
|
const allAvailableDateRanges = computed(() => getAllDateRanges(DateRangeScene.Normal, true, !!accountsStore.getAccountStatementDate(accountId.value)));
|
||||||
const displayStartTime = computed<string>(() => formatUnixTimeToLongDateTime(startTime.value));
|
|
||||||
const displayEndTime = computed<string>(() => formatUnixTimeToLongDateTime(endTime.value));
|
|
||||||
|
|
||||||
const allReconciliationStatementVirtualListItems = computed<ReconciliationStatementVirtualListItem[]>(() => {
|
const allReconciliationStatementVirtualListItems = computed<ReconciliationStatementVirtualListItem[]>(() => {
|
||||||
const ret: ReconciliationStatementVirtualListItem[] = [];
|
const ret: ReconciliationStatementVirtualListItem[] = [];
|
||||||
|
|||||||
@@ -124,8 +124,9 @@ import { useI18n } from '@/locales/helpers.ts';
|
|||||||
import { useSettingsStore } from '@/stores/setting.ts';
|
import { useSettingsStore } from '@/stores/setting.ts';
|
||||||
|
|
||||||
import { TextDirection } from '@/core/text.ts';
|
import { TextDirection } from '@/core/text.ts';
|
||||||
|
import { type DateTime } from '@/core/datetime.ts';
|
||||||
import { FontSize } from '@/core/font.ts';
|
import { FontSize } from '@/core/font.ts';
|
||||||
import { parseDateTimeFromUnixTime, getCurrentUnixTime } from '@/lib/datetime.ts';
|
import { getCurrentDateTime } from '@/lib/datetime.ts';
|
||||||
import { setAppFontSize, getFontSizePreviewClassName } from '@/lib/ui/mobile.ts';
|
import { setAppFontSize, getFontSizePreviewClassName } from '@/lib/ui/mobile.ts';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -136,23 +137,23 @@ const {
|
|||||||
tt,
|
tt,
|
||||||
getCurrentLanguageTextDirection,
|
getCurrentLanguageTextDirection,
|
||||||
getWeekdayShortName,
|
getWeekdayShortName,
|
||||||
getCalendarDisplayDayOfMonthFromUnixTime,
|
getCalendarDisplayDayOfMonthFromDateTime,
|
||||||
formatUnixTimeToShortTime,
|
formatDateTimeToShortTime,
|
||||||
formatUnixTimeToGregorianLikeLongYearMonth,
|
formatDateTimeToGregorianLikeLongYearMonth,
|
||||||
formatAmountToLocalizedNumeralsWithCurrency
|
formatAmountToLocalizedNumeralsWithCurrency
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
const currentUnixTime = ref<number>(getCurrentUnixTime());
|
const currentDateTime = ref<DateTime>(getCurrentDateTime());
|
||||||
const fontSize = ref<number>(settingsStore.appSettings.fontSize);
|
const fontSize = ref<number>(settingsStore.appSettings.fontSize);
|
||||||
|
|
||||||
const textDirection = computed<string>(() => getCurrentLanguageTextDirection());
|
const textDirection = computed<string>(() => getCurrentLanguageTextDirection());
|
||||||
const fontSizePreviewClassName = computed<string>(() => getFontSizePreviewClassName(fontSize.value));
|
const fontSizePreviewClassName = computed<string>(() => getFontSizePreviewClassName(fontSize.value));
|
||||||
const currentLongYearMonth = computed<string>(() => formatUnixTimeToGregorianLikeLongYearMonth(currentUnixTime.value));
|
const currentLongYearMonth = computed<string>(() => formatDateTimeToGregorianLikeLongYearMonth(currentDateTime.value));
|
||||||
const currentDayOfMonth = computed<string>(() => getCalendarDisplayDayOfMonthFromUnixTime(currentUnixTime.value));
|
const currentDayOfMonth = computed<string>(() => getCalendarDisplayDayOfMonthFromDateTime(currentDateTime.value));
|
||||||
const currentDayOfWeek = computed<string>(() => getWeekdayShortName(parseDateTimeFromUnixTime(currentUnixTime.value).getWeekDay()));
|
const currentDayOfWeek = computed<string>(() => getWeekdayShortName(currentDateTime.value.getWeekDay()));
|
||||||
const currentShortTime = computed<string>(() => formatUnixTimeToShortTime(currentUnixTime.value));
|
const currentShortTime = computed<string>(() => formatDateTimeToShortTime(currentDateTime.value));
|
||||||
|
|
||||||
function getFontSizeName(): string {
|
function getFontSizeName(): string {
|
||||||
return '';
|
return '';
|
||||||
|
|||||||
@@ -251,8 +251,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<date-time-selection-sheet :init-mode="transactionDateTimeSheetMode"
|
<date-time-selection-sheet :init-mode="transactionDateTimeSheetMode"
|
||||||
|
:timezone-utc-offset="transaction.utcOffset"
|
||||||
|
:model-value="transaction.time"
|
||||||
v-model:show="showTransactionDateTimeSheet"
|
v-model:show="showTransactionDateTimeSheet"
|
||||||
v-model="transaction.time">
|
@update:model-value="updateTransactionTime">
|
||||||
</date-time-selection-sheet>
|
</date-time-selection-sheet>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -323,8 +325,9 @@
|
|||||||
:filter-placeholder="tt('Timezone')"
|
:filter-placeholder="tt('Timezone')"
|
||||||
:filter-no-items-text="tt('No results')"
|
:filter-no-items-text="tt('No results')"
|
||||||
:items="allTimezones"
|
:items="allTimezones"
|
||||||
|
:model-value="transaction.timeZone"
|
||||||
v-model:show="showTimezonePopup"
|
v-model:show="showTimezonePopup"
|
||||||
v-model="transaction.timeZone">
|
@update:model-value="updateTransactionTimezone">
|
||||||
</list-item-selection-popup>
|
</list-item-selection-popup>
|
||||||
</f7-list-item>
|
</f7-list-item>
|
||||||
|
|
||||||
@@ -512,10 +515,9 @@ import type { TransactionPictureInfoBasicResponse } from '@/models/transaction_p
|
|||||||
import { Transaction } from '@/models/transaction.ts';
|
import { Transaction } from '@/models/transaction.ts';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getActualUnixTimeForStore,
|
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getTimezoneOffset,
|
getTimezoneOffset,
|
||||||
getTimezoneOffsetMinutes
|
getTimezoneOffsetMinutes,
|
||||||
|
parseDateTimeFromUnixTimeWithTimezoneOffset
|
||||||
} from '@/lib/datetime.ts';
|
} from '@/lib/datetime.ts';
|
||||||
import { formatCoordinate } from '@/lib/coordinate.ts';
|
import { formatCoordinate } from '@/lib/coordinate.ts';
|
||||||
import { generateRandomUUID } from '@/lib/misc.ts';
|
import { generateRandomUUID } from '@/lib/misc.ts';
|
||||||
@@ -536,8 +538,8 @@ const {
|
|||||||
tt,
|
tt,
|
||||||
getMultiMonthdayShortNames,
|
getMultiMonthdayShortNames,
|
||||||
getMultiWeekdayLongNames,
|
getMultiWeekdayLongNames,
|
||||||
formatUnixTimeToLongDate,
|
formatDateTimeToLongDate,
|
||||||
formatUnixTimeToLongTime,
|
formatDateTimeToLongTime,
|
||||||
formatGregorianTextualYearMonthDayToLongDate,
|
formatGregorianTextualYearMonthDayToLongDate,
|
||||||
parseAmountFromLocalizedNumerals
|
parseAmountFromLocalizedNumerals
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
@@ -589,6 +591,8 @@ const {
|
|||||||
geoLocationStatusInfo,
|
geoLocationStatusInfo,
|
||||||
inputEmptyProblemMessage,
|
inputEmptyProblemMessage,
|
||||||
inputIsEmpty,
|
inputIsEmpty,
|
||||||
|
updateTransactionTime,
|
||||||
|
updateTransactionTimezone,
|
||||||
swapTransactionData,
|
swapTransactionData,
|
||||||
getDisplayAmount,
|
getDisplayAmount,
|
||||||
getTransactionPictureUrl
|
getTransactionPictureUrl
|
||||||
@@ -655,19 +659,23 @@ const destinationAmountClass = computed<Record<string, boolean>>(() => {
|
|||||||
|
|
||||||
const transactionDisplayDate = computed<string>(() => {
|
const transactionDisplayDate = computed<string>(() => {
|
||||||
if (mode.value !== TransactionEditPageMode.View || !showTimeInDefaultTimezone.value) {
|
if (mode.value !== TransactionEditPageMode.View || !showTimeInDefaultTimezone.value) {
|
||||||
return formatUnixTimeToLongDate(getActualUnixTimeForStore(transaction.value.time, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.value.time, transaction.value.utcOffset);
|
||||||
|
return formatDateTimeToLongDate(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatUnixTimeToLongDate(getActualUnixTimeForStore(transaction.value.time, transaction.value.utcOffset, getBrowserTimezoneOffsetMinutes()));
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.value.time, getTimezoneOffsetMinutes(transaction.value.time));
|
||||||
|
return formatDateTimeToLongDate(dateTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
const transactionDisplayTime = computed<string>(() => {
|
const transactionDisplayTime = computed<string>(() => {
|
||||||
if (mode.value !== TransactionEditPageMode.View || !showTimeInDefaultTimezone.value) {
|
if (mode.value !== TransactionEditPageMode.View || !showTimeInDefaultTimezone.value) {
|
||||||
return formatUnixTimeToLongTime(getActualUnixTimeForStore(transaction.value.time, getTimezoneOffsetMinutes(), getBrowserTimezoneOffsetMinutes()));
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.value.time, transaction.value.utcOffset);
|
||||||
|
return formatDateTimeToLongTime(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(settingsStore.appSettings.timeZone));
|
const dateTime = parseDateTimeFromUnixTimeWithTimezoneOffset(transaction.value.time, getTimezoneOffsetMinutes(transaction.value.time));
|
||||||
return `${formatUnixTimeToLongTime(getActualUnixTimeForStore(transaction.value.time, transaction.value.utcOffset, getBrowserTimezoneOffsetMinutes()))} (UTC${utcOffset})`;
|
const utcOffset = numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(getTimezoneOffset(transaction.value.time));
|
||||||
|
return `${formatDateTimeToLongTime(dateTime)} (UTC${utcOffset})`;
|
||||||
});
|
});
|
||||||
|
|
||||||
const transactionDisplayTimezoneName = computed<string>(() => {
|
const transactionDisplayTimezoneName = computed<string>(() => {
|
||||||
@@ -949,7 +957,6 @@ function init(): void {
|
|||||||
tagIds: query['tagIds'],
|
tagIds: query['tagIds'],
|
||||||
comment: query['comment']
|
comment: query['comment']
|
||||||
},
|
},
|
||||||
pageTypeAndMode.type === TransactionEditPageType.Transaction && (mode.value === TransactionEditPageMode.Edit || mode.value === TransactionEditPageMode.View),
|
|
||||||
pageTypeAndMode.type === TransactionEditPageType.Transaction && (mode.value === TransactionEditPageMode.Edit || mode.value === TransactionEditPageMode.View)
|
pageTypeAndMode.type === TransactionEditPageType.Transaction && (mode.value === TransactionEditPageMode.Edit || mode.value === TransactionEditPageMode.View)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
<template #media>
|
<template #media>
|
||||||
<div class="display-flex flex-direction-column transaction-date" :style="getTransactionDateStyle(transaction, idx > 0 ? transactionMonthList.items[idx - 1] : undefined)">
|
<div class="display-flex flex-direction-column transaction-date" :style="getTransactionDateStyle(transaction, idx > 0 ? transactionMonthList.items[idx - 1] : undefined)">
|
||||||
<span class="transaction-day full-line flex-direction-column">
|
<span class="transaction-day full-line flex-direction-column">
|
||||||
{{ getCalendarDisplayDayOfMonthFromUnixTime(transaction.time) }}
|
{{ transaction.gregorianCalendarDayOfMonth ? numeralSystem.formatNumber(transaction.gregorianCalendarDayOfMonth) : '' }}
|
||||||
</span>
|
</span>
|
||||||
<span class="transaction-day-of-week full-line flex-direction-column" v-if="transaction.displayDayOfWeek">
|
<span class="transaction-day-of-week full-line flex-direction-column" v-if="transaction.displayDayOfWeek">
|
||||||
{{ getWeekdayShortName(transaction.displayDayOfWeek) }}
|
{{ getWeekdayShortName(transaction.displayDayOfWeek) }}
|
||||||
@@ -265,7 +265,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="transaction-footer">
|
<div class="transaction-footer">
|
||||||
<span>{{ getDisplayTime(transaction) }}</span>
|
<span>{{ getDisplayTime(transaction) }}</span>
|
||||||
<span v-if="transaction.utcOffset !== currentTimezoneOffsetMinutes">{{ `(${getDisplayTimezone(transaction)})` }}</span>
|
<span v-if="!isSameAsDefaultTimezoneOffsetMinutes(transaction)">{{ `(${getDisplayTimezone(transaction)})` }}</span>
|
||||||
<span v-if="transaction.sourceAccount">·</span>
|
<span v-if="transaction.sourceAccount">·</span>
|
||||||
<span v-if="transaction.sourceAccount">{{ transaction.sourceAccount.name }}</span>
|
<span v-if="transaction.sourceAccount">{{ transaction.sourceAccount.name }}</span>
|
||||||
<f7-icon class="transaction-account-arrow icon-with-direction" f7="arrow_right" v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id"></f7-icon>
|
<f7-icon class="transaction-account-arrow icon-with-direction" f7="arrow_right" v-if="transaction.sourceAccount && transaction.type === TransactionType.Transfer && transaction.destinationAccount && transaction.sourceAccount.id !== transaction.destinationAccount.id"></f7-icon>
|
||||||
@@ -624,7 +624,7 @@ import {
|
|||||||
DateRangeScene,
|
DateRangeScene,
|
||||||
DateRange
|
DateRange
|
||||||
} from '@/core/datetime.ts';
|
} from '@/core/datetime.ts';
|
||||||
import { AmountFilterType } from '@/core/numeral.ts';
|
import { type NumeralSystem, AmountFilterType } from '@/core/numeral.ts';
|
||||||
import { TransactionType } from '@/core/transaction.ts';
|
import { TransactionType } from '@/core/transaction.ts';
|
||||||
import type { TransactionCategory } from '@/models/transaction_category.ts';
|
import type { TransactionCategory } from '@/models/transaction_category.ts';
|
||||||
import { type Transaction, TransactionTagFilter } from '@/models/transaction.ts';
|
import { type Transaction, TransactionTagFilter } from '@/models/transaction.ts';
|
||||||
@@ -637,8 +637,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
getCurrentUnixTime,
|
getCurrentUnixTime,
|
||||||
parseDateTimeFromUnixTime,
|
parseDateTimeFromUnixTime,
|
||||||
getBrowserTimezoneOffsetMinutes,
|
|
||||||
getActualUnixTimeForStore,
|
|
||||||
getDayFirstUnixTimeBySpecifiedUnixTime,
|
getDayFirstUnixTimeBySpecifiedUnixTime,
|
||||||
getYearMonthFirstUnixTime,
|
getYearMonthFirstUnixTime,
|
||||||
getYearMonthLastUnixTime,
|
getYearMonthLastUnixTime,
|
||||||
@@ -664,8 +662,8 @@ const props = defineProps<{
|
|||||||
const {
|
const {
|
||||||
tt,
|
tt,
|
||||||
getCurrentLanguageTextDirection,
|
getCurrentLanguageTextDirection,
|
||||||
getWeekdayShortName,
|
getCurrentNumeralSystemType,
|
||||||
getCalendarDisplayDayOfMonthFromUnixTime
|
getWeekdayShortName
|
||||||
} = useI18n();
|
} = useI18n();
|
||||||
|
|
||||||
const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
|
const { showAlert, showToast, routeBackOnError } = useI18nUIComponents();
|
||||||
@@ -676,7 +674,6 @@ const {
|
|||||||
customMinDatetime,
|
customMinDatetime,
|
||||||
customMaxDatetime,
|
customMaxDatetime,
|
||||||
currentCalendarDate,
|
currentCalendarDate,
|
||||||
currentTimezoneOffsetMinutes,
|
|
||||||
firstDayOfWeek,
|
firstDayOfWeek,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
defaultCurrency,
|
defaultCurrency,
|
||||||
@@ -711,6 +708,7 @@ const {
|
|||||||
transactionCalendarMaxDate,
|
transactionCalendarMaxDate,
|
||||||
currentMonthTransactionData,
|
currentMonthTransactionData,
|
||||||
hasSubCategoryInQuery,
|
hasSubCategoryInQuery,
|
||||||
|
isSameAsDefaultTimezoneOffsetMinutes,
|
||||||
canAddTransaction,
|
canAddTransaction,
|
||||||
getDisplayTime,
|
getDisplayTime,
|
||||||
getDisplayLongYearMonth,
|
getDisplayLongYearMonth,
|
||||||
@@ -737,6 +735,7 @@ const showCustomMonthSheet = ref<boolean>(false);
|
|||||||
const showDeleteActionSheet = ref<boolean>(false);
|
const showDeleteActionSheet = ref<boolean>(false);
|
||||||
|
|
||||||
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
const textDirection = computed<TextDirection>(() => getCurrentLanguageTextDirection());
|
||||||
|
const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());
|
||||||
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
|
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
|
||||||
|
|
||||||
const transactions = computed<TransactionMonthList[]>(() => {
|
const transactions = computed<TransactionMonthList[]>(() => {
|
||||||
@@ -1057,7 +1056,7 @@ function changePageType(type: number): void {
|
|||||||
function changeDateFilter(dateType: number): void {
|
function changeDateFilter(dateType: number): void {
|
||||||
if (dateType === DateRange.Custom.type) { // Custom
|
if (dateType === DateRange.Custom.type) { // Custom
|
||||||
if (!query.value.minTime || !query.value.maxTime) {
|
if (!query.value.minTime || !query.value.maxTime) {
|
||||||
customMaxDatetime.value = getActualUnixTimeForStore(getCurrentUnixTime(), currentTimezoneOffsetMinutes.value, getBrowserTimezoneOffsetMinutes());
|
customMaxDatetime.value = getCurrentUnixTime();
|
||||||
customMinDatetime.value = getDayFirstUnixTimeBySpecifiedUnixTime(customMaxDatetime.value);
|
customMinDatetime.value = getDayFirstUnixTimeBySpecifiedUnixTime(customMaxDatetime.value);
|
||||||
} else {
|
} else {
|
||||||
customMaxDatetime.value = query.value.maxTime;
|
customMaxDatetime.value = query.value.maxTime;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import { TextDirection } from '@/core/text.ts';
|
|||||||
import { type TokenInfoResponse, SessionDeviceType, SessionInfo } from '@/models/token.ts';
|
import { type TokenInfoResponse, SessionDeviceType, SessionInfo } from '@/models/token.ts';
|
||||||
|
|
||||||
import { isEquals } from '@/lib/common.ts';
|
import { isEquals } from '@/lib/common.ts';
|
||||||
|
import { parseDateTimeFromUnixTime } from '@/lib/datetime.ts';
|
||||||
import { parseSessionInfo } from '@/lib/session.ts';
|
import { parseSessionInfo } from '@/lib/session.ts';
|
||||||
|
|
||||||
class MobilePageSessionInfo extends SessionInfo {
|
class MobilePageSessionInfo extends SessionInfo {
|
||||||
@@ -69,7 +70,7 @@ class MobilePageSessionInfo extends SessionInfo {
|
|||||||
super(sessionInfo.tokenId, sessionInfo.isCurrent, sessionInfo.deviceType, sessionInfo.deviceInfo, sessionInfo.deviceName, sessionInfo.lastSeen);
|
super(sessionInfo.tokenId, sessionInfo.isCurrent, sessionInfo.deviceType, sessionInfo.deviceInfo, sessionInfo.deviceName, sessionInfo.lastSeen);
|
||||||
this.domId = getTokenDomId(sessionInfo.tokenId);
|
this.domId = getTokenDomId(sessionInfo.tokenId);
|
||||||
this.icon = getTokenIcon(sessionInfo.deviceType);
|
this.icon = getTokenIcon(sessionInfo.deviceType);
|
||||||
this.lastSeenDateTime = sessionInfo.lastSeen ? formatUnixTimeToLongDateTime(sessionInfo.lastSeen) : '-';
|
this.lastSeenDateTime = sessionInfo.lastSeen ? formatDateTimeToLongDateTime(parseDateTimeFromUnixTime(sessionInfo.lastSeen)) : '-';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +78,12 @@ const props = defineProps<{
|
|||||||
f7router: Router.Router;
|
f7router: Router.Router;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { tt, getCurrentLanguageTextDirection, formatUnixTimeToLongDateTime } = useI18n();
|
const {
|
||||||
|
tt,
|
||||||
|
getCurrentLanguageTextDirection,
|
||||||
|
formatDateTimeToLongDateTime
|
||||||
|
} = useI18n();
|
||||||
|
|
||||||
const { showConfirm, showToast, routeBackOnError } = useI18nUIComponents();
|
const { showConfirm, showToast, routeBackOnError } = useI18nUIComponents();
|
||||||
|
|
||||||
const tokensStore = useTokensStore();
|
const tokensStore = useTokensStore();
|
||||||
|
|||||||
Reference in New Issue
Block a user