Campaign forms

CampaignForms

This block of classes handles the display and processing of the form used to create/edit a Campaign entity via the UI. It follows the standard architecture used in timveroOS: Form → FormService → Entity, with full versioning support through HistoryEntityFormService.


✅ CampaignForm

CampaignForm is a DTO class representing the fields of the campaign creation/edit form. Validation annotations provide basic input checks.

Example fields:

public class CampaignForm {

    @NotEmpty
    private String name;

    @NotNull
    private CampaignExecutionType executionType;

    private boolean restartable;

    private Integer restartableUnit;

    private RestartableUnitType restartableUnitType;

    @Valid
    private ExpressionForm expression;

    @NotEmpty
    private Set<@NotNull String> creditProductCodes;

    private LocalDateTime dateTimeExecution;

    // getters and setters
}

🔁 CampaignFormMapper

The CampaignFormMapper interface is used to convert between Campaign and CampaignForm using the MapStruct library. It extends EntityToFormMapper<Campaign, CampaignForm>.

Example:

@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE, uses = ReferenceMapper.class)
public interface CampaignFormMapper extends EntityToFormMapper<Campaign, CampaignForm> {
}

MapStruct automatically generates the conversion based on matching fields. Additional logic can be added using @AfterMapping if needed.


⚙️ CampaignFormService — Extends HistoryEntityFormService

CampaignFormService implements the core business logic for editing campaigns via the UI. It extends HistoryEntityFormService<Campaign, CampaignForm, Long>, which means:

  • Versioning is handled automatically — saving a campaign creates a new version

  • Previous versions are marked as inactive

  • The version lineage is tracked via lineageId

Example:

@Service
public class CampaignFormService extends
    HistoryEntityFormService<Campaign, CampaignForm, Long> {

    @Autowired
    private CreditProductRepository productRepository;
    @Autowired
    private ScriptManager scriptManager;

    @Override
    protected void assembleEditModel(Long aLong, CampaignForm form, Map<String, Object> model) {
        model.put("campaign", form);
        model.put("executionTypes", CampaignExecutionType.values());
        model.put("creditProductCodes", productRepository.getCreditProductCodes());
        model.put("restartableUnitTypes", RestartableUnitType.values());
        model.put("engineNames", scriptManager.getEngineNames());
    }

    @Override
    protected void assembleViewModel(Long id, Campaign entity, Map<String, Object> model) {
        // Implementation as needed
    }

    @Override
    public List<Campaign> findAllVersions(UUID versionId) {
        return super.findAllVersions(versionId);
    }
}

Key Method:

@Override
protected void assembleEditModel(Long aLong, CampaignForm form, Map<String, Object> model) {
    model.put("campaign", form);
    model.put("executionTypes", CampaignExecutionType.values());
    model.put("creditProductCodes", productRepository.getCreditProductCodes());
    model.put("restartableUnitTypes", RestartableUnitType.values());
    model.put("engineNames", scriptManager.getEngineNames());
}

Version History Support:

@Override
public List<Campaign> findAllVersions(UUID versionId) {
    return super.findAllVersions(versionId);
}

Dependencies Used:

  • CreditProductRepository — for retrieving available credit products

  • ScriptManager — for showing available scripting engines


/campaign/list.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<th:block>
    <table class="table">
        <thead>
        <tr role="row">
            <th data-sortField="id" th:text="#{symbol.id}"></th>
            <th data-sortField="name" th:text="#{campaign.name}"></th>
            <th th:text="#{campaign.active}"></th>
            <th th:text="#{campaign.executionType}"></th>
            <th th:text="#{campaign.lastStartDate}"></th>
        </tr>
        </thead>
        <tbody th:attr="data-page=${page.page},data-total=${page.total}">
        <th:block
            th:each="entity : ${page.rows}"
            th:object="${entity}">
            <tr role="row"
                class="clickable"
                th:href="@{'/campaign/'+ ${entity.id}}">
                <td th:text="*{id}"></td>
                <td th:text="*{name}"></td>
                <td th:text="*{active} ? #{common.yes} : #{common.no} "></td>
                <td th:text="*{#enums.name(executionType)}"></td>
                <td th:text="${latestExecution} ? ${#ldates.format(latestExecution.createdAt)} : #{campaign.noneStartDate}"></td>
            </tr>
        </th:block>
        </tbody>
    </table>
</th:block>
</html>

Purpose: Displays a table with the list of all campaigns. It serves as the main campaign overview page.

Key Features:

  • Sortable by id, name, and executionType

  • Displays active/inactive status

  • Shows the last execution date (if available)

Last updated

Was this helpful?