Skip to content
Snippets Groups Projects
Commit af6d4ce0 authored by uhensler's avatar uhensler
Browse files

OO-4630: Calendar sync and email notification of appointment findings

parent 03798347
No related branches found
No related tags found
No related merge requests found
Showing
with 170 additions and 31 deletions
...@@ -124,7 +124,7 @@ public interface AppointmentsService { ...@@ -124,7 +124,7 @@ public interface AppointmentsService {
public void deleteParticipation(Participation participation); public void deleteParticipation(Participation participation);
public void deleteParticipations(Collection<? extends ParticipationRef> participationRefs); public void deleteParticipations(Collection<? extends ParticipationRef> participationRefs, boolean sendEmail);
public Long getParticipationCount(ParticipationSearchParams params); public Long getParticipationCount(ParticipationSearchParams params);
......
...@@ -112,6 +112,10 @@ public class ParticipationSearchParams { ...@@ -112,6 +112,10 @@ public class ParticipationSearchParams {
return participationKeys; return participationKeys;
} }
public void setParticipation(Participation participation) {
this.participationKeys = Collections.singletonList(participation.getKey());
}
public void setParticipations(Collection<? extends ParticipationRef> participations) { public void setParticipations(Collection<? extends ParticipationRef> participations) {
this.participationKeys = participations.stream() this.participationKeys = participations.stream()
.map(ParticipationRef::getKey) .map(ParticipationRef::getKey)
......
...@@ -23,6 +23,7 @@ import static java.util.Collections.singletonList; ...@@ -23,6 +23,7 @@ import static java.util.Collections.singletonList;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -31,6 +32,7 @@ import org.apache.logging.log4j.Logger; ...@@ -31,6 +32,7 @@ import org.apache.logging.log4j.Logger;
import org.olat.core.gui.translator.Translator; import org.olat.core.gui.translator.Translator;
import org.olat.core.id.Identity; import org.olat.core.id.Identity;
import org.olat.core.logging.Tracing; import org.olat.core.logging.Tracing;
import org.olat.core.util.DateUtils;
import org.olat.core.util.StringHelper; import org.olat.core.util.StringHelper;
import org.olat.core.util.Util; import org.olat.core.util.Util;
import org.olat.core.util.i18n.I18nManager; import org.olat.core.util.i18n.I18nManager;
...@@ -161,6 +163,78 @@ public class AppointmentsMailing { ...@@ -161,6 +163,78 @@ public class AppointmentsMailing {
} }
} }
void sendParticipationCreated(Participation participation) {
ParticipationSearchParams participationParams = new ParticipationSearchParams();
participationParams.setParticipation(participation);
participationParams.setFetchAppointments(true);
participationParams.setFetchTopics(true);
participationParams.setFetchIdentities(true);
participationParams.setFetchUser(true);
List<Participation> reloadedParticipations = participationDao.loadParticipations(participationParams);
if (reloadedParticipations.isEmpty()) return;
Participation reloadedParticipation = reloadedParticipations.get(0);
Appointment appointment = reloadedParticipation.getAppointment();
Identity identity = reloadedParticipation.getIdentity();
Locale locale = I18nManager.getInstance().getLocaleOrDefault(identity.getUser().getPreferences().getLanguage());
Translator translator = Util.createPackageTranslator(AppointmentsRunController.class, locale);
String subject = translator.translate("mail.participation.created.subject",
new String[] {appointment.getTopic().getTitle() });
String body = translator.translate("mail.participation.created.body", new String[] {
userManager.getUserDisplayName(identity.getKey()),
createFormatedAppointments(Collections.singletonList(appointment), translator)
});
MailerResult result = new MailerResult();
MailBundle bundle = new MailBundle();
bundle.setToId(identity);
bundle.setContent(subject, body);
bundle.setContext(getMailContext(appointment.getTopic()));
result = mailManager.sendMessage(bundle);
if (!result.isSuccessful()) {
log.warn(MessageFormat.format("Sending participation created [keys={0}] to {1} failed: {2}",
reloadedParticipation.getKey(), identity, result.getErrorMessage()));
}
}
void sendParticipationDeleted(Participation participation) {
ParticipationSearchParams participationParams = new ParticipationSearchParams();
participationParams.setParticipation(participation);
participationParams.setFetchAppointments(true);
participationParams.setFetchTopics(true);
participationParams.setFetchIdentities(true);
participationParams.setFetchUser(true);
List<Participation> reloadedParticipations = participationDao.loadParticipations(participationParams);
if (reloadedParticipations.isEmpty()) return;
Participation reloadedParticipation = reloadedParticipations.get(0);
Appointment appointment = reloadedParticipation.getAppointment();
Identity identity = reloadedParticipation.getIdentity();
Locale locale = I18nManager.getInstance().getLocaleOrDefault(identity.getUser().getPreferences().getLanguage());
Translator translator = Util.createPackageTranslator(AppointmentsRunController.class, locale);
String subject = translator.translate("mail.participation.deleted.subject",
new String[] {appointment.getTopic().getTitle() });
String body = translator.translate("mail.participation.deleted.body", new String[] {
userManager.getUserDisplayName(identity.getKey()),
createFormatedAppointments(Collections.singletonList(appointment), translator)
});
MailerResult result = new MailerResult();
MailBundle bundle = new MailBundle();
bundle.setToId(identity);
bundle.setContent(subject, body);
bundle.setContext(getMailContext(appointment.getTopic()));
result = mailManager.sendMessage(bundle);
if (!result.isSuccessful()) {
log.warn(MessageFormat.format("Sending participation deleted [keys={0}] to {1} failed: {2}",
reloadedParticipation.getKey(), identity, result.getErrorMessage()));
}
}
void sendRebook(Appointment toAppointment, List<Participation> fromParticipations) { void sendRebook(Appointment toAppointment, List<Participation> fromParticipations) {
if (toAppointment == null || fromParticipations == null || fromParticipations.isEmpty()) return; if (toAppointment == null || fromParticipations == null || fromParticipations.isEmpty()) return;
...@@ -213,13 +287,19 @@ public class AppointmentsMailing { ...@@ -213,13 +287,19 @@ public class AppointmentsMailing {
} }
private void appendFormatedAppointment(StringBuilder sb, Appointment appointment, Translator translator) { private void appendFormatedAppointment(StringBuilder sb, Appointment appointment, Translator translator) {
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, translator.getLocale());
sb.append(translator.translate("mail.topic", new String[] { appointment.getTopic().getTitle() })); sb.append(translator.translate("mail.topic", new String[] { appointment.getTopic().getTitle() }));
sb.append("<br>"); sb.append("<br>");
sb.append(translator.translate("mail.start", new String[] { dateFormat.format(appointment.getStart()) })); if (DateUtils.isSameDate(appointment.getStart(), appointment.getEnd())) {
sb.append("<br>"); DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, translator.getLocale());
sb.append(translator.translate("mail.end", new String[] { dateFormat.format(appointment.getEnd()) })); sb.append(translator.translate("mail.day", new String[] { dateFormat.format(appointment.getStart()) }));
sb.append("<br>"); sb.append("<br>");
} else {
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, translator.getLocale());
sb.append(translator.translate("mail.start", new String[] { dateFormat.format(appointment.getStart()) }));
sb.append("<br>");
sb.append(translator.translate("mail.end", new String[] { dateFormat.format(appointment.getEnd()) }));
sb.append("<br>");
}
if (StringHelper.containsNonWhitespace(appointment.getLocation())) { if (StringHelper.containsNonWhitespace(appointment.getLocation())) {
sb.append(translator.translate("mail.location", new String[] { appointment.getLocation() })); sb.append(translator.translate("mail.location", new String[] { appointment.getLocation() }));
sb.append("<br>"); sb.append("<br>");
......
...@@ -28,6 +28,7 @@ import java.util.Date; ...@@ -28,6 +28,7 @@ import java.util.Date;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.olat.basesecurity.BaseSecurityManager; import org.olat.basesecurity.BaseSecurityManager;
...@@ -53,6 +54,7 @@ import org.olat.course.nodes.appointments.ParticipationRef; ...@@ -53,6 +54,7 @@ import org.olat.course.nodes.appointments.ParticipationRef;
import org.olat.course.nodes.appointments.ParticipationResult; import org.olat.course.nodes.appointments.ParticipationResult;
import org.olat.course.nodes.appointments.ParticipationSearchParams; import org.olat.course.nodes.appointments.ParticipationSearchParams;
import org.olat.course.nodes.appointments.Topic; import org.olat.course.nodes.appointments.Topic;
import org.olat.course.nodes.appointments.Topic.Type;
import org.olat.course.nodes.appointments.TopicRef; import org.olat.course.nodes.appointments.TopicRef;
import org.olat.course.nodes.appointments.TopicToGroup; import org.olat.course.nodes.appointments.TopicToGroup;
import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntry;
...@@ -101,8 +103,10 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -101,8 +103,10 @@ public class AppointmentsServiceImpl implements AppointmentsService {
public Topic updateTopic(Topic topic) { public Topic updateTopic(Topic topic) {
AppointmentSearchParams params = new AppointmentSearchParams(); AppointmentSearchParams params = new AppointmentSearchParams();
params.setTopic(topic); params.setTopic(topic);
params.setStatus(Status.confirmed);
params.setFetchTopic(true); params.setFetchTopic(true);
if (Type.finding == topic.getType()) {
params.setStatus(Status.confirmed);
}
List<Appointment> appointments = appointmentDao.loadAppointments(params); List<Appointment> appointments = appointmentDao.loadAppointments(params);
if (!appointments.isEmpty()) { if (!appointments.isEmpty()) {
...@@ -130,13 +134,23 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -130,13 +134,23 @@ public class AppointmentsServiceImpl implements AppointmentsService {
params.setSubIdent(subIdent); params.setSubIdent(subIdent);
} }
params.setStartAfter(new Date()); params.setStartAfter(new Date());
params.setStatus(Status.confirmed);
params.setFetchTopic(true); params.setFetchTopic(true);
List<Appointment> appointments = appointmentDao.loadAppointments(params); List<Appointment> appointments = appointmentDao.loadAppointments(params);
appointmentsMailing.sendAppointmentDeleted(appointments);
List<Organizer> organizers = organizerDao.loadOrganizers(entry, subIdent); if (!appointments.isEmpty()) {
appointmentsMailing.sendAppointmentsDeleted(appointments, organizers); Map<Topic, List<Appointment>> topicToAppointments = appointments.stream()
.collect(Collectors.groupingBy(a -> a.getTopic()));
for (Entry<Topic, List<Appointment>> topicAppointments : topicToAppointments.entrySet()) {
calendarSyncher.unsyncCalendars(topicAppointments.getKey(), topicAppointments.getValue());
}
List<Appointment> confimredAppointments = appointments.stream()
.filter(a -> a.getStatus() == Status.confirmed)
.collect(Collectors.toList());
appointmentsMailing.sendAppointmentDeleted(confimredAppointments);
List<Organizer> organizers = organizerDao.loadOrganizers(entry, subIdent);
appointmentsMailing.sendAppointmentsDeleted(confimredAppointments, organizers);
}
List<Topic> topics = topicDao.loadTopics(entry, subIdent); List<Topic> topics = topicDao.loadTopics(entry, subIdent);
for (Topic topic : topics) { for (Topic topic : topics) {
...@@ -154,13 +168,19 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -154,13 +168,19 @@ public class AppointmentsServiceImpl implements AppointmentsService {
AppointmentSearchParams params = new AppointmentSearchParams(); AppointmentSearchParams params = new AppointmentSearchParams();
params.setTopic(topicRef); params.setTopic(topicRef);
params.setStartAfter(new Date()); params.setStartAfter(new Date());
params.setStatus(Status.confirmed);
params.setFetchTopic(true); params.setFetchTopic(true);
List<Appointment> appointments = appointmentDao.loadAppointments(params); List<Appointment> appointments = appointmentDao.loadAppointments(params);
appointmentsMailing.sendAppointmentDeleted(appointments);
List<Organizer> organizers = organizerDao.loadOrganizers(topicRef); if (!appointments.isEmpty()) {
appointmentsMailing.sendAppointmentsDeleted(appointments, organizers); List<Appointment> confimredAppointments = appointments.stream()
.filter(a -> a.getStatus() == Status.confirmed)
.collect(Collectors.toList());
appointmentsMailing.sendAppointmentDeleted(confimredAppointments);
List<Organizer> organizers = organizerDao.loadOrganizers(topicRef);
appointmentsMailing.sendAppointmentsDeleted(confimredAppointments, organizers);
calendarSyncher.unsyncCalendars(appointments.get(0).getTopic(), appointments);
}
Topic topic = topicDao.loadByKey(topicRef.getKey()); Topic topic = topicDao.loadByKey(topicRef.getKey());
deleteTopicGroup(topic); deleteTopicGroup(topic);
...@@ -185,8 +205,10 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -185,8 +205,10 @@ public class AppointmentsServiceImpl implements AppointmentsService {
AppointmentSearchParams params = new AppointmentSearchParams(); AppointmentSearchParams params = new AppointmentSearchParams();
params.setTopic(topic); params.setTopic(topic);
params.setStatus(Status.confirmed);
params.setFetchTopic(true); params.setFetchTopic(true);
if (Type.finding == topic.getType()) {
params.setStatus(Status.confirmed);
}
List<Appointment> appointments = appointmentDao.loadAppointments(params); List<Appointment> appointments = appointmentDao.loadAppointments(params);
calendarSyncher.syncCalendar(appointments, identity); calendarSyncher.syncCalendar(appointments, identity);
...@@ -304,7 +326,9 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -304,7 +326,9 @@ public class AppointmentsServiceImpl implements AppointmentsService {
@Override @Override
public Appointment saveAppointment(Appointment appointment) { public Appointment saveAppointment(Appointment appointment) {
Appointment saveAppointment = appointmentDao.saveAppointment(appointment); Appointment saveAppointment = appointmentDao.saveAppointment(appointment);
calendarSyncher.syncCalendars(appointment.getTopic(), singletonList(appointment)); if (Status.confirmed == appointment.getStatus() || Type.finding != appointment.getTopic().getType()) {
calendarSyncher.syncCalendars(appointment.getTopic(), singletonList(appointment));
}
return saveAppointment; return saveAppointment;
} }
...@@ -351,7 +375,11 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -351,7 +375,11 @@ public class AppointmentsServiceImpl implements AppointmentsService {
Appointment reloaded = appointments.get(0); Appointment reloaded = appointments.get(0);
if (Status.confirmed == reloaded.getStatus()) { if (Status.confirmed == reloaded.getStatus()) {
appointmentDao.updateStatus(reloaded, Status.planned); appointmentDao.updateStatus(reloaded, Status.planned);
calendarSyncher.syncCalendars(reloaded.getTopic(), singletonList(reloaded)); if (Type.finding == reloaded.getTopic().getType()) {
calendarSyncher.unsyncCalendars(reloaded.getTopic(), singletonList(reloaded));
} else {
calendarSyncher.syncCalendars(reloaded.getTopic(), singletonList(reloaded));
}
appointmentsMailing.sendAppointmentUnconfirmed(reloaded); appointmentsMailing.sendAppointmentUnconfirmed(reloaded);
} }
} }
...@@ -360,7 +388,9 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -360,7 +388,9 @@ public class AppointmentsServiceImpl implements AppointmentsService {
@Override @Override
public void deleteAppointment(Appointment appointment) { public void deleteAppointment(Appointment appointment) {
calendarSyncher.unsyncCalendars(appointment.getTopic(), singletonList(appointment)); calendarSyncher.unsyncCalendars(appointment.getTopic(), singletonList(appointment));
appointmentsMailing.sendAppointmentDeleted(singletonList(appointment)); if (Status.confirmed == appointment.getStatus() || Type.finding != appointment.getTopic().getType()) {
appointmentsMailing.sendAppointmentDeleted(singletonList(appointment));
}
appointmentDao.delete(appointment); appointmentDao.delete(appointment);
} }
...@@ -428,7 +458,12 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -428,7 +458,12 @@ public class AppointmentsServiceImpl implements AppointmentsService {
Participation participation = participationDao.createParticipation(reloadedAppointment, identity, createdBy); Participation participation = participationDao.createParticipation(reloadedAppointment, identity, createdBy);
participations.add(participation); participations.add(participation);
calendarSyncher.syncCalendar(reloadedAppointment, identity); if (Status.confirmed == appointment.getStatus() || Type.finding != appointment.getTopic().getType()) {
calendarSyncher.syncCalendar(reloadedAppointment, identity);
}
if (Status.confirmed == appointment.getStatus()) {
appointmentsMailing.sendParticipationCreated(participation);
}
} }
if (autoConfirmation) { if (autoConfirmation) {
...@@ -489,7 +524,10 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -489,7 +524,10 @@ public class AppointmentsServiceImpl implements AppointmentsService {
Identity identity = fromParticipation.getIdentity(); Identity identity = fromParticipation.getIdentity();
Participation participation = participationDao.createParticipation(toAppointment, identity, rebookedBy); Participation participation = participationDao.createParticipation(toAppointment, identity, rebookedBy);
participations.add(participation); participations.add(participation);
calendarSyncher.syncCalendar(toAppointment, identity);
if (Status.confirmed == toAppointment.getStatus() || Type.finding != toAppointment.getTopic().getType()) {
calendarSyncher.syncCalendar(toAppointment, identity);
}
} }
appointmentsMailing.sendRebook(toAppointment, fromParticipations); appointmentsMailing.sendRebook(toAppointment, fromParticipations);
...@@ -506,19 +544,28 @@ public class AppointmentsServiceImpl implements AppointmentsService { ...@@ -506,19 +544,28 @@ public class AppointmentsServiceImpl implements AppointmentsService {
} }
@Override @Override
public void deleteParticipations(Collection<? extends ParticipationRef> participationRefs) { public void deleteParticipations(Collection<? extends ParticipationRef> participationRefs, boolean sendEmail) {
ParticipationSearchParams participationParams = new ParticipationSearchParams(); ParticipationSearchParams participationParams = new ParticipationSearchParams();
participationParams.setParticipations(participationRefs); participationParams.setParticipations(participationRefs);
participationParams.setFetchAppointments(true); participationParams.setFetchAppointments(true);
participationParams.setFetchIdentities(true); participationParams.setFetchIdentities(true);
List<Participation> loadParticipations = participationDao.loadParticipations(participationParams); List<Participation> loadParticipations = participationDao.loadParticipations(participationParams);
loadParticipations.forEach(participation -> deleteParticipation(participation)); loadParticipations.forEach(participation -> deleteParticipation(participation, sendEmail));
} }
@Override @Override
public void deleteParticipation(Participation participation) { public void deleteParticipation(Participation participation) {
calendarSyncher.unsyncCalendar(participation.getAppointment(), participation.getIdentity()); deleteParticipation(participation, false);
}
public void deleteParticipation(Participation participation, boolean sendEmail) {
Appointment appointment = participation.getAppointment();
calendarSyncher.unsyncCalendar(appointment, participation.getIdentity());
if (sendEmail && Status.confirmed == appointment.getStatus()) {
appointmentsMailing.sendParticipationDeleted(participation);
}
participationDao.delete(participation); participationDao.delete(participation);
} }
@Override @Override
......
...@@ -301,7 +301,7 @@ public abstract class AbstractParticipationRemoveController extends FormBasicCon ...@@ -301,7 +301,7 @@ public abstract class AbstractParticipationRemoveController extends FormBasicCon
return; return;
} }
} else { } else {
appointmentsService.deleteParticipations(participationRefs); appointmentsService.deleteParticipations(participationRefs, true);
} }
onAfterRemoving(); onAfterRemoving();
......
...@@ -199,11 +199,9 @@ public abstract class AppointmentListController extends FormBasicController impl ...@@ -199,11 +199,9 @@ public abstract class AppointmentListController extends FormBasicController impl
DefaultFlexiColumnModel addUserModel = new DefaultFlexiColumnModel(AppointmentCols.addUser); DefaultFlexiColumnModel addUserModel = new DefaultFlexiColumnModel(AppointmentCols.addUser);
addUserModel.setExportable(false); addUserModel.setExportable(false);
columnsModel.addFlexiColumnModel(addUserModel); columnsModel.addFlexiColumnModel(addUserModel);
if (Type.finding != topic.getType()) { DefaultFlexiColumnModel removeModel = new DefaultFlexiColumnModel(AppointmentCols.removeUser);
DefaultFlexiColumnModel removeModel = new DefaultFlexiColumnModel(AppointmentCols.removeUser); removeModel.setExportable(false);
removeModel.setExportable(false); columnsModel.addFlexiColumnModel(removeModel);
columnsModel.addFlexiColumnModel(removeModel);
}
DefaultFlexiColumnModel confirmModel = new DefaultFlexiColumnModel(AppointmentCols.confirm); DefaultFlexiColumnModel confirmModel = new DefaultFlexiColumnModel(AppointmentCols.confirm);
confirmModel.setExportable(false); confirmModel.setExportable(false);
columnsModel.addFlexiColumnModel(confirmModel); columnsModel.addFlexiColumnModel(confirmModel);
......
...@@ -206,7 +206,7 @@ public class FindingConfirmationController extends FormBasicController { ...@@ -206,7 +206,7 @@ public class FindingConfirmationController extends FormBasicController {
unselectedParticipations.add(participation); unselectedParticipations.add(participation);
} }
} }
appointmentsService.deleteParticipations(unselectedParticipations); appointmentsService.deleteParticipations(unselectedParticipations, false);
appointmentsService.confirmAppointment(appointment); appointmentsService.confirmAppointment(appointment);
......
...@@ -95,10 +95,15 @@ mail.appointments.deleted.body=Liebe/r {0} <br><br>Folgende Termine wurden abges ...@@ -95,10 +95,15 @@ mail.appointments.deleted.body=Liebe/r {0} <br><br>Folgende Termine wurden abges
mail.appointments.deleted.subject=Termine abgesagt mail.appointments.deleted.subject=Termine abgesagt
mail.confirmed.body=Liebe/r {0} <br><br>Folgender Termin wurde best\u00e4tigt.<br><br>{1} mail.confirmed.body=Liebe/r {0} <br><br>Folgender Termin wurde best\u00e4tigt.<br><br>{1}
mail.confirmed.subject=Termin "{0}" best\u00e4tigt mail.confirmed.subject=Termin "{0}" best\u00e4tigt
mail.day=Datum: {0} (ganzer Tag)
mail.deleted.body=Liebe/r {0} <br><br>Folgender Termin wurde abgesagt.<br><br>{1} mail.deleted.body=Liebe/r {0} <br><br>Folgender Termin wurde abgesagt.<br><br>{1}
mail.deleted.subject=Termin "{0}" abgesagt mail.deleted.subject=Termin "{0}" abgesagt
mail.end=Ende: {0} mail.end=Ende: {0}
mail.location=Ort: {0} mail.location=Ort: {0}
mail.participation.created.body=Liebe/r {0} <br><br>Sie wurden zu folgendem Termin hinzugef\u00fcgt.<br><br>{1}
mail.participation.created.subject=Zu Termin "{0}" hinzugef\u00fcgt
mail.participation.deleted.body=Liebe/r {0} <br><br>Sie wurden aus folgendem Termin entfernt.<br><br>{1}
mail.participation.deleted.subject=Aus Termin "{0}" entfernt
mail.rebooked.subject=Termin umgebucht mail.rebooked.subject=Termin umgebucht
mail.rebooked.body=Liebe/r {0} <br><br>Folgender Termin wurde umbgebucht.<br><br><b>Bisheriger Termin</b><br>{1}<br><b>Neuer Termin</b><br>{2} mail.rebooked.body=Liebe/r {0} <br><br>Folgender Termin wurde umbgebucht.<br><br><b>Bisheriger Termin</b><br>{1}<br><b>Neuer Termin</b><br>{2}
mail.start=Start: {0} mail.start=Start: {0}
......
...@@ -94,10 +94,15 @@ mail.appointments.deleted.body=Dear {0} <br><br>The following appointments were ...@@ -94,10 +94,15 @@ mail.appointments.deleted.body=Dear {0} <br><br>The following appointments were
mail.appointments.deleted.subject=Appointments deleted mail.appointments.deleted.subject=Appointments deleted
mail.confirmed.body=Dear {0} <br><br>The following appointment was confirmed.<br><br>{1} mail.confirmed.body=Dear {0} <br><br>The following appointment was confirmed.<br><br>{1}
mail.confirmed.subject=Appointment "{0}" confirmed mail.confirmed.subject=Appointment "{0}" confirmed
mail.day=Date: {0} (full day)
mail.deleted.body=Dear {0} <br><br>The following appointment was declined.<br><br>{1} mail.deleted.body=Dear {0} <br><br>The following appointment was declined.<br><br>{1}
mail.deleted.subject=Appointment "{0}" declined mail.deleted.subject=Appointment "{0}" declined
mail.end=End: {0} mail.end=End: {0}
mail.location=Location: {0} mail.location=Location: {0}
mail.participation.created.body=Dear {0} <br><br>You were added to the following appointment.<br><br>{1}
mail.participation.created.subject=Added to appointment "{0}"
mail.participation.deleted.body=Dear {0} <br><br>You were removed from the following appointment.<br><br>{1}
mail.participation.deleted.subject=Removed from appointment "{0}"
mail.rebooked.subject=Appointment rebooked mail.rebooked.subject=Appointment rebooked
mail.rebooked.body=Dear {0} <br><br>The following appointment was rebooked.<br><br><b>Previous appointment</b><br>{1}<br><b>New appointment</b><br>{2} mail.rebooked.body=Dear {0} <br><br>The following appointment was rebooked.<br><br><b>Previous appointment</b><br>{1}<br><b>New appointment</b><br>{2}
mail.start=Start: {0} mail.start=Start: {0}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment