scheduled transaction supports start time and end time (#36)
This commit is contained in:
@@ -156,7 +156,12 @@ func (a *TransactionTemplatesApi) TemplateCreateHandler(c *core.WebContext) (any
|
||||
}
|
||||
|
||||
serverUtcOffset := utils.GetServerTimezoneOffsetMinutes()
|
||||
template := a.createNewTemplateModel(uid, &templateCreateReq, maxOrderId+1)
|
||||
template, err := a.createNewTemplateModel(uid, &templateCreateReq, maxOrderId+1)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_templates.TemplateCreateHandler] failed to create new template for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
if a.CurrentConfig().EnableDuplicateSubmissionsCheck && templateCreateReq.ClientSessionId != "" {
|
||||
found, remark := a.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_TEMPLATE, uid, templateCreateReq.ClientSessionId)
|
||||
@@ -260,6 +265,34 @@ func (a *TransactionTemplatesApi) TemplateModifyHandler(c *core.WebContext) (any
|
||||
newTemplate.ScheduledFrequency = a.getOrderedFrequencyValues(*templateModifyReq.ScheduledFrequency)
|
||||
newTemplate.ScheduledAt = a.getUTCScheduledAt(*templateModifyReq.ScheduledTimezoneUtcOffset)
|
||||
newTemplate.ScheduledTimezoneUtcOffset = *templateModifyReq.ScheduledTimezoneUtcOffset
|
||||
|
||||
if templateModifyReq.ScheduledStartDate != nil {
|
||||
startTime, err := utils.ParseFromLongDateFirstTime(*templateModifyReq.ScheduledStartDate, *templateModifyReq.ScheduledTimezoneUtcOffset)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_templates.TemplateModifyHandler] failed to parse scheduled start date for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
startUnixTime := startTime.Unix()
|
||||
newTemplate.ScheduledStartTime = &startUnixTime
|
||||
}
|
||||
|
||||
if templateModifyReq.ScheduledEndDate != nil {
|
||||
endTime, err := utils.ParseFromLongDateLastTime(*templateModifyReq.ScheduledEndDate, *templateModifyReq.ScheduledTimezoneUtcOffset)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(c, "[transaction_templates.TemplateModifyHandler] failed to parse scheduled end date for user \"uid:%d\", because %s", uid, err.Error())
|
||||
return nil, errs.Or(err, errs.ErrOperationFailed)
|
||||
}
|
||||
|
||||
endUnixTime := endTime.Unix()
|
||||
newTemplate.ScheduledEndTime = &endUnixTime
|
||||
}
|
||||
|
||||
if newTemplate.ScheduledStartTime != nil && newTemplate.ScheduledEndTime != nil && *newTemplate.ScheduledStartTime > *newTemplate.ScheduledEndTime {
|
||||
return nil, errs.ErrScheduledTransactionTemplateStartDataLaterThanEndDate
|
||||
}
|
||||
}
|
||||
|
||||
if newTemplate.Name == template.Name &&
|
||||
@@ -277,6 +310,8 @@ func (a *TransactionTemplatesApi) TemplateModifyHandler(c *core.WebContext) (any
|
||||
} else if template.TemplateType == models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE {
|
||||
if newTemplate.ScheduledFrequencyType == template.ScheduledFrequencyType &&
|
||||
newTemplate.ScheduledFrequency == template.ScheduledFrequency &&
|
||||
newTemplate.ScheduledStartTime == template.ScheduledStartTime &&
|
||||
newTemplate.ScheduledEndTime == template.ScheduledEndTime &&
|
||||
newTemplate.ScheduledAt == template.ScheduledAt &&
|
||||
newTemplate.ScheduledTimezoneUtcOffset == template.ScheduledTimezoneUtcOffset {
|
||||
return nil, errs.ErrNothingWillBeUpdated
|
||||
@@ -419,7 +454,7 @@ func (a *TransactionTemplatesApi) TemplateDeleteHandler(c *core.WebContext) (any
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (a *TransactionTemplatesApi) createNewTemplateModel(uid int64, templateCreateReq *models.TransactionTemplateCreateRequest, order int32) *models.TransactionTemplate {
|
||||
func (a *TransactionTemplatesApi) createNewTemplateModel(uid int64, templateCreateReq *models.TransactionTemplateCreateRequest, order int32) (*models.TransactionTemplate, error) {
|
||||
template := &models.TransactionTemplate{
|
||||
Uid: uid,
|
||||
TemplateType: templateCreateReq.TemplateType,
|
||||
@@ -441,9 +476,35 @@ func (a *TransactionTemplatesApi) createNewTemplateModel(uid int64, templateCrea
|
||||
template.ScheduledFrequency = a.getOrderedFrequencyValues(*templateCreateReq.ScheduledFrequency)
|
||||
template.ScheduledAt = a.getUTCScheduledAt(*templateCreateReq.ScheduledTimezoneUtcOffset)
|
||||
template.ScheduledTimezoneUtcOffset = *templateCreateReq.ScheduledTimezoneUtcOffset
|
||||
|
||||
if templateCreateReq.ScheduledStartDate != nil {
|
||||
startTime, err := utils.ParseFromLongDateFirstTime(*templateCreateReq.ScheduledStartDate, *templateCreateReq.ScheduledTimezoneUtcOffset)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return template
|
||||
startUnixTime := startTime.Unix()
|
||||
template.ScheduledStartTime = &startUnixTime
|
||||
}
|
||||
|
||||
if templateCreateReq.ScheduledEndDate != nil {
|
||||
endTime, err := utils.ParseFromLongDateLastTime(*templateCreateReq.ScheduledEndDate, *templateCreateReq.ScheduledTimezoneUtcOffset)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endUnixTime := endTime.Unix()
|
||||
template.ScheduledEndTime = &endUnixTime
|
||||
}
|
||||
|
||||
if template.ScheduledStartTime != nil && template.ScheduledEndTime != nil && *template.ScheduledStartTime > *template.ScheduledEndTime {
|
||||
return nil, errs.ErrScheduledTransactionTemplateStartDataLaterThanEndDate
|
||||
}
|
||||
}
|
||||
|
||||
return template, nil
|
||||
}
|
||||
|
||||
func (a *TransactionTemplatesApi) getUTCScheduledAt(scheduledTimezoneUtcOffset int16) int16 {
|
||||
|
||||
@@ -10,4 +10,5 @@ var (
|
||||
ErrScheduledTransactionNotEnabled = NewNormalError(NormalSubcategoryTemplate, 3, http.StatusBadRequest, "scheduled transaction is not enabled")
|
||||
ErrScheduledTransactionFrequencyInvalid = NewNormalError(NormalSubcategoryTemplate, 4, http.StatusBadRequest, "scheduled transaction frequency is invalid")
|
||||
ErrTransactionTemplateHasTooManyTags = NewNormalError(NormalSubcategoryTemplate, 5, http.StatusBadRequest, "transaction template has too many tags")
|
||||
ErrScheduledTransactionTemplateStartDataLaterThanEndDate = NewNormalError(NormalSubcategoryTemplate, 6, http.StatusBadRequest, "scheduled transaction start date is later than end time")
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@ package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mayswind/ezbookkeeping/pkg/utils"
|
||||
)
|
||||
@@ -29,15 +30,17 @@ const (
|
||||
type TransactionTemplate struct {
|
||||
TemplateId int64 `xorm:"PK"`
|
||||
Uid int64 `xorm:"INDEX(IDX_transaction_template_uid_deleted_template_type_order) NOT NULL"`
|
||||
Deleted bool `xorm:"INDEX(IDX_transaction_template_uid_deleted_template_type_order) INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_at) NOT NULL"`
|
||||
TemplateType TransactionTemplateType `xorm:"INDEX(IDX_transaction_template_uid_deleted_template_type_order) INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_at) NOT NULL"`
|
||||
Deleted bool `xorm:"INDEX(IDX_transaction_template_uid_deleted_template_type_order) INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_time) NOT NULL"`
|
||||
TemplateType TransactionTemplateType `xorm:"INDEX(IDX_transaction_template_uid_deleted_template_type_order) INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_time) NOT NULL"`
|
||||
Name string `xorm:"VARCHAR(64) NOT NULL"`
|
||||
Type TransactionType `xorm:"NOT NULL"`
|
||||
CategoryId int64 `xorm:"NOT NULL"`
|
||||
AccountId int64 `xorm:"NOT NULL"`
|
||||
ScheduledFrequencyType TransactionScheduleFrequencyType `xorm:"INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_at)"`
|
||||
ScheduledFrequencyType TransactionScheduleFrequencyType `xorm:"INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_time)"`
|
||||
ScheduledFrequency string `xorm:"VARCHAR(100)"`
|
||||
ScheduledAt int16 `xorm:"INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_at)"`
|
||||
ScheduledStartTime *int64 `xorm:"INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_time)"`
|
||||
ScheduledEndTime *int64 `xorm:"INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_time)"`
|
||||
ScheduledAt int16 `xorm:"INDEX(IDX_transaction_template_deleted_type_freqtype_scheduled_time)"`
|
||||
ScheduledTimezoneUtcOffset int16
|
||||
TagIds string `xorm:"VARCHAR(255) NOT NULL"`
|
||||
Amount int64 `xorm:"NOT NULL"`
|
||||
@@ -77,6 +80,8 @@ type TransactionTemplateCreateRequest struct {
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
ScheduledFrequencyType *TransactionScheduleFrequencyType `json:"scheduledFrequencyType" binding:"omitempty"`
|
||||
ScheduledFrequency *string `json:"scheduledFrequency" binding:"omitempty"`
|
||||
ScheduledStartDate *string `json:"scheduledStartDate" binding:"omitempty"`
|
||||
ScheduledEndDate *string `json:"scheduledEndDate" binding:"omitempty"`
|
||||
ScheduledTimezoneUtcOffset *int16 `json:"utcOffset" binding:"omitempty,min=-720,max=840"`
|
||||
ClientSessionId string `json:"clientSessionId"`
|
||||
}
|
||||
@@ -102,6 +107,8 @@ type TransactionTemplateModifyRequest struct {
|
||||
Comment string `json:"comment" binding:"max=255"`
|
||||
ScheduledFrequencyType *TransactionScheduleFrequencyType `json:"scheduledFrequencyType" binding:"omitempty"`
|
||||
ScheduledFrequency *string `json:"scheduledFrequency" binding:"omitempty"`
|
||||
ScheduledStartDate *string `json:"scheduledStartDate" binding:"omitempty"`
|
||||
ScheduledEndDate *string `json:"scheduledEndDate" binding:"omitempty"`
|
||||
ScheduledTimezoneUtcOffset *int16 `json:"utcOffset" binding:"omitempty,min=-720,max=840"`
|
||||
}
|
||||
|
||||
@@ -133,6 +140,8 @@ type TransactionTemplateInfoResponse struct {
|
||||
Name string `json:"name"`
|
||||
ScheduledFrequencyType *TransactionScheduleFrequencyType `json:"scheduledFrequencyType,omitempty"`
|
||||
ScheduledFrequency *string `json:"scheduledFrequency,omitempty"`
|
||||
ScheduledStartDate *string `json:"scheduledStartDate" binding:"omitempty"`
|
||||
ScheduledEndDate *string `json:"scheduledEndDate" binding:"omitempty"`
|
||||
ScheduledAt *int16 `json:"scheduledAt,omitempty"`
|
||||
DisplayOrder int32 `json:"displayOrder"`
|
||||
Hidden bool `json:"hidden"`
|
||||
@@ -171,6 +180,18 @@ func (t *TransactionTemplate) ToTransactionTemplateInfoResponse(serverUtcOffset
|
||||
response.ScheduledFrequencyType = &t.ScheduledFrequencyType
|
||||
response.ScheduledFrequency = &t.ScheduledFrequency
|
||||
response.ScheduledAt = &t.ScheduledAt
|
||||
|
||||
templateTimeZone := time.FixedZone("Template Timezone", int(t.ScheduledTimezoneUtcOffset)*60)
|
||||
|
||||
if t.ScheduledStartTime != nil {
|
||||
startDate := utils.FormatUnixTimeToLongDate(*t.ScheduledStartTime, templateTimeZone)
|
||||
response.ScheduledStartDate = &startDate
|
||||
}
|
||||
|
||||
if t.ScheduledEndTime != nil {
|
||||
endDate := utils.FormatUnixTimeToLongDate(*t.ScheduledEndTime, templateTimeZone)
|
||||
response.ScheduledEndDate = &endDate
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
|
||||
@@ -136,7 +136,7 @@ func (s *TransactionTemplateService) ModifyTemplate(c core.Context, template *mo
|
||||
template.UpdatedUnixTime = time.Now().Unix()
|
||||
|
||||
return s.UserDataDB(template.Uid).DoTransaction(c, func(sess *xorm.Session) error {
|
||||
updatedRows, err := sess.ID(template.TemplateId).Cols("name", "type", "category_id", "account_id", "scheduled_frequency_type", "scheduled_frequency", "scheduled_at", "scheduled_timezone_utc_offset", "tag_ids", "amount", "related_account_id", "related_account_amount", "hide_amount", "comment", "updated_unix_time").Where("uid=? AND deleted=?", template.Uid, false).Update(template)
|
||||
updatedRows, err := sess.ID(template.TemplateId).Cols("name", "type", "category_id", "account_id", "scheduled_frequency_type", "scheduled_frequency", "scheduled_start_time", "scheduled_end_time", "scheduled_at", "scheduled_timezone_utc_offset", "tag_ids", "amount", "related_account_id", "related_account_amount", "hide_amount", "comment", "updated_unix_time").Where("uid=? AND deleted=?", template.Uid, false).Update(template)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -398,7 +398,7 @@ func (s *TransactionService) CreateScheduledTransactions(c core.Context, current
|
||||
|
||||
for i := 0; i < s.UserDataDBCount(); i++ {
|
||||
var templates []*models.TransactionTemplate
|
||||
err := s.UserDataDBByIndex(i).NewSession(c).Where("deleted=? AND template_type=? AND (scheduled_frequency_type=? OR scheduled_frequency_type=?) AND scheduled_at>=? AND scheduled_at<?", false, models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_WEEKLY, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_MONTHLY, minScheduledAt, maxScheduledAt).Find(&templates)
|
||||
err := s.UserDataDBByIndex(i).NewSession(c).Where("deleted=? AND template_type=? AND (scheduled_frequency_type=? OR scheduled_frequency_type=?) AND (scheduled_start_time IS NULL OR scheduled_start_time<=?) AND (scheduled_end_time IS NULL OR scheduled_end_time>=?) AND scheduled_at>=? AND scheduled_at<?", false, models.TRANSACTION_TEMPLATE_TYPE_SCHEDULE, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_WEEKLY, models.TRANSACTION_SCHEDULE_FREQUENCY_TYPE_MONTHLY, startTime.Unix(), startTime.Unix(), minScheduledAt, maxScheduledAt).Find(&templates)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -457,6 +457,18 @@ func (s *TransactionService) CreateScheduledTransactions(c core.Context, current
|
||||
continue
|
||||
}
|
||||
|
||||
if template.ScheduledStartTime != nil && *template.ScheduledStartTime > transactionUnixTime {
|
||||
skipCount++
|
||||
log.Infof(c, "[transactions.CreateScheduledTransactions] transaction template \"id:%d\" does not need to create transaction, now is earlier than the start time %d", template.TemplateId, *template.ScheduledStartTime)
|
||||
continue
|
||||
}
|
||||
|
||||
if template.ScheduledEndTime != nil && *template.ScheduledEndTime < transactionUnixTime {
|
||||
skipCount++
|
||||
log.Infof(c, "[transactions.CreateScheduledTransactions] transaction template \"id:%d\" does not need to create transaction, now is later than the end time %d", template.TemplateId, *template.ScheduledEndTime)
|
||||
continue
|
||||
}
|
||||
|
||||
var transactionDbType models.TransactionDbType
|
||||
|
||||
if template.Type == models.TRANSACTION_TYPE_EXPENSE {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
longDateFormat = "2006-01-02"
|
||||
longDateTimeFormat = "2006-01-02 15:04:05"
|
||||
longDateTimeWithTimezoneFormat = "2006-01-02 15:04:05Z07:00"
|
||||
longDateTimeWithTimezoneFormat2 = "2006-01-02 15:04:05 Z0700"
|
||||
@@ -42,6 +43,17 @@ func ParseNumericYearMonth(yearMonth string) (int32, int32, error) {
|
||||
return year, month, nil
|
||||
}
|
||||
|
||||
// FormatUnixTimeToLongDate returns a textual representation of the unix time formatted by long date time format
|
||||
func FormatUnixTimeToLongDate(unixTime int64, timezone *time.Location) string {
|
||||
t := parseFromUnixTime(unixTime)
|
||||
|
||||
if timezone != nil {
|
||||
t = t.In(timezone)
|
||||
}
|
||||
|
||||
return t.Format(longDateFormat)
|
||||
}
|
||||
|
||||
// FormatUnixTimeToLongDateTime returns a textual representation of the unix time formatted by long date time format
|
||||
func FormatUnixTimeToLongDateTime(unixTime int64, timezone *time.Location) string {
|
||||
t := parseFromUnixTime(unixTime)
|
||||
@@ -119,6 +131,24 @@ func GetMaxUnixTimeWithSameLocalDateTime(unixTime int64, currentUtcOffset int16)
|
||||
return unixTime + int64(currentUtcOffset)*60 - westernmostTimezoneUtcOffset*60
|
||||
}
|
||||
|
||||
// ParseFromLongDateFirstTime parses a formatted string in long date format
|
||||
func ParseFromLongDateFirstTime(t string, utcOffset int16) (time.Time, error) {
|
||||
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
||||
return time.ParseInLocation(longDateFormat, t, timezone)
|
||||
}
|
||||
|
||||
// ParseFromLongDateLastTime parses a formatted string in long date format
|
||||
func ParseFromLongDateLastTime(t string, utcOffset int16) (time.Time, error) {
|
||||
timezone := time.FixedZone("Timezone", int(utcOffset)*60)
|
||||
lastTime, err := time.ParseInLocation(longDateFormat, t, timezone)
|
||||
|
||||
if err != nil {
|
||||
return lastTime, err
|
||||
}
|
||||
|
||||
return lastTime.Add(24 * time.Hour).Add(-1 * time.Nanosecond), nil
|
||||
}
|
||||
|
||||
// ParseFromLongDateTimeToMinUnixTime parses a formatted string in long date time format to minimal unix time (the westernmost timezone)
|
||||
func ParseFromLongDateTimeToMinUnixTime(t string) (time.Time, error) {
|
||||
timezone := time.FixedZone("Timezone", easternmostTimezoneUtcOffset*60)
|
||||
|
||||
@@ -18,6 +18,20 @@ func TestParseNumericYearMonth(t *testing.T) {
|
||||
assert.Equal(t, expectedMonth, actualMonth)
|
||||
}
|
||||
|
||||
func TestFormatUnixTimeToLongDate(t *testing.T) {
|
||||
unixTime := int64(1617228083)
|
||||
utcTimezone := time.FixedZone("Test Timezone", 0) // UTC
|
||||
utc8Timezone := time.FixedZone("Test Timezone", 28800) // UTC+8
|
||||
|
||||
expectedValue := "2021-03-31"
|
||||
actualValue := FormatUnixTimeToLongDate(unixTime, utcTimezone)
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
|
||||
expectedValue = "2021-04-01"
|
||||
actualValue = FormatUnixTimeToLongDate(unixTime, utc8Timezone)
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
}
|
||||
|
||||
func TestFormatUnixTimeToLongDateTime(t *testing.T) {
|
||||
unixTime := int64(1617228083)
|
||||
utcTimezone := time.FixedZone("Test Timezone", 0) // UTC
|
||||
@@ -106,6 +120,24 @@ func TestGetMaxUnixTimeWithSameLocalDateTime(t *testing.T) {
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
}
|
||||
|
||||
func TestParseFromLongDateFirstTime(t *testing.T) {
|
||||
expectedValue := int64(1690819200)
|
||||
actualTime, err := ParseFromLongDateFirstTime("2023-08-01", 480)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
actualValue := actualTime.Unix()
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
}
|
||||
|
||||
func TestParseFromLongDateLastTime(t *testing.T) {
|
||||
expectedValue := int64(1690905599)
|
||||
actualTime, err := ParseFromLongDateLastTime("2023-08-01", 480)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
actualValue := actualTime.Unix()
|
||||
assert.Equal(t, expectedValue, actualValue)
|
||||
}
|
||||
|
||||
func TestParseFromLongDateTimeToMinUnixTime(t *testing.T) {
|
||||
expectedValue := int64(1690797600)
|
||||
actualTime, err := ParseFromLongDateTimeToMinUnixTime("2023-08-01 00:00:00")
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<v-select
|
||||
persistent-placeholder
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
:clearable="modelValue ? clearable : false"
|
||||
:label="label"
|
||||
:menu-props="{ 'content-class': 'date-select-menu' }"
|
||||
v-model="dateTime"
|
||||
>
|
||||
<template #selection>
|
||||
<span class="text-truncate cursor-pointer">{{ displayTime }}</span>
|
||||
</template>
|
||||
|
||||
<template #no-data>
|
||||
<vue-date-picker inline vertical auto-apply
|
||||
ref="datepicker"
|
||||
month-name-format="long"
|
||||
model-type="yyyy-MM-dd"
|
||||
:clearable="true"
|
||||
:enable-time-picker="false"
|
||||
:dark="isDarkMode"
|
||||
:week-start="firstDayOfWeek"
|
||||
:year-range="yearRange"
|
||||
:day-names="dayNames"
|
||||
:year-first="isYearFirst"
|
||||
v-model="dateTime">
|
||||
<template #month="{ text }">
|
||||
{{ getMonthShortName(text) }}
|
||||
</template>
|
||||
<template #month-overlay-value="{ text }">
|
||||
{{ getMonthShortName(text) }}
|
||||
</template>
|
||||
</vue-date-picker>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { useTheme } from 'vuetify';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import { ThemeType } from '@/core/theme.ts';
|
||||
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
|
||||
import { getCurrentYear } from '@/lib/datetime.ts';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string;
|
||||
disabled?: boolean;
|
||||
readonly?: boolean;
|
||||
clearable?: boolean;
|
||||
label?: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string): void;
|
||||
}>();
|
||||
|
||||
const theme = useTheme();
|
||||
const { tt, getAllMinWeekdayNames, getMonthShortName, formatDateToLongDate, isLongDateMonthAfterYear } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const yearRange = ref<number[]>([
|
||||
2000,
|
||||
getCurrentYear() + 1
|
||||
]);
|
||||
|
||||
const dateTime = computed<string>({
|
||||
get: () => props.modelValue ?? '',
|
||||
set: (value: string) => emit('update:modelValue', value)
|
||||
});
|
||||
|
||||
const isDarkMode = computed<boolean>(() => theme.global.name.value === ThemeType.Dark);
|
||||
const firstDayOfWeek = computed<number>(() => userStore.currentUserFirstDayOfWeek);
|
||||
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
|
||||
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
|
||||
const displayTime = computed<string>(() => {
|
||||
if (props.modelValue) {
|
||||
return formatDateToLongDate(props.modelValue);
|
||||
} else {
|
||||
return tt('Unspecified');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.date-select-menu {
|
||||
max-height: inherit !important;
|
||||
}
|
||||
|
||||
.date-select-menu .dp__menu {
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" class="date-selection-sheet" style="height:auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left">
|
||||
<f7-link :text="tt('Clear')" @click="clear"></f7-link>
|
||||
</div>
|
||||
<div class="right">
|
||||
<f7-link :text="tt('Done')" @click="confirm"></f7-link>
|
||||
</div>
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<div class="block block-outline no-margin no-padding">
|
||||
<vue-date-picker inline auto-apply
|
||||
month-name-format="long"
|
||||
model-type="yyyy-MM-dd"
|
||||
six-weeks="center"
|
||||
class="justify-content-center"
|
||||
:enable-time-picker="false"
|
||||
:clearable="true"
|
||||
:dark="isDarkMode"
|
||||
:week-start="firstDayOfWeek"
|
||||
:year-range="yearRange"
|
||||
:day-names="dayNames"
|
||||
:year-first="isYearFirst"
|
||||
v-model="dateTime">
|
||||
<template #month="{ text }">
|
||||
{{ getMonthShortName(text) }}
|
||||
</template>
|
||||
<template #month-overlay-value="{ text }">
|
||||
{{ getMonthShortName(text) }}
|
||||
</template>
|
||||
</vue-date-picker>
|
||||
</div>
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import { useI18n } from '@/locales/helpers.ts';
|
||||
|
||||
import { useEnvironmentsStore } from '@/stores/environment.ts';
|
||||
import { useUserStore } from '@/stores/user.ts';
|
||||
|
||||
import { arrangeArrayWithNewStartIndex } from '@/lib/common.ts';
|
||||
import { getCurrentYear } from '@/lib/datetime.ts';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string;
|
||||
show: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string): void;
|
||||
(e: 'update:show', value: boolean): void;
|
||||
}>();
|
||||
|
||||
const { tt, getAllMinWeekdayNames, getMonthShortName, isLongDateMonthAfterYear } = useI18n();
|
||||
|
||||
const environmentsStore = useEnvironmentsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const yearRange = ref<number[]>([
|
||||
2000,
|
||||
getCurrentYear() + 1
|
||||
]);
|
||||
const dateTime = ref<string>('');
|
||||
|
||||
const isDarkMode = computed<boolean>(() => environmentsStore.framework7DarkMode || false);
|
||||
const firstDayOfWeek = computed<number>(() => userStore.currentUserFirstDayOfWeek);
|
||||
const dayNames = computed<string[]>(() => arrangeArrayWithNewStartIndex(getAllMinWeekdayNames(), firstDayOfWeek.value));
|
||||
const isYearFirst = computed<boolean>(() => isLongDateMonthAfterYear());
|
||||
|
||||
function clear(): void {
|
||||
dateTime.value = '';
|
||||
confirm();
|
||||
}
|
||||
|
||||
function confirm(): void {
|
||||
emit('update:modelValue', dateTime.value);
|
||||
emit('update:show', false);
|
||||
}
|
||||
|
||||
function onSheetOpen(): void {
|
||||
dateTime.value = props.modelValue ?? '';
|
||||
}
|
||||
|
||||
function onSheetClosed(): void {
|
||||
emit('update:show', false);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.date-selection-sheet .dp__menu {
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -79,6 +79,7 @@ import ItemIcon from '@/components/desktop/ItemIcon.vue';
|
||||
import BtnVerticalGroup from '@/components/desktop/BtnVerticalGroup.vue';
|
||||
import AmountInput from '@/components/desktop/AmountInput.vue';
|
||||
import DateTimeSelect from '@/components/desktop/DateTimeSelect.vue';
|
||||
import DateSelect from '@/components/desktop/DateSelect.vue';
|
||||
import ColorSelect from '@/components/desktop/ColorSelect.vue';
|
||||
import IconSelect from '@/components/desktop/IconSelect.vue';
|
||||
import TwoColumnSelect from '@/components/desktop/TwoColumnSelect.vue';
|
||||
@@ -450,6 +451,7 @@ app.component('ItemIcon', ItemIcon);
|
||||
app.component('BtnVerticalGroup', BtnVerticalGroup);
|
||||
app.component('AmountInput', AmountInput);
|
||||
app.component('DateTimeSelect', DateTimeSelect);
|
||||
app.component('DateSelect', DateSelect);
|
||||
app.component('ColorSelect', ColorSelect);
|
||||
app.component('IconSelect', IconSelect);
|
||||
app.component('TwoColumnSelect', TwoColumnSelect);
|
||||
|
||||
@@ -199,6 +199,10 @@ export function formatCurrentTime(format: string): string {
|
||||
return moment().format(format);
|
||||
}
|
||||
|
||||
export function formatDate(date: string, format: string): string {
|
||||
return moment(date, 'YYYY-MM-DD').format(format);
|
||||
}
|
||||
|
||||
export function getUnixTime(date: SupportedDate): number {
|
||||
return moment(date).unix();
|
||||
}
|
||||
|
||||
@@ -1123,6 +1123,7 @@
|
||||
"scheduled transaction is not enabled": "Geplante Transaktion ist nicht aktiviert",
|
||||
"scheduled transaction frequency is invalid": "Häufigkeit der geplanten Transaktion ist ungültig",
|
||||
"transaction template has too many tags": "Transaktionsvorlage hat zu viele Tags",
|
||||
"scheduled transaction start date is later than end time": "Scheduled transaction start date is later than end time",
|
||||
"transaction picture id is invalid": "Transaktionsbild-ID ist ungültig",
|
||||
"transaction picture not found": "Transaktionsbild nicht gefunden",
|
||||
"no transaction picture": "Kein Transaktionsbild vorhanden",
|
||||
@@ -1289,6 +1290,8 @@
|
||||
"Previous Billing Cycle": "Vorheriger Abrechnungszeitraum",
|
||||
"Current Billing Cycle": "Aktueller Abrechnungszeitraum",
|
||||
"Custom Date": "Benutzerdefiniertes Datum",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
"Start Time": "Startzeit",
|
||||
"End Time": "Endzeit",
|
||||
"Select Date": "Datum auswählen",
|
||||
|
||||
@@ -1123,6 +1123,7 @@
|
||||
"scheduled transaction is not enabled": "Scheduled transaction is not enabled",
|
||||
"scheduled transaction frequency is invalid": "Scheduled transaction frequency is invalid",
|
||||
"transaction template has too many tags": "There are too many tags in this transaction template",
|
||||
"scheduled transaction start date is later than end time": "Scheduled transaction start date is later than end time",
|
||||
"transaction picture id is invalid": "Transaction picture ID is invalid",
|
||||
"transaction picture not found": "Transaction picture is not found",
|
||||
"no transaction picture": "There is no transaction picture file",
|
||||
@@ -1289,6 +1290,8 @@
|
||||
"Previous Billing Cycle": "Previous Billing Cycle",
|
||||
"Current Billing Cycle": "Current Billing Cycle",
|
||||
"Custom Date": "Custom Date",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
"Start Time": "Start Time",
|
||||
"End Time": "End Time",
|
||||
"Select Date": "Select Date",
|
||||
|
||||
@@ -1123,6 +1123,7 @@
|
||||
"scheduled transaction is not enabled": "La transacción programada no está habilitada",
|
||||
"scheduled transaction frequency is invalid": "La frecuencia de transacción programada no es válida",
|
||||
"transaction template has too many tags": "Hay demasiadas etiquetas en esta plantilla de transacción",
|
||||
"scheduled transaction start date is later than end time": "Scheduled transaction start date is later than end time",
|
||||
"transaction picture id is invalid": "El ID de la imagen de la transacción no es válido",
|
||||
"transaction picture not found": "No se encuentra la imagen de la transacción",
|
||||
"no transaction picture": "No hay ningún archivo de imagen de transacción.",
|
||||
@@ -1289,6 +1290,8 @@
|
||||
"Previous Billing Cycle": "Ciclo de facturación anterior",
|
||||
"Current Billing Cycle": "Ciclo de facturación actual",
|
||||
"Custom Date": "Fecha personalizada",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
"Start Time": "Hora de inicio",
|
||||
"End Time": "Hora de finalización",
|
||||
"Select Date": "Seleccionar fecha",
|
||||
|
||||
@@ -117,6 +117,7 @@ import {
|
||||
isPM,
|
||||
formatUnixTime,
|
||||
formatCurrentTime,
|
||||
formatDate,
|
||||
parseDateFromUnixTime,
|
||||
getYear,
|
||||
getTimezoneOffset,
|
||||
@@ -1297,6 +1298,10 @@ export function useI18n() {
|
||||
return getLocalizedDateTimeType(ShortTimeFormat.all(), ShortTimeFormat.values(), userStore.currentUserShortTimeFormat, 'shortTimeFormat', ShortTimeFormat.Default).isMeridiemIndicatorFirst || false;
|
||||
}
|
||||
|
||||
function formatDateToLongDate(date: string): string {
|
||||
return formatDate(date, getLocalizedLongDateFormat());
|
||||
}
|
||||
|
||||
function formatYearQuarter(year: number, quarter: number): string {
|
||||
if (1 <= quarter && quarter <= 4) {
|
||||
return t('format.yearQuarter.q' + quarter, {
|
||||
@@ -1713,6 +1718,7 @@ export function useI18n() {
|
||||
formatUnixTimeToShortMonthDay: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortMonthDayFormat(), utcOffset, currentUtcOffset),
|
||||
formatUnixTimeToLongTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedLongTimeFormat(), utcOffset, currentUtcOffset),
|
||||
formatUnixTimeToShortTime: (unixTime: number, utcOffset?: number, currentUtcOffset?: number) => formatUnixTime(unixTime, getLocalizedShortTimeFormat(), utcOffset, currentUtcOffset),
|
||||
formatDateToLongDate,
|
||||
formatYearQuarter,
|
||||
formatDateRange,
|
||||
getTimezoneDifferenceDisplayText,
|
||||
|
||||
@@ -1123,6 +1123,7 @@
|
||||
"scheduled transaction is not enabled": "Запланированная транзакция не включена",
|
||||
"scheduled transaction frequency is invalid": "Частота запланированной транзакции недействительна",
|
||||
"transaction template has too many tags": "Слишком много тегов в этом шаблоне транзакции",
|
||||
"scheduled transaction start date is later than end time": "Scheduled transaction start date is later than end time",
|
||||
"transaction picture id is invalid": "ID изображения транзакции недействителен",
|
||||
"transaction picture not found": "Изображение транзакции не найдено",
|
||||
"no transaction picture": "Нет файла изображения транзакции",
|
||||
@@ -1289,6 +1290,8 @@
|
||||
"Previous Billing Cycle": "Предыдущий расчетный период",
|
||||
"Current Billing Cycle": "Текущий расчетный период",
|
||||
"Custom Date": "Выбрать дату",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
"Start Time": "Время начала",
|
||||
"End Time": "Время окончания",
|
||||
"Select Date": "Выбрать дату",
|
||||
|
||||
@@ -1123,6 +1123,7 @@
|
||||
"scheduled transaction is not enabled": "Giao dịch theo lịch trình chưa được bật",
|
||||
"scheduled transaction frequency is invalid": "Tần suất giao dịch theo lịch trình không hợp lệ",
|
||||
"transaction template has too many tags": "Có quá nhiều thẻ trong mẫu giao dịch này",
|
||||
"scheduled transaction start date is later than end time": "Scheduled transaction start date is later than end time",
|
||||
"transaction picture id is invalid": "ID ảnh giao dịch không hợp lệ",
|
||||
"transaction picture not found": "Không tìm thấy ảnh giao dịch",
|
||||
"no transaction picture": "Không có tệp ảnh giao dịch",
|
||||
@@ -1289,6 +1290,8 @@
|
||||
"Previous Billing Cycle": "Previous Billing Cycle",
|
||||
"Current Billing Cycle": "Current Billing Cycle",
|
||||
"Custom Date": "Ngày tùy chỉnh",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
"Start Time": "Thời gian bắt đầu",
|
||||
"End Time": "Thời gian kết thúc",
|
||||
"Select Date": "Chọn ngày",
|
||||
|
||||
@@ -1123,6 +1123,7 @@
|
||||
"scheduled transaction is not enabled": "定时交易没有启用",
|
||||
"scheduled transaction frequency is invalid": "定时交易周期无效",
|
||||
"transaction template has too many tags": "交易模板中的标签过多",
|
||||
"scheduled transaction start date is later than end time": "定时交易开始时间晚于结束时间",
|
||||
"transaction picture id is invalid": "交易图片ID无效",
|
||||
"transaction picture not found": "交易图片不存在",
|
||||
"no transaction picture": "没有交易图片文件",
|
||||
@@ -1289,6 +1290,8 @@
|
||||
"Previous Billing Cycle": "上个账单周期",
|
||||
"Current Billing Cycle": "当前账单周期",
|
||||
"Custom Date": "自定义日期",
|
||||
"Start Date": "开始日期",
|
||||
"End Date": "结束日期",
|
||||
"Start Time": "开始时间",
|
||||
"End Time": "结束时间",
|
||||
"Select Date": "选择日期",
|
||||
|
||||
@@ -92,6 +92,7 @@ import PinCodeInputSheet from '@/components/mobile/PinCodeInputSheet.vue';
|
||||
import PasswordInputSheet from '@/components/mobile/PasswordInputSheet.vue';
|
||||
import PasscodeInputSheet from '@/components/mobile/PasscodeInputSheet.vue';
|
||||
import DateTimeSelectionSheet from '@/components/mobile/DateTimeSelectionSheet.vue';
|
||||
import DateSelectionSheet from '@/components/mobile/DateSelectionSheet.vue';
|
||||
import DateRangeSelectionSheet from '@/components/mobile/DateRangeSelectionSheet.vue';
|
||||
import MonthRangeSelectionSheet from '@/components/mobile/MonthRangeSelectionSheet.vue';
|
||||
import ListItemSelectionSheet from '@/components/mobile/ListItemSelectionSheet.vue';
|
||||
@@ -175,6 +176,7 @@ app.component('PinCodeInputSheet', PinCodeInputSheet);
|
||||
app.component('PasswordInputSheet', PasswordInputSheet);
|
||||
app.component('PasscodeInputSheet', PasscodeInputSheet);
|
||||
app.component('DateTimeSelectionSheet', DateTimeSelectionSheet);
|
||||
app.component('DateSelectionSheet', DateSelectionSheet);
|
||||
app.component('DateRangeSelectionSheet', DateRangeSelectionSheet);
|
||||
app.component('MonthRangeSelectionSheet', MonthRangeSelectionSheet);
|
||||
app.component('ListItemSelectionSheet', ListItemSelectionSheet);
|
||||
|
||||
@@ -8,16 +8,20 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
|
||||
public name: string;
|
||||
public scheduledFrequencyType?: number;
|
||||
public scheduledFrequency?: string;
|
||||
public scheduledStartDate?: string;
|
||||
public scheduledEndDate?: string;
|
||||
public scheduledAt?: number;
|
||||
public displayOrder: number;
|
||||
public hidden: boolean;
|
||||
|
||||
private constructor(id: string, templateType: number, name: string, type: number, categoryId: string, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, scheduledFrequencyType: number | undefined, scheduledFrequency: string | undefined, scheduledAt: number | undefined, tagIds: string[], comment: string, editable: boolean, displayOrder: number, hidden: boolean) {
|
||||
private constructor(id: string, templateType: number, name: string, type: number, categoryId: string, utcOffset: number, sourceAccountId: string, destinationAccountId: string, sourceAmount: number, destinationAmount: number, hideAmount: boolean, scheduledFrequencyType: number | undefined, scheduledFrequency: string | undefined, scheduledStartDate: string | undefined, scheduledEndDate: string | undefined, scheduledAt: number | undefined, tagIds: string[], comment: string, editable: boolean, displayOrder: number, hidden: boolean) {
|
||||
super(id, '', type, categoryId, 0, undefined, utcOffset, sourceAccountId, destinationAccountId, sourceAmount, destinationAmount, hideAmount, tagIds, comment, editable);
|
||||
this.templateType = templateType;
|
||||
this.name = name;
|
||||
this.scheduledFrequencyType = scheduledFrequencyType;
|
||||
this.scheduledFrequency = scheduledFrequency;
|
||||
this.scheduledStartDate = scheduledStartDate;
|
||||
this.scheduledEndDate = scheduledEndDate;
|
||||
this.scheduledAt = scheduledAt;
|
||||
this.displayOrder = displayOrder;
|
||||
this.hidden = hidden;
|
||||
@@ -30,6 +34,8 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
|
||||
if (this.templateType === TemplateType.Schedule.type) {
|
||||
this.scheduledFrequencyType = other.scheduledFrequencyType;
|
||||
this.scheduledFrequency = other.scheduledFrequency;
|
||||
this.scheduledStartDate = other.scheduledStartDate;
|
||||
this.scheduledEndDate = other.scheduledEndDate;
|
||||
this.utcOffset = other.utcOffset;
|
||||
this.timeZone = undefined;
|
||||
}
|
||||
@@ -50,6 +56,8 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
|
||||
comment: this.comment,
|
||||
scheduledFrequencyType: this.templateType === TemplateType.Schedule.type ? this.scheduledFrequencyType : undefined,
|
||||
scheduledFrequency: this.templateType === TemplateType.Schedule.type ? this.scheduledFrequency : undefined,
|
||||
scheduledStartDate: this.templateType === TemplateType.Schedule.type && this.scheduledStartDate ? this.scheduledStartDate : undefined,
|
||||
scheduledEndDate: this.templateType === TemplateType.Schedule.type && this.scheduledEndDate ? this.scheduledEndDate : undefined,
|
||||
utcOffset: this.templateType === TemplateType.Schedule.type ? this.utcOffset : undefined,
|
||||
clientSessionId: clientSessionId
|
||||
};
|
||||
@@ -70,6 +78,8 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
|
||||
comment: this.comment,
|
||||
scheduledFrequencyType: this.templateType === TemplateType.Schedule.type ? this.scheduledFrequencyType : undefined,
|
||||
scheduledFrequency: this.templateType === TemplateType.Schedule.type ? this.scheduledFrequency : undefined,
|
||||
scheduledStartDate: this.templateType === TemplateType.Schedule.type && this.scheduledStartDate ? this.scheduledStartDate : undefined,
|
||||
scheduledEndDate: this.templateType === TemplateType.Schedule.type && this.scheduledEndDate ? this.scheduledEndDate : undefined,
|
||||
utcOffset: this.templateType === TemplateType.Schedule.type ? this.utcOffset : undefined
|
||||
};
|
||||
}
|
||||
@@ -89,6 +99,8 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
|
||||
transaction.hideAmount,
|
||||
undefined, // scheduledFrequencyType
|
||||
undefined, // scheduledFrequency
|
||||
undefined, // scheduledStartDate
|
||||
undefined, // scheduledEndDate
|
||||
undefined, // scheduledAt
|
||||
transaction.tagIds,
|
||||
transaction.comment,
|
||||
@@ -113,6 +125,8 @@ export class TransactionTemplate extends Transaction implements TransactionTempl
|
||||
templateResponse.hideAmount,
|
||||
templateResponse.scheduledFrequencyType,
|
||||
templateResponse.scheduledFrequency,
|
||||
templateResponse.scheduledStartDate ?? undefined,
|
||||
templateResponse.scheduledEndDate ?? undefined,
|
||||
templateResponse.scheduledAt,
|
||||
templateResponse.tagIds,
|
||||
templateResponse.comment,
|
||||
@@ -147,6 +161,8 @@ export interface TransactionTemplateCreateRequest {
|
||||
readonly comment: string;
|
||||
readonly scheduledFrequencyType?: number;
|
||||
readonly scheduledFrequency?: string;
|
||||
readonly scheduledStartDate?: string;
|
||||
readonly scheduledEndDate?: string;
|
||||
readonly utcOffset?: number;
|
||||
readonly clientSessionId: string;
|
||||
}
|
||||
@@ -165,6 +181,8 @@ export interface TransactionTemplateModifyRequest {
|
||||
readonly comment: string;
|
||||
readonly scheduledFrequencyType?: number;
|
||||
readonly scheduledFrequency?: string;
|
||||
readonly scheduledStartDate?: string;
|
||||
readonly scheduledEndDate?: string;
|
||||
readonly utcOffset?: number;
|
||||
}
|
||||
|
||||
@@ -191,6 +209,8 @@ export interface TransactionTemplateInfoResponse extends TransactionInfoResponse
|
||||
readonly name: string;
|
||||
readonly scheduledFrequencyType?: number;
|
||||
readonly scheduledFrequency?: string;
|
||||
readonly scheduledStartDate?: string;
|
||||
readonly scheduledEndDate?: string;
|
||||
readonly scheduledAt?: number;
|
||||
readonly displayOrder: number;
|
||||
readonly hidden: boolean;
|
||||
|
||||
@@ -235,6 +235,22 @@
|
||||
</template>
|
||||
</v-autocomplete>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6" v-if="type === TransactionEditPageType.Template && transaction instanceof TransactionTemplate && transaction.templateType === TemplateType.Schedule.type">
|
||||
<date-select
|
||||
:readonly="mode === TransactionEditPageMode.View"
|
||||
:disabled="loading || submitting"
|
||||
:clearable="true"
|
||||
:label="tt('Start Date')"
|
||||
v-model="transaction.scheduledStartDate" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6" v-if="type === TransactionEditPageType.Template && transaction instanceof TransactionTemplate && transaction.templateType === TemplateType.Schedule.type">
|
||||
<date-select
|
||||
:readonly="mode === TransactionEditPageMode.View"
|
||||
:disabled="loading || submitting"
|
||||
:clearable="true"
|
||||
:label="tt('End Date')"
|
||||
v-model="transaction.scheduledEndDate" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="12" v-if="type === TransactionEditPageType.Transaction">
|
||||
<v-select
|
||||
persistent-placeholder
|
||||
|
||||
@@ -271,6 +271,34 @@
|
||||
</schedule-frequency-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
class="transaction-edit-datetime list-item-with-header-and-title"
|
||||
link="#" no-chevron
|
||||
:class="{ 'readonly': mode === TransactionEditPageMode.View }"
|
||||
:header="tt('Start Date')"
|
||||
:title="transactionDisplayScheduledStartDate"
|
||||
@click="showScheduledStartDateSheet = true"
|
||||
v-if="pageTypeAndMode?.type === TransactionEditPageType.Template && transaction instanceof TransactionTemplate && transaction.templateType === TemplateType.Schedule.type"
|
||||
>
|
||||
<date-selection-sheet v-model:show="showScheduledStartDateSheet"
|
||||
v-model="transaction.scheduledStartDate">
|
||||
</date-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
class="transaction-edit-datetime list-item-with-header-and-title"
|
||||
link="#" no-chevron
|
||||
:class="{ 'readonly': mode === TransactionEditPageMode.View }"
|
||||
:header="tt('End Date')"
|
||||
:title="transactionDisplayScheduledEndDate"
|
||||
@click="showScheduledEndDateSheet = true"
|
||||
v-if="pageTypeAndMode?.type === TransactionEditPageType.Template && transaction instanceof TransactionTemplate && transaction.templateType === TemplateType.Schedule.type"
|
||||
>
|
||||
<date-selection-sheet v-model:show="showScheduledEndDateSheet"
|
||||
v-model="transaction.scheduledEndDate">
|
||||
</date-selection-sheet>
|
||||
</f7-list-item>
|
||||
|
||||
<f7-list-item
|
||||
:no-chevron="mode === TransactionEditPageMode.View"
|
||||
class="list-item-with-header-and-title list-item-title-hide-overflow list-item-no-item-after"
|
||||
@@ -497,7 +525,8 @@ const {
|
||||
getMultiMonthdayShortNames,
|
||||
getMultiWeekdayLongNames,
|
||||
formatUnixTimeToLongDate,
|
||||
formatUnixTimeToLongTime
|
||||
formatUnixTimeToLongTime,
|
||||
formatDateToLongDate
|
||||
} = useI18n();
|
||||
const { showAlert, showConfirm, showToast, routeBackOnError } = useI18nUIComponents();
|
||||
|
||||
@@ -574,6 +603,8 @@ const showSourceAccountSheet = ref<boolean>(false);
|
||||
const showDestinationAccountSheet = ref<boolean>(false);
|
||||
const showTransactionDateTimeSheet = ref<boolean>(false);
|
||||
const showTransactionScheduledFrequencySheet = ref<boolean>(false);
|
||||
const showScheduledStartDateSheet = ref<boolean>(false);
|
||||
const showScheduledEndDateSheet = ref<boolean>(false);
|
||||
const showGeoLocationMapSheet = ref<boolean>(false);
|
||||
const showTransactionTagSheet = ref<boolean>(false);
|
||||
const showTransactionPictures = ref<boolean>(false);
|
||||
@@ -700,6 +731,34 @@ const transactionDisplayScheduledFrequency = computed<string>(() => {
|
||||
}
|
||||
});
|
||||
|
||||
const transactionDisplayScheduledStartDate = computed<string>(() => {
|
||||
if (pageTypeAndMode?.type !== TransactionEditPageType.Template) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const template = transaction.value as TransactionTemplate;
|
||||
|
||||
if (template.scheduledStartDate) {
|
||||
return formatDateToLongDate(template.scheduledStartDate);
|
||||
} else {
|
||||
return tt('Unspecified');
|
||||
}
|
||||
});
|
||||
|
||||
const transactionDisplayScheduledEndDate = computed<string>(() => {
|
||||
if (pageTypeAndMode?.type !== TransactionEditPageType.Template) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const template = transaction.value as TransactionTemplate;
|
||||
|
||||
if (template.scheduledEndDate) {
|
||||
return formatDateToLongDate(template.scheduledEndDate);
|
||||
} else {
|
||||
return tt('Unspecified');
|
||||
}
|
||||
});
|
||||
|
||||
function getPageTypeNameMode(): { type: TransactionEditPageType, mode: TransactionEditPageMode } | null {
|
||||
if (props.f7route.path === '/transaction/add') {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user