diff --git a/backend/controllers/diaryController.js b/backend/controllers/diaryController.js
index e2f0587e..768f772c 100644
--- a/backend/controllers/diaryController.js
+++ b/backend/controllers/diaryController.js
@@ -18,14 +18,14 @@ const createDateForClub = async (req, res) => {
try {
const { clubId } = req.params;
const { authcode: userToken } = req.headers;
- const { date, trainingStart, trainingEnd } = req.body;
+ const { date, trainingStart, trainingEnd, excludeFromBilling } = req.body;
if (!date) {
throw new HttpError('The date field is required', 400);
}
if (isNaN(new Date(date).getTime())) {
throw new HttpError('Invalid date format', 400);
}
- const newDate = await diaryService.createDateForClub(userToken, clubId, date, trainingStart, trainingEnd);
+ const newDate = await diaryService.createDateForClub(userToken, clubId, date, trainingStart, trainingEnd, excludeFromBilling);
res.status(201).json(newDate);
} catch (error) {
console.error('[createDateForClub] - Error:', error);
@@ -37,15 +37,22 @@ const updateTrainingTimes = async (req, res) => {
try {
const { clubId } = req.params;
const { authcode: userToken } = req.headers;
- const { dateId, trainingStart, trainingEnd } = req.body;
- if (!dateId || !trainingStart) {
- devLog(dateId, trainingStart, trainingEnd);
+ const { dateId, trainingStart, trainingEnd, excludeFromBilling } = req.body;
+ if (!dateId) {
+ devLog(dateId, trainingStart, trainingEnd, excludeFromBilling);
throw new HttpError('notallfieldsfilled', 400);
}
- const updatedDate = await diaryService.updateTrainingTimes(userToken, clubId, dateId, trainingStart, trainingEnd);
+ const updatedDate = await diaryService.updateTrainingTimes(
+ userToken,
+ clubId,
+ dateId,
+ trainingStart,
+ trainingEnd,
+ excludeFromBilling,
+ );
// Emit Socket-Event
- emitDiaryDateUpdated(clubId, dateId, { trainingStart, trainingEnd });
+ emitDiaryDateUpdated(clubId, dateId, { trainingStart, trainingEnd, excludeFromBilling });
res.status(200).json(updatedDate);
} catch (error) {
diff --git a/backend/models/DiaryDates.js b/backend/models/DiaryDates.js
index 86082f5c..ef845f7f 100644
--- a/backend/models/DiaryDates.js
+++ b/backend/models/DiaryDates.js
@@ -23,6 +23,12 @@ const DiaryDate = sequelize.define('DiaryDate', {
trainingEnd: {
type: DataTypes.TIME,
allowNull: true,
+ },
+ excludeFromBilling: {
+ type: DataTypes.BOOLEAN,
+ allowNull: false,
+ defaultValue: false,
+ field: 'exclude_from_billing',
}
}, {
tableName: 'diary_dates',
diff --git a/backend/services/billingService.js b/backend/services/billingService.js
index 4d233cde..fee3dfa7 100644
--- a/backend/services/billingService.js
+++ b/backend/services/billingService.js
@@ -321,7 +321,8 @@ class BillingService {
clubId,
date: { [Op.between]: [periodStart, periodEnd] },
trainingStart: { [Op.ne]: null },
- trainingEnd: { [Op.ne]: null }
+ trainingEnd: { [Op.ne]: null },
+ excludeFromBilling: false,
},
attributes: ['date', 'trainingStart', 'trainingEnd'],
order: [['date', 'ASC'], ['trainingStart', 'ASC']]
diff --git a/backend/services/diaryService.js b/backend/services/diaryService.js
index 1e8a64b9..2d0e9f3f 100644
--- a/backend/services/diaryService.js
+++ b/backend/services/diaryService.js
@@ -26,7 +26,7 @@ class DiaryService {
return dates;
}
- async createDateForClub(userToken, clubId, date, trainingStart, trainingEnd) {
+ async createDateForClub(userToken, clubId, date, trainingStart, trainingEnd, excludeFromBilling = false) {
await checkAccess(userToken, clubId);
const club = await Club.findByPk(clubId);
if (!club) {
@@ -44,12 +44,13 @@ class DiaryService {
clubId,
trainingStart: trainingStart || null,
trainingEnd: trainingEnd || null,
+ excludeFromBilling: Boolean(excludeFromBilling),
});
return newDate;
}
- async updateTrainingTimes(userToken, clubId, dateId, trainingStart, trainingEnd) {
+ async updateTrainingTimes(userToken, clubId, dateId, trainingStart, trainingEnd, excludeFromBilling) {
await checkAccess(userToken, clubId);
const diaryDate = await DiaryDate.findOne({ where: { clubId, id: dateId } });
if (!diaryDate) {
@@ -60,6 +61,9 @@ class DiaryService {
}
diaryDate.trainingStart = trainingStart || null;
diaryDate.trainingEnd = trainingEnd || null;
+ if (excludeFromBilling !== undefined) {
+ diaryDate.excludeFromBilling = Boolean(excludeFromBilling);
+ }
await diaryDate.save();
return diaryDate;
}
diff --git a/frontend/src/components/diary/DiaryOverviewPanels.vue b/frontend/src/components/diary/DiaryOverviewPanels.vue
index 38391382..b1ba7d52 100644
--- a/frontend/src/components/diary/DiaryOverviewPanels.vue
+++ b/frontend/src/components/diary/DiaryOverviewPanels.vue
@@ -51,6 +51,17 @@
+
+
+
@@ -120,11 +131,12 @@ export default {
activitiesCount: { type: Number, default: 0 },
trainingStart: { type: String, default: '' },
trainingEnd: { type: String, default: '' },
+ excludeFromBilling: { type: Boolean, default: false },
groups: { type: Array, required: true },
editingGroupId: { type: [Number, String, null], default: null },
newGroupCount: { type: Number, default: 2 }
},
- emits: ['toggle-panel', 'update-training-times', 'update:training-start', 'update:training-end', 'edit-group', 'update-group-field', 'save-group', 'cancel-edit-group', 'delete-group', 'update:new-group-count', 'create-groups']
+ emits: ['toggle-panel', 'update-training-times', 'update:training-start', 'update:training-end', 'update:exclude-from-billing', 'edit-group', 'update-group-field', 'save-group', 'cancel-edit-group', 'delete-group', 'update:new-group-count', 'create-groups']
};
@@ -243,6 +255,20 @@ export default {
margin-bottom: 0.25rem;
}
+.diary-billing-toggle-wrap {
+ display: flex;
+ align-items: center;
+ min-height: 2.5rem;
+}
+
+.diary-billing-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.45rem;
+ font-weight: 600;
+ color: #173042;
+}
+
.diary-groups-grid {
display: grid;
grid-template-columns: 1.4fr 1fr;
diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue
index 065775ef..bc4a9e2e 100644
--- a/frontend/src/views/DiaryView.vue
+++ b/frontend/src/views/DiaryView.vue
@@ -68,6 +68,12 @@
+
+
+
@@ -83,6 +89,7 @@
:activities-count="activities.length"
:training-start="trainingStart"
:training-end="trainingEnd"
+ :exclude-from-billing="excludeFromBilling"
:groups="groups"
:editing-group-id="editingGroupId"
:new-group-count="newGroupCount"
@@ -90,6 +97,7 @@
@update-training-times="updateTrainingTimes"
@update:training-start="trainingStart = $event"
@update:training-end="trainingEnd = $event"
+ @update:exclude-from-billing="excludeFromBilling = $event"
@edit-group="editGroup"
@update-group-field="updateGroupField"
@save-group="saveGroup"
@@ -977,6 +985,7 @@ export default {
newDate: '',
trainingStart: '',
trainingEnd: '',
+ excludeFromBilling: false,
members: [],
participants: [],
showTrainingGroupDialog: false,
@@ -1780,6 +1789,7 @@ export default {
date: slot.date,
trainingStart: slot.startTime || null,
trainingEnd: slot.endTime || null,
+ excludeFromBilling: false,
});
await this.refreshDates(post.data.id);
await this.handleDateChange();
@@ -1799,6 +1809,7 @@ export default {
const dateData = response.data.find(entry => entry.id === dateId);
this.trainingStart = dateData.trainingStart;
this.trainingEnd = dateData.trainingEnd;
+ this.excludeFromBilling = Boolean(dateData.excludeFromBilling);
this.selectedActivityTags = dateData.diaryTags.map(tag => ({
id: tag.id,
name: tag.name
@@ -1816,6 +1827,7 @@ export default {
this.newDate = '';
this.trainingStart = '';
this.trainingEnd = '';
+ this.excludeFromBilling = false;
this.participants = [];
}
},
@@ -1836,6 +1848,7 @@ export default {
date: this.newDate,
trainingStart: this.trainingStart || null,
trainingEnd: this.trainingEnd || null,
+ excludeFromBilling: this.excludeFromBilling,
});
this.dates.push({ id: response.data.id, date: response.data.date });
// Liste nach Datum sortieren (neueste zuerst)
@@ -1844,6 +1857,7 @@ export default {
this.newDate = '';
this.trainingStart = response.data.trainingStart;
this.trainingEnd = response.data.trainingEnd;
+ this.excludeFromBilling = Boolean(response.data.excludeFromBilling);
// Direkt auf das leere Tagebuch des neuen Datums wechseln
await this.handleDateChange();
} catch (error) {
@@ -1858,6 +1872,7 @@ export default {
dateId,
trainingStart: this.trainingStart || null,
trainingEnd: this.trainingEnd || null,
+ excludeFromBilling: this.excludeFromBilling,
});
this.showInfo(this.$t('messages.success'), this.$t('diary.trainingTimesUpdated'), '', 'success');
} catch (error) {
@@ -4332,6 +4347,9 @@ export default {
if (data.updates.trainingEnd !== undefined) {
this.trainingEnd = data.updates.trainingEnd;
}
+ if (data.updates.excludeFromBilling !== undefined) {
+ this.excludeFromBilling = Boolean(data.updates.excludeFromBilling);
+ }
}
},
diff --git a/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/AppRoot.kt b/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/AppRoot.kt
index c7b1ffb4..02cdf60b 100644
--- a/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/AppRoot.kt
+++ b/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/AppRoot.kt
@@ -1588,6 +1588,7 @@ private fun DiaryListScreen(
var newDiaryDateStr by rememberSaveable { mutableStateOf("") }
var newDiaryStart by rememberSaveable { mutableStateOf("") }
var newDiaryEnd by rememberSaveable { mutableStateOf("") }
+ var newDiaryExcludeFromBilling by rememberSaveable { mutableStateOf(false) }
val newDateScope = rememberCoroutineScope()
var newDateScheduleGroups by remember { mutableStateOf>(emptyList()) }
var newDateScheduleLoading by remember { mutableStateOf(false) }
@@ -1735,6 +1736,7 @@ private fun DiaryListScreen(
newDiaryDateStr = kotlin.runCatching { java.time.LocalDate.now().toString() }.getOrElse { "" }
newDiaryStart = diaryTimeForFormField(tmpl?.trainingStart).ifBlank { "17:30" }
newDiaryEnd = diaryTimeForFormField(tmpl?.trainingEnd).ifBlank { "19:30" }
+ newDiaryExcludeFromBilling = false
showNewDateDialog = true
},
modifier = Modifier.heightIn(min = TouchMinHeight),
@@ -1774,6 +1776,7 @@ private fun DiaryListScreen(
slot.date,
diaryTimeFieldToApi(slot.trainingStart),
diaryTimeFieldToApi(slot.trainingEnd),
+ excludeFromBilling = false,
)
quickCreateBusy = false
if (id != null) {
@@ -1922,6 +1925,20 @@ private fun DiaryListScreen(
enabled = !diaryState.isLoading,
modifier = Modifier.fillMaxWidth(),
)
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Text("Nicht abrechnen")
+ Switch(
+ checked = newDiaryExcludeFromBilling,
+ onCheckedChange = { newDiaryExcludeFromBilling = it },
+ enabled = !diaryState.isLoading,
+ )
+ }
diaryState.error?.let { err ->
Text(
err,
@@ -1941,6 +1958,7 @@ private fun DiaryListScreen(
newDiaryDateStr.trim(),
diaryTimeFieldToApi(newDiaryStart),
diaryTimeFieldToApi(newDiaryEnd),
+ newDiaryExcludeFromBilling,
)
if (id != null) {
showNewDateDialog = false
@@ -2775,10 +2793,11 @@ private fun DiaryDetailScreen(
initialDate = entry.date.take(10),
initialStart = entry.trainingStart.orEmpty(),
initialEnd = entry.trainingEnd.orEmpty(),
+ initialExcludeFromBilling = entry.excludeFromBilling,
submitLabel = tr("common.save", "Speichern"),
- onSubmit = { _, start, end ->
+ onSubmit = { _, start, end, excludeFromBilling ->
dependencies.applicationScope.launch {
- dependencies.diaryManager.updateTimes(clubId, entry.id, start, end)
+ dependencies.diaryManager.updateTimes(clubId, entry.id, start, end, excludeFromBilling)
showEdit = false
}
},
@@ -6878,14 +6897,16 @@ private fun DeleteAccountDialog(
@Composable
private fun DiaryEditForm(
submitLabel: String,
- onSubmit: (date: String, trainingStart: String?, trainingEnd: String?) -> Unit,
+ onSubmit: (date: String, trainingStart: String?, trainingEnd: String?, excludeFromBilling: Boolean) -> Unit,
initialDate: String = "",
initialStart: String = "",
initialEnd: String = "",
+ initialExcludeFromBilling: Boolean = false,
) {
var date by rememberSaveable { mutableStateOf(initialDate) }
var start by rememberSaveable { mutableStateOf(initialStart) }
var end by rememberSaveable { mutableStateOf(initialEnd) }
+ var excludeFromBilling by rememberSaveable { mutableStateOf(initialExcludeFromBilling) }
var error by rememberSaveable { mutableStateOf(null) }
Card(modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp), elevation = 2.dp) {
@@ -6895,6 +6916,17 @@ private fun DiaryEditForm(
OutlinedTextField(value = start, onValueChange = { start = it }, label = { Text("Start") }, modifier = Modifier.weight(1f), singleLine = true)
OutlinedTextField(value = end, onValueChange = { end = it }, label = { Text("Ende") }, modifier = Modifier.weight(1f), singleLine = true)
}
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Text("Nicht abrechnen")
+ Switch(
+ checked = excludeFromBilling,
+ onCheckedChange = { excludeFromBilling = it },
+ )
+ }
ErrorText(error)
Button(onClick = {
if (!date.matches(Regex("\\d{4}-\\d{2}-\\d{2}"))) {
@@ -6906,7 +6938,7 @@ private fun DiaryEditForm(
return@Button
}
error = null
- onSubmit(date, start.takeIf { it.isNotBlank() }, end.takeIf { it.isNotBlank() })
+ onSubmit(date, start.takeIf { it.isNotBlank() }, end.takeIf { it.isNotBlank() }, excludeFromBilling)
}) {
Text(submitLabel)
}
diff --git a/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/BillingOrdersScreens.kt b/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/BillingOrdersScreens.kt
index 77897401..177f15ee 100644
--- a/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/BillingOrdersScreens.kt
+++ b/mobile-app/composeApp/src/androidMain/kotlin/de/tsschulz/tt_tagebuch/app/ui/BillingOrdersScreens.kt
@@ -197,6 +197,65 @@ private fun GlobalOrdersScreen(dependencies: AppDependencies, onBack: () -> Unit
}
}
+ fun quickSaveFlags(orderId: Int, nextStatus: String? = null, nextPaidConfirmed: Boolean? = null) {
+ val snapshot = rows.firstOrNull { it.order.id == orderId } ?: return
+ val patchedStatus = nextStatus ?: snapshot.draftStatus
+ val patchedPaidConfirmed = nextPaidConfirmed ?: snapshot.draftPaidConfirmed
+ val memberId = snapshot.order.memberId ?: return
+ val orderClubId = snapshot.order.clubId ?: return
+
+ rows = rows.map {
+ if (it.order.id == orderId) {
+ it.copy(
+ draftStatus = patchedStatus,
+ draftPaidConfirmed = patchedPaidConfirmed,
+ )
+ } else {
+ it
+ }
+ }
+
+ scope.launch {
+ savingIds = savingIds + orderId
+ runCatching {
+ dependencies.memberOrdersApi.update(
+ clubId = orderClubId,
+ memberId = memberId,
+ orderId = orderId,
+ body = MemberOrderPatchBody(
+ // Nur Status-Flags sofort speichern; restliche Felder bleiben Draft bis "Speichern".
+ item = snapshot.order.item,
+ status = patchedStatus,
+ cost = normalizeAmount(snapshot.order.cost),
+ paidAmount = normalizeAmount(snapshot.order.paidAmount),
+ budget = normalizeAmount(snapshot.order.budget),
+ paidConfirmed = patchedPaidConfirmed,
+ ),
+ ).order
+ }.onSuccess { updated ->
+ if (updated != null) {
+ rows = rows.map { row ->
+ if (row.order.id == orderId) {
+ row.copy(
+ order = updated,
+ draftStatus = updated.status,
+ draftPaidConfirmed = updated.paidConfirmed,
+ )
+ } else {
+ row
+ }
+ }
+ }
+ }.onFailure { e ->
+ rows = rows.map {
+ if (it.order.id == orderId) snapshot else it
+ }
+ err = e.message
+ }
+ savingIds = savingIds - orderId
+ }
+ }
+
Column(
modifier = Modifier
.fillMaxSize()
@@ -338,8 +397,9 @@ private fun GlobalOrdersScreen(dependencies: AppDependencies, onBack: () -> Unit
orderStatuses.forEach { (v, k) ->
TextButton(
onClick = {
- rows = rows.map { if (it.order.id == o.id) it.copy(draftStatus = v) else it }
+ quickSaveFlags(orderId = o.id, nextStatus = v)
},
+ enabled = !savingIds.contains(o.id),
) {
Text(
tr(k, v),
@@ -373,8 +433,9 @@ private fun GlobalOrdersScreen(dependencies: AppDependencies, onBack: () -> Unit
Switch(
checked = row.draftPaidConfirmed,
onCheckedChange = { v ->
- rows = rows.map { if (it.order.id == o.id) it.copy(draftPaidConfirmed = v) else it }
+ quickSaveFlags(orderId = o.id, nextPaidConfirmed = v)
},
+ enabled = !savingIds.contains(o.id),
)
Text(tr("orders.paidConfirmed", "Bezahlt bestÃĪtigt"), modifier = Modifier.padding(start = 8.dp))
}
diff --git a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/DiaryApi.kt b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/DiaryApi.kt
index b51a5587..4124691c 100644
--- a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/DiaryApi.kt
+++ b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/DiaryApi.kt
@@ -83,15 +83,27 @@ class DiaryApi(
client.http.delete("/api/diary-date-activities/group/$clubId/$groupActivityId")
}
- suspend fun createDate(clubId: Int, date: String, trainingStart: String?, trainingEnd: String?): DiaryDate {
+ suspend fun createDate(
+ clubId: Int,
+ date: String,
+ trainingStart: String?,
+ trainingEnd: String?,
+ excludeFromBilling: Boolean = false,
+ ): DiaryDate {
return client.http.post("/api/diary/$clubId") {
- setBody(CreateDiaryDateRequest(date, trainingStart, trainingEnd))
+ setBody(CreateDiaryDateRequest(date, trainingStart, trainingEnd, excludeFromBilling))
}.body()
}
- suspend fun updateTimes(clubId: Int, dateId: Int, trainingStart: String?, trainingEnd: String?): DiaryDate {
+ suspend fun updateTimes(
+ clubId: Int,
+ dateId: Int,
+ trainingStart: String?,
+ trainingEnd: String?,
+ excludeFromBilling: Boolean? = null,
+ ): DiaryDate {
return client.http.put("/api/diary/$clubId") {
- setBody(UpdateDiaryTimesRequest(dateId, trainingStart, trainingEnd))
+ setBody(UpdateDiaryTimesRequest(dateId, trainingStart, trainingEnd, excludeFromBilling))
}.body()
}
diff --git a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/models/DiaryDate.kt b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/models/DiaryDate.kt
index 29898155..f84dc7a5 100644
--- a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/models/DiaryDate.kt
+++ b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/api/models/DiaryDate.kt
@@ -9,6 +9,7 @@ data class DiaryDate(
val date: String,
val trainingStart: String? = null,
val trainingEnd: String? = null,
+ val excludeFromBilling: Boolean = false,
val diaryNotes: List = emptyList(),
val diaryTags: List = emptyList(),
)
@@ -31,6 +32,7 @@ data class CreateDiaryDateRequest(
val date: String,
val trainingStart: String? = null,
val trainingEnd: String? = null,
+ val excludeFromBilling: Boolean = false,
)
@Serializable
@@ -38,6 +40,7 @@ data class UpdateDiaryTimesRequest(
val dateId: Int,
val trainingStart: String? = null,
val trainingEnd: String? = null,
+ val excludeFromBilling: Boolean? = null,
)
@Serializable
diff --git a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/models/Models.kt b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/models/Models.kt
index b7859e0d..e6d7e2fc 100644
--- a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/models/Models.kt
+++ b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/models/Models.kt
@@ -31,6 +31,7 @@ data class DiaryDate(
val clubId: Int,
val trainingStart: String? = null,
val trainingEnd: String? = null,
+ val excludeFromBilling: Boolean = false,
val activities: List = emptyList(),
val participants: List = emptyList()
)
diff --git a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/state/DiaryManager.kt b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/state/DiaryManager.kt
index a84daf43..180f024e 100644
--- a/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/state/DiaryManager.kt
+++ b/mobile-app/shared/src/commonMain/kotlin/de/tsschulz/tt_tagebuch/shared/state/DiaryManager.kt
@@ -263,10 +263,16 @@ class DiaryManager(
}
/** @return neue `diaryDateId` bei Erfolg, sonst `null` */
- suspend fun createDate(clubId: Int, date: String, trainingStart: String?, trainingEnd: String?): Int? {
+ suspend fun createDate(
+ clubId: Int,
+ date: String,
+ trainingStart: String?,
+ trainingEnd: String?,
+ excludeFromBilling: Boolean = false,
+ ): Int? {
_state.value = _state.value.copy(isLoading = true, error = null)
return try {
- val created = diaryApi.createDate(clubId, date, trainingStart, trainingEnd)
+ val created = diaryApi.createDate(clubId, date, trainingStart, trainingEnd, excludeFromBilling)
loadDates(clubId)
created.id
} catch (t: Throwable) {
@@ -275,10 +281,16 @@ class DiaryManager(
}
}
- suspend fun updateTimes(clubId: Int, dateId: Int, trainingStart: String?, trainingEnd: String?) {
+ suspend fun updateTimes(
+ clubId: Int,
+ dateId: Int,
+ trainingStart: String?,
+ trainingEnd: String?,
+ excludeFromBilling: Boolean? = null,
+ ) {
_state.value = _state.value.copy(isLoading = true, error = null)
try {
- diaryApi.updateTimes(clubId, dateId, trainingStart, trainingEnd)
+ diaryApi.updateTimes(clubId, dateId, trainingStart, trainingEnd, excludeFromBilling)
loadDates(clubId)
} catch (t: Throwable) {
_state.value = _state.value.copy(isLoading = false, error = t.toUserMessage("Zeiten konnten nicht gespeichert werden"))