177 lines
6.6 KiB
Go
177 lines
6.6 KiB
Go
package mt
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/mayswind/ezbookkeeping/pkg/converters/datatable"
|
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
|
"github.com/mayswind/ezbookkeeping/pkg/log"
|
|
"github.com/mayswind/ezbookkeeping/pkg/models"
|
|
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
|
)
|
|
|
|
var mt940TransactionSupportedColumns = map[datatable.TransactionDataTableColumn]bool{
|
|
datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME: true,
|
|
datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE: true,
|
|
datatable.TRANSACTION_DATA_TABLE_SUB_CATEGORY: true,
|
|
datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME: true,
|
|
datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY: true,
|
|
datatable.TRANSACTION_DATA_TABLE_AMOUNT: true,
|
|
datatable.TRANSACTION_DATA_TABLE_RELATED_ACCOUNT_NAME: true,
|
|
datatable.TRANSACTION_DATA_TABLE_DESCRIPTION: true,
|
|
}
|
|
|
|
// mt940TransactionDataTable represents the mt940 statement data dataTable
|
|
type mt940TransactionDataTable struct {
|
|
data *mt940Data
|
|
}
|
|
|
|
// mt940TransactionDataRow represents a row in the mt940 statement data dataTable
|
|
type mt940TransactionDataRow struct {
|
|
statement *mtStatement
|
|
finalItems map[datatable.TransactionDataTableColumn]string
|
|
}
|
|
|
|
// mt940TransactionDataRowIterator represents an iterator for mt940 statement data rows
|
|
type mt940TransactionDataRowIterator struct {
|
|
dataTable *mt940TransactionDataTable
|
|
currentIndex int
|
|
}
|
|
|
|
// HasColumn implements TransactionDataTable.HasColumn
|
|
func (t *mt940TransactionDataTable) HasColumn(column datatable.TransactionDataTableColumn) bool {
|
|
_, exists := mt940TransactionSupportedColumns[column]
|
|
return exists
|
|
}
|
|
|
|
// TransactionRowCount implements TransactionDataTable.TransactionRowCount
|
|
func (t *mt940TransactionDataTable) TransactionRowCount() int {
|
|
return len(t.data.Statements)
|
|
}
|
|
|
|
// TransactionRowIterator implements TransactionDataTable.TransactionRowIterator
|
|
func (t *mt940TransactionDataTable) TransactionRowIterator() datatable.TransactionDataRowIterator {
|
|
return &mt940TransactionDataRowIterator{
|
|
dataTable: t,
|
|
currentIndex: -1,
|
|
}
|
|
}
|
|
|
|
// IsValid implements TransactionDataRow.IsValid
|
|
func (r *mt940TransactionDataRow) IsValid() bool {
|
|
return true
|
|
}
|
|
|
|
// GetData implements TransactionDataRow.GetData
|
|
func (r *mt940TransactionDataRow) GetData(column datatable.TransactionDataTableColumn) string {
|
|
_, exists := mt940TransactionSupportedColumns[column]
|
|
|
|
if exists {
|
|
return r.finalItems[column]
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// HasNext implements TransactionDataRowIterator.HasNext
|
|
func (t *mt940TransactionDataRowIterator) HasNext() bool {
|
|
return t.currentIndex+1 < len(t.dataTable.data.Statements)
|
|
}
|
|
|
|
// Next implements TransactionDataRowIterator.Next
|
|
func (t *mt940TransactionDataRowIterator) Next(ctx core.Context, user *models.User) (datatable.TransactionDataRow, error) {
|
|
if t.currentIndex+1 >= len(t.dataTable.data.Statements) {
|
|
return nil, nil
|
|
}
|
|
|
|
t.currentIndex++
|
|
|
|
data := t.dataTable.data.Statements[t.currentIndex]
|
|
rowItems, err := t.parseTransaction(ctx, user, t.dataTable.data, data)
|
|
|
|
if err != nil {
|
|
log.Errorf(ctx, "[mt_transaction_data_table.Next] cannot parsing transaction in row#%d, because %s", t.currentIndex, err.Error())
|
|
return nil, err
|
|
}
|
|
|
|
return &mt940TransactionDataRow{
|
|
statement: data,
|
|
finalItems: rowItems,
|
|
}, nil
|
|
}
|
|
|
|
func (t *mt940TransactionDataRowIterator) parseTransaction(ctx core.Context, user *models.User, mt940Data *mt940Data, statement *mtStatement) (map[datatable.TransactionDataTableColumn]string, error) {
|
|
data := make(map[datatable.TransactionDataTableColumn]string, len(mt940TransactionSupportedColumns))
|
|
|
|
if statement.ValueDate == "" && len(statement.ValueDate) != 6 {
|
|
return nil, errs.ErrTransactionTimeInvalid
|
|
}
|
|
|
|
transactionTime, err := utils.FormatYearMonthDayToLongDateTime(statement.ValueDate[0:2], statement.ValueDate[2:4], statement.ValueDate[4:6])
|
|
|
|
if err != nil {
|
|
log.Errorf(ctx, "[mt_transaction_data_table.parseTransaction] cannot format transaction time in row#%d, because %s", t.currentIndex, err.Error())
|
|
return nil, errs.ErrTransactionTimeInvalid
|
|
}
|
|
|
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TIME] = transactionTime
|
|
data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_NAME] = mt940Data.AccountId
|
|
|
|
if mt940Data.OpeningBalance != nil && mt940Data.OpeningBalance.Currency != "" {
|
|
data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] = mt940Data.OpeningBalance.Currency
|
|
} else if mt940Data.ClosingBalance != nil && mt940Data.ClosingBalance.Currency != "" {
|
|
data[datatable.TRANSACTION_DATA_TABLE_ACCOUNT_CURRENCY] = mt940Data.ClosingBalance.Currency
|
|
}
|
|
|
|
amountValue := strings.ReplaceAll(statement.Amount, ",", ".") // decimal separator is comma in mt data
|
|
|
|
if len(amountValue) > 0 && amountValue[len(amountValue)-1] == '.' {
|
|
amountValue = amountValue[:len(amountValue)-1]
|
|
}
|
|
|
|
amount, err := utils.ParseAmount(amountValue)
|
|
|
|
if err != nil {
|
|
log.Errorf(ctx, "[mt_transaction_data_table.parseTransaction] cannot parsing transaction amount \"%s\", because %s", statement.Amount, err.Error())
|
|
return nil, errs.ErrAmountInvalid
|
|
}
|
|
|
|
data[datatable.TRANSACTION_DATA_TABLE_AMOUNT] = utils.FormatAmount(amount)
|
|
|
|
if statement.CreditDebitMark == MT_MARK_CREDIT {
|
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = utils.IntToString(int(models.TRANSACTION_TYPE_INCOME))
|
|
} else if statement.CreditDebitMark == MT_MARK_DEBIT {
|
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = utils.IntToString(int(models.TRANSACTION_TYPE_EXPENSE))
|
|
} else if statement.CreditDebitMark == MT_MARK_REVERSAL_CREDIT {
|
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = utils.IntToString(int(models.TRANSACTION_TYPE_EXPENSE))
|
|
} else if statement.CreditDebitMark == MT_MARK_REVERSAL_DEBIT {
|
|
data[datatable.TRANSACTION_DATA_TABLE_TRANSACTION_TYPE] = utils.IntToString(int(models.TRANSACTION_TYPE_INCOME))
|
|
} else {
|
|
return nil, errs.ErrTransactionTypeInvalid
|
|
}
|
|
|
|
informationToAccountOwnerMap := statement.GetInformationToAccountOwnerMap()
|
|
|
|
if len(informationToAccountOwnerMap) > 0 {
|
|
if value, exists := informationToAccountOwnerMap[MT_INFORMATION_TO_ACCOUNT_OWNER_TAG_REMITTANCE]; exists {
|
|
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = value
|
|
}
|
|
} else {
|
|
data[datatable.TRANSACTION_DATA_TABLE_DESCRIPTION] = strings.Join(statement.InformationToAccountOwner, "\n")
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// createNewMT940TransactionDataTable creates a new mt940 statement data dataTable
|
|
func createNewMT940TransactionDataTable(data *mt940Data) (*mt940TransactionDataTable, error) {
|
|
if data == nil || len(data.Statements) < 1 {
|
|
return nil, errs.ErrNotFoundTransactionDataInFile
|
|
}
|
|
|
|
return &mt940TransactionDataTable{
|
|
data: data,
|
|
}, nil
|
|
}
|