Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@
import uk.gov.companieshouse.api.model.efs.categorytemplates.CategoryTemplateListApi;
import uk.gov.companieshouse.efs.api.categorytemplates.model.CategoryTemplate;

/**
* Mapper for converting CategoryTemplate model objects to API representations.
* <p>
* This class provides methods to map a list of {@link CategoryTemplate} objects to a {@link CategoryTemplateListApi},
* and a single {@link CategoryTemplate} to a {@link CategoryTemplateApi}. It is used to bridge the internal data model
* and the external API layer, ensuring that the data is transformed appropriately for external consumption.
* </p>
*
* <ul>
* <li>{@link #map(List)}: Maps a list of CategoryTemplate objects to a CategoryTemplateListApi.</li>
* <li>{@link #map(CategoryTemplate)}: Maps a single CategoryTemplate object to a CategoryTemplateApi.</li>
* </ul>
*/
@Component
public class CategoryTemplateMapper {

Expand All @@ -32,10 +45,10 @@ public CategoryTemplateListApi map(List<CategoryTemplate> categoryTemplates) {
*/
public CategoryTemplateApi map(CategoryTemplate categoryTemplate) {
return new CategoryTemplateApi(
categoryTemplate.getCategoryType(),
categoryTemplate.getCategoryName(),
categoryTemplate.getParent(),
categoryTemplate.getCategoryHint(),
categoryTemplate.getGuidanceTexts());
categoryTemplate.categoryType(),
categoryTemplate.categoryName(),
categoryTemplate.parent(),
categoryTemplate.categoryHint(),
categoryTemplate.guidanceTexts());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,131 +4,58 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

/**
* Builder class for the {@code CategoryTemplate}.
* Represents a category template document stored in the MongoDB collection "category_templates".
* <p>
* This record is used to model category metadata for forms, including type, name, parent category,
* display order, hints, and associated guidance text IDs. It is annotated for use with Spring Data MongoDB
* and Jackson for serialization/deserialization.
* </p>
*
* <ul>
* <li>{@code categoryType}: Unique identifier for the category type.</li>
* <li>{@code orderIndex}: Display order index for sorting categories.</li>
* <li>{@code categoryName}: Human-readable name of the category.</li>
* <li>{@code parent}: Parent category type, if applicable.</li>
* <li>{@code categoryHint}: Optional hint or description for the category.</li>
* <li>{@code guidanceTexts}: List of guidance text IDs associated with the category. Never null.</li>
* </ul>
*/
@Document(collection = "category_templates")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CategoryTemplate {

private CategoryTemplate() {
// required by Spring Data
}

public record CategoryTemplate(
@JsonProperty("category_type")
@Id
private String categoryType;
String categoryType,

@JsonProperty("order_index")
@Field
private Integer orderIndex;
Integer orderIndex,

@JsonProperty("category_name")
@Field
private String categoryName;
String categoryName,

@JsonProperty("parent")
@Field
private String parent;
String parent,

@JsonProperty("category_hint")
@Field
private String categoryHint;
String categoryHint,

@JsonProperty("guidance_text_list")
@Field
private List<Integer> guidanceTexts;

/**
* Constructor which sets the submission form category data.
*
* @param categoryType the category type
* @param orderIndex the ordering within the category
* @param categoryName the category name
* @param parent used when the category has a parent category
* @param categoryHint the category hint
* @param guidanceTexts a list of id's of guidance fragments to show on the category
* selection screen
*/
public CategoryTemplate(String categoryType, final Integer orderIndex, String categoryName,
String parent, String categoryHint, final List<Integer> guidanceTexts) {
this.categoryType = categoryType;
this.orderIndex = orderIndex;
this.categoryName = categoryName;
this.parent = parent;
this.categoryHint = categoryHint;
this.guidanceTexts = guidanceTexts;
}

public String getCategoryType() {
return categoryType;
}

public Integer getOrderIndex() {
return orderIndex;
}

public String getCategoryName() {
return categoryName;
}

public String getParent() {
return parent;
}

public String getCategoryHint() {
return categoryHint;
}

public List<Integer> getGuidanceTexts() {
return Optional.ofNullable(guidanceTexts)
.orElse(Collections.emptyList());
}

public void setGuidanceTexts(List<Integer> guidanceTexts) {
this.guidanceTexts = guidanceTexts;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
List<Integer> guidanceTexts
) {
public CategoryTemplate {
// Ensure guidanceTexts is never null
if (guidanceTexts == null) {
guidanceTexts = Collections.emptyList();
}
final CategoryTemplate that = (CategoryTemplate) o;
return Objects.equals(getCategoryType(), that.getCategoryType()) &&
Objects.equals(getOrderIndex(), that.getOrderIndex()) &&
Objects.equals(getCategoryName(), that.getCategoryName()) &&
Objects.equals(getParent(), that.getParent()) &&
Objects.equals(getCategoryHint(), that.getCategoryHint()) &&
Objects.equals(getGuidanceTexts(), that.getGuidanceTexts());
}

@Override
public int hashCode() {
return Objects.hash(getCategoryType(), getOrderIndex(), getCategoryName(), getParent(),
getCategoryHint(), getGuidanceTexts());
}

@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("categoryType", getCategoryType())
.append("orderIndex", getOrderIndex())
.append("categoryName", getCategoryName())
.append("parent", getParent())
.append("categoryHint", getCategoryHint())
.append("guidanceTexts", getGuidanceTexts())
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
@Import(Config.class)
public class CategoryTemplateServiceImpl implements CategoryTemplateService {

private CategoryTemplateRepository repository;
private CategoryTemplateMapper mapper;
private final CategoryTemplateRepository repository;
private final CategoryTemplateMapper mapper;

/**
* FormTemplateService constructor.
Expand Down Expand Up @@ -63,7 +63,7 @@ public CategoryTypeConstants getTopLevelCategory(final String category) {
CategoryTemplate categoryTemplate = repository.findById(currentCategory).orElse(null);

if (categoryTemplate != null) {
final String parentCategory = categoryTemplate.getParent();
final String parentCategory = categoryTemplate.parent();
final CategoryTypeConstants parentCategoryType =
CategoryTypeConstants.nameOf(parentCategory).orElse(OTHER);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@

import static java.lang.String.format;

/**
* Service implementation for sending various types of email notifications related to submissions.
* <p>
* This class coordinates the mapping of submission models to email documents and delegates the actual
* sending of emails to the {@link EmailClient}. It supports external and internal notifications, payment
* reports, delayed submission notifications, and more. Each public method corresponds to a specific type
* of email notification and uses the appropriate mapper from {@link EmailMapperFactory}.
* <p>
* Error handling is performed for failed email sends, and all operations are logged for traceability.
*/
@Service
public class EmailServiceImpl implements EmailService {

Expand All @@ -39,13 +49,13 @@ public EmailServiceImpl(EmailMapperFactory emailMapperFactory, EmailClient email

@Override
public void sendExternalConfirmation(ExternalNotificationEmailModel emailModel) {
LOGGER.debug(format("Sending external email confirming submission [%s]", emailModel.getSubmission().getId()));
LOGGER.debug(format("Sending external email confirming submission [%s]", emailModel.submission().getId()));
sendMessage(this.emailMapperFactory.getConfirmationEmailMapper().map(emailModel));
}

@Override
public void sendExternalPaymentFailedNotification(ExternalNotificationEmailModel emailModel) {
LOGGER.debug(format("Sending external email notifying payment failed for submission [%s]", emailModel.getSubmission().getId()));
LOGGER.debug(format("Sending external email notifying payment failed for submission [%s]", emailModel.submission().getId()));
sendMessage(this.emailMapperFactory.getPaymentFailedEmailMapper().map(emailModel));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,23 @@
import uk.gov.companieshouse.efs.api.util.IdentifierGeneratable;
import uk.gov.companieshouse.efs.api.util.TimestampGenerator;

/**
* Maps {@link ExternalNotificationEmailModel} to {@link EmailDocument} for external notification emails.
* <p>
* This class is responsible for transforming submission data into the format required for sending
* external notification emails. It uses configuration, identifier and timestamp generators, and services
* for category and form templates to build the email payload.
* <p>
* Typical usage involves calling {@link #map(ExternalNotificationEmailModel)} with a model containing
* submission details, which returns a fully populated {@link EmailDocument} ready for sending.
*/
public class ExternalNotificationEmailMapper {

private NotificationConfig config;
private IdentifierGeneratable idGenerator;
private TimestampGenerator<LocalDateTime> timestampGenerator;
private CategoryTemplateService categoryTemplateService;
private FormTemplateService formTemplateService;
private final NotificationConfig config;
private final IdentifierGeneratable idGenerator;
private final TimestampGenerator<LocalDateTime> timestampGenerator;
private final CategoryTemplateService categoryTemplateService;
private final FormTemplateService formTemplateService;

public ExternalNotificationEmailMapper(NotificationConfig config,
IdentifierGeneratable idGenerator, TimestampGenerator<LocalDateTime> timestampGenerator,
Expand All @@ -39,7 +49,7 @@ public EmailDocument<ExternalConfirmationEmailData> map(ExternalNotificationEmai
return EmailDocument.<ExternalConfirmationEmailData>builder()
.withTopic(config.getTopic())
.withMessageId(idGenerator.generateId())
.withRecipientEmailAddress(model.getSubmission().getPresenter().getEmail())
.withRecipientEmailAddress(model.submission().getPresenter().getEmail())
.withEmailTemplateAppId(config.getAppId())
.withEmailTemplateMessageType(config.getMessageType())
.withData(fromSubmission(model))
Expand All @@ -49,15 +59,15 @@ public EmailDocument<ExternalConfirmationEmailData> map(ExternalNotificationEmai

private ExternalConfirmationEmailData fromSubmission(ExternalNotificationEmailModel model) {
return ExternalConfirmationEmailData.builder()
.withTo(model.getSubmission().getPresenter().getEmail())
.withPresenter(model.getSubmission().getPresenter())
.withTo(model.submission().getPresenter().getEmail())
.withPresenter(model.submission().getPresenter())
.withSubject(config.getSubject())
.withCompany(model.getSubmission().getCompany())
.withConfirmationReference(model.getSubmission().getConfirmationReference())
.withFormType(model.getSubmission().getFormDetails().getFormType())
.withCompany(model.submission().getCompany())
.withConfirmationReference(model.submission().getConfirmationReference())
.withFormType(model.submission().getFormDetails().getFormType())
.withTopLevelCategory(getTopLevelCategoryForFormType(model))
.withEmailFileDetailsList(createEmailFileDetailsList(model.getSubmission().getFormDetails().getFileDetailsList()))
.withFeeOnSubmission(model.getSubmission().getFeeOnSubmission())
.withEmailFileDetailsList(createEmailFileDetailsList(model.submission().getFormDetails().getFileDetailsList()))
.withFeeOnSubmission(model.submission().getFeeOnSubmission())
.build();
}

Expand All @@ -71,7 +81,7 @@ private EmailFileDetails emailFileDetails(FileDetails fileDetails) {

private CategoryTypeConstants getTopLevelCategoryForFormType(final ExternalNotificationEmailModel model) {
FormTemplateApi formTemplate = formTemplateService
.getFormTemplate(model.getSubmission().getFormDetails().getFormType());
.getFormTemplate(model.submission().getFormDetails().getFormType());
return categoryTemplateService.getTopLevelCategory(formTemplate.getFormCategory());
}
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
package uk.gov.companieshouse.efs.api.email.model;

import java.util.Objects;
import uk.gov.companieshouse.efs.api.submissions.model.Submission;

public class ExternalNotificationEmailModel {

private final Submission submission;

public ExternalNotificationEmailModel(Submission submission) {
this.submission = submission;
}

public Submission getSubmission() {
return submission;
}

@Override
public int hashCode() {
return Objects.hash(submission);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ExternalNotificationEmailModel other = (ExternalNotificationEmailModel) obj;
return Objects.equals(submission, other.submission);
}

}
/**
* Represents an external notification email model containing a submission.
*/
public record ExternalNotificationEmailModel(Submission submission) {}
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,7 @@ void testMapperMapsCategoryToCategoryTemplateApi() {
}

private CategoryTemplate getCategory() {
final CategoryTemplate category =
new CategoryTemplate("MA", 1, "New Incorporation", "", "", null);

category.setGuidanceTexts(Collections.singletonList(3000));

return category;
return new CategoryTemplate("MA", 1, "New Incorporation", "", "", Collections.singletonList(3000));
}

private CategoryTemplateListApi expectedList() {
Expand All @@ -60,8 +55,7 @@ private CategoryTemplateListApi expectedList() {
}

private CategoryTemplateApi expectedSingle() {
CategoryTemplateApi element = new CategoryTemplateApi("MA", "New Incorporation", "", "",
return new CategoryTemplateApi("MA", "New Incorporation", "", "",
Collections.singletonList(3000));
return new CategoryTemplateApi(element);
}
}
Loading