34#include <nlohmann/json.hpp>
38#include <unordered_set>
42std::vector<core::domain::Alias> toAliases(
const std::vector<core::ports::workspace::AliasSnapshot>& aliases) {
43 std::vector<core::domain::Alias> out;
44 out.reserve(aliases.size());
45 for (
const auto& alias : aliases) {
46 out.emplace_back(alias.value, alias.kind, alias.source, alias.createdAt, alias.updatedAt);
51template <
typename Entity>
53 entity.setCreatedAt(std::string{});
54 entity.setUpdatedAt(std::string{});
57template <
typename Entity>
58void stampCreated(Entity& entity) {
61 if (entity.createdAt().empty()) {
62 entity.setCreatedAt(now);
64 if (entity.updatedAt().empty()) {
65 entity.setUpdatedAt(entity.createdAt());
70template <
typename Entity>
71void stampUpdated(Entity& entity) {
72 if constexpr (HasTimestamps<Entity>) {
77template <
typename Collection,
typename Configure>
78std::string appendEntity(Collection& collection, Configure&& configure) {
79 using Entity =
typename Collection::value_type::element_type;
80 auto entity = std::make_shared<Entity>();
83 stampCreated(*entity);
84 const std::string
id = entity->id();
85 collection.push_back(std::move(entity));
89template <
typename Collection,
typename Update>
90bool updateEntity(Collection& collection,
const std::string&
id, Update&& update) {
94 for (
auto& entity : collection) {
95 if (!entity || entity->id() !=
id) {
99 stampUpdated(*entity);
105template <
typename Collection>
106bool eraseEntity(Collection& collection,
const std::string&
id) {
110 const auto originalSize = collection.size();
111 collection.erase(std::remove_if(collection.begin(), collection.end(), [&](
const auto& entity) {
112 return entity && entity->id() == id;
113 }), collection.end());
114 return collection.size() != originalSize;
124 property.rename(input.
name);
125 property.setAliases(input.
aliases);
130 std::vector<std::string> actorIds;
132 for (
const auto& actorId : input.
actorIds) {
134 if (normalized.empty()) {
137 actorIds.push_back(normalized);
152std::string serializeSnapshotTransactionsForDomain(
153 const std::vector<core::ports::workspace::TransactionSnapshot>& source);
168 for (
const auto& [key, value] : input.
adjustments) {
174 const std::string& name,
176 const std::vector<std::string>& analysisIds) {
177 annual.
apply(name, year, analysisIds);
193std::vector<std::pair<std::string, double>>
194analysisAdjustmentsFromCommand(
205std::string serializeSnapshotTransactionsForDomain(
206 const std::vector<core::ports::workspace::TransactionSnapshot>& source) {
207 if (source.empty()) {
210 nlohmann::json rows = nlohmann::json::array();
211 for (
const auto& tx : source) {
212 rows.push_back(nlohmann::json{
214 {
"transactionId", tx.
id},
216 {
"transactionName", tx.
name},
223 {
"contractType", tx.contractType},
226 {
"allocatable", tx.allocatable},
228 {
"propertyNames", tx.propertyNames},
234bool isBlank(
const std::string& value) {
239 const std::string& field,
240 const std::string& value,
241 const std::string& label) {
242 if (isBlank(value)) {
243 result.
addError(field,
"required", label +
" is required.");
248 const std::string& field,
249 const std::string& value,
250 const std::string& label) {
251 requireText(result, field, value, label);
253 result.
addError(field,
"invalid", label +
" is invalid.");
258 const std::string& field,
259 const std::string& value,
260 const std::string& label) {
261 if (isBlank(value)) {
262 result.
addError(field,
"required", label +
" is required.");
267 return result.
valid();
281 bool requireStatementId) {
283 requireEntityName(result,
"name", command.
name,
"Transaction name");
284 requireText(result,
"bookingDate", command.
bookingDate,
"Booking date");
286 result.
addError(
"bookingDate",
"invalid",
"Booking date is invalid.");
288 const auto amount = parseTransactionAmount(command);
290 result.
addError(
"amount",
"invalid",
"Amount is invalid.");
292 if (requireStatementId) {
293 requireId(result,
"statementId", command.
statementId,
"Statement");
317 const std::string& actorId,
318 const std::vector<std::string>& desiredContractIds) {
319 if (actorId.empty()) {
323 std::unordered_set<std::string> desired;
324 for (
const auto& contractId : desiredContractIds) {
325 if (!contractId.empty()) {
326 desired.insert(contractId);
330 bool changed =
false;
331 for (
auto& contract : state.
contracts()) {
335 const bool shouldLink = desired.find(contract->
id()) != desired.end();
338 const auto& actorIds = contract->
actorIds();
339 const bool alreadySingleOwner = actorIds.size() == 1u && actorIds.front() == actorId;
340 if (!alreadySingleOwner) {
342 stampUpdated(*contract);
345 }
else if (!shouldLink && hasLink) {
347 stampUpdated(*contract);
356 const std::string& propertyId,
357 const std::vector<std::string>& desiredContractIds) {
358 if (propertyId.empty()) {
362 std::unordered_set<std::string> desired;
363 for (
const auto& contractId : desiredContractIds) {
364 if (!contractId.empty()) {
365 desired.insert(contractId);
369 bool changed =
false;
370 for (
auto& contract : state.
contracts()) {
374 const bool shouldLink = desired.find(contract->
id()) != desired.end();
376 if (shouldLink && !hasLink) {
378 stampUpdated(*contract);
380 }
else if (!shouldLink && hasLink) {
382 stampUpdated(*contract);
391 const auto& contracts = state.
contracts();
393 for (
auto& actor : state.
actors()) {
394 if (!actor)
continue;
395 std::vector<std::string> contractIds;
396 for (
const auto& contract : contracts) {
398 contractIds.push_back(contract->
id());
405 if (!property)
continue;
406 std::vector<std::string> contractIds;
407 for (
const auto& contract : contracts) {
409 contractIds.push_back(contract->
id());
412 property->setContractIds(std::move(contractIds));
417std::shared_ptr<T> findById(
const std::vector<std::shared_ptr<T>>& items,
const std::string&
id) {
418 const auto it = std::find_if(items.begin(), items.end(), [&](
const auto& item) {
419 return item && item->id() == id;
421 return it == items.end() ? nullptr : *it;
426 const std::string&
id);
430 const std::string&
id) {
431 const auto statement = findById(statements,
id);
437 removeTransaction(statements, transactions, transactionId);
440 statements.erase(std::remove_if(statements.begin(), statements.end(), [&](
const auto& item) {
441 return item && item->id() == id;
442 }), statements.end());
447 const std::string&
id) {
448 for (
auto& statement : statements) {
454 transactions.erase(std::remove_if(transactions.begin(), transactions.end(), [&](
const auto& item) {
455 return item && item->id() == id;
456 }), transactions.end());
460 const std::string& statementId,
461 const std::string& transactionId) {
462 const auto statement = findById(statements, statementId);
470 const std::string& statementId,
471 const std::string& transactionId) {
472 const auto statement = findById(statements, statementId);
479class WorkspaceCatalogMutator {
481 std::string addActor(core::domain::catalog::WorkspaceCatalog& state,
const core::application::ActorInput& input)
const {
485 auto actors = state.
actors();
486 const auto id = appendEntity(actors, [&](core::domain::Actor& actor) { applyActorDraft(actor, input); });
489 projectActorPropertyLinksFromContracts(state);
493 bool updateActor(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id,
const core::application::ActorInput& input)
const {
497 auto actors = state.
actors();
498 const bool updated = updateEntity(actors,
id, [&](core::domain::Actor& actor) { applyActorDraft(actor, input); });
502 projectActorPropertyLinksFromContracts(state);
507 bool deleteActor(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
508 auto actors = state.
actors();
509 const bool removed = eraseEntity(actors,
id);
512 syncActorRelations(state,
id, std::vector<std::string>{});
513 projectActorPropertyLinksFromContracts(state);
518 std::string addProperty(core::domain::catalog::WorkspaceCatalog& state,
const core::application::PropertyInput& input)
const {
523 const auto id = appendEntity(properties, [&](core::domain::Property& property) { applyPropertyDraft(property, input); });
525 syncPropertyRelations(state,
id, input.
contractIds);
526 projectActorPropertyLinksFromContracts(state);
530 bool updateProperty(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id,
const core::application::PropertyInput& input)
const {
535 const bool updated = updateEntity(properties,
id, [&](core::domain::Property& property) { applyPropertyDraft(property, input); });
538 syncPropertyRelations(state,
id, input.
contractIds);
539 projectActorPropertyLinksFromContracts(state);
544 bool deleteProperty(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
546 const bool removed = eraseEntity(properties,
id);
549 syncPropertyRelations(state,
id, std::vector<std::string>{});
550 projectActorPropertyLinksFromContracts(state);
555 std::string addContract(core::domain::catalog::WorkspaceCatalog& state,
const core::application::ContractInput& input)
const {
560 const auto id = appendEntity(contracts, [&](core::domain::Contract& contract) { applyContractDraft(contract, input); });
562 projectActorPropertyLinksFromContracts(state);
566 bool updateContract(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id,
const core::application::ContractInput& input)
const {
571 const bool updated = updateEntity(contracts,
id, [&](core::domain::Contract& contract) { applyContractDraft(contract, input); });
574 projectActorPropertyLinksFromContracts(state);
579 bool deleteContract(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
581 const bool removed = eraseEntity(contracts,
id);
584 projectActorPropertyLinksFromContracts(state);
589 std::string addStatement(core::domain::catalog::WorkspaceCatalog& state,
const std::string& name)
const {
594 const auto id = appendEntity(statements, [&](core::domain::Statement& statement) { applyStatementName(statement, name); });
599 bool updateStatement(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id,
const std::string& name)
const {
604 const bool updated = updateEntity(statements,
id, [&](core::domain::Statement& statement) { applyStatementName(statement, name); });
609 bool deleteStatement(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
616 const bool hadStatement =
static_cast<bool>(findById(statements,
id));
617 const auto originalTransactionCount = transactions.size();
618 removeStatement(statements, transactions,
id);
621 return hadStatement || state.
transactions().size() != originalTransactionCount;
624 std::string addTransaction(core::domain::catalog::WorkspaceCatalog& state,
const core::application::TransactionInput& input)
const {
635 const auto id = appendEntity(transactions, [&](core::domain::Transaction& tx) {
636 applyTransactionDraft(tx, input);
639 const auto statement = findById(statements, input.
statementId);
644 linkTransactionToStatement(statements, input.
statementId,
id);
652 bool updateTransaction(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id,
const core::application::TransactionInput& input)
const {
663 std::string previousStatementId;
664 std::string previousContractId;
665 bool previousAllocatable =
false;
668 if (
const auto transaction = findById(transactions,
id)) {
669 previousStatementId = transaction->statementId();
670 previousContractId = transaction->contractId();
671 previousAllocatable = transaction->isAllocatable();
674 const auto updated = updateEntity(transactions,
id, [&](core::domain::Transaction& tx) {
675 applyTransactionDraft(tx, input);
682 if (
const auto updatedTx = findById(transactions,
id)) {
683 const bool allocatableChanged = updatedTx->isAllocatable() != previousAllocatable;
684 const std::string effectiveContractId = !updatedTx->contractId().empty() ? updatedTx->contractId() : previousContractId;
685 if (allocatableChanged && !effectiveContractId.empty()) {
687 const bool contractModeUpdated = updateEntity(contracts, effectiveContractId, [](core::domain::Contract& contract) {
690 stampUpdated(contract);
693 if (contractModeUpdated) {
700 if (!previousStatementId.empty()) {
701 unlinkTransactionFromStatement(statements, previousStatementId,
id);
704 linkTransactionToStatement(statements, input.
statementId,
id);
707 linkTransactionToStatement(statements, input.
statementId,
id);
715 bool deleteTransaction(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
718 const auto originalSize = transactions.size();
719 removeTransaction(statements, transactions,
id);
725 std::string addAnalysis(core::domain::catalog::WorkspaceCatalog& state,
const core::application::AnalysisInput& input)
const {
726 const auto filterSpec = analysisFilterSpecFromSelection(input.
filter);
732 const auto id = appendEntity(analyses, [&](core::domain::Analysis& analysis) { applyAnalysisDraft(analysis, input); });
737 bool updateAnalysis(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id,
const core::application::AnalysisInput& input)
const {
738 const auto filterSpec = analysisFilterSpecFromSelection(input.
filter);
744 const bool updated = updateEntity(analyses,
id, [&](core::domain::Analysis& analysis) { applyAnalysisDraft(analysis, input); });
749 bool deleteAnalysis(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
751 const bool removed = eraseEntity(analyses,
id);
756 std::string addAnnual(core::domain::catalog::WorkspaceCatalog& state,
757 const std::string& name,
759 const std::vector<std::string>& analysisIds)
const {
764 auto annuals = state.
annuals();
765 const auto id = appendEntity(annuals, [&](core::domain::Annual& annual) { applyAnnualDraft(annual, name, year, analysisIds); });
770 bool updateAnnual(core::domain::catalog::WorkspaceCatalog& state,
771 const std::string&
id,
772 const std::string& name,
774 const std::vector<std::string>& analysisIds)
const {
779 auto annuals = state.
annuals();
780 const bool updated = updateEntity(annuals,
id, [&](core::domain::Annual& annual) { applyAnnualDraft(annual, name, year, analysisIds); });
785 bool deleteAnnual(core::domain::catalog::WorkspaceCatalog& state,
const std::string&
id)
const {
786 auto annuals = state.
annuals();
787 const bool removed = eraseEntity(annuals,
id);
793const WorkspaceCatalogMutator& catalogMutator() {
794 static const WorkspaceCatalogMutator instance;
803 : session_(&session) {
820void WorkspaceCommandService::commit() {
824void WorkspaceCommandService::notifyCatalogChanged() {
825 session_->notifyState();
833 service.notifyCatalogChanged();
839 service.notifyCatalogChanged();
845 requireEntityName(result,
"name", command.
name,
"Actor name");
851 requireEntityName(result,
"name", command.
name,
"Property name");
857 requireEntityName(result,
"name", command.
name,
"Contract name");
858 requireText(result,
"type", command.
type,
"Contract type");
860 result.
addError(
"type",
"invalid",
"Contract type is invalid.");
867 requireEntityName(result,
"name", command.
name,
"Statement name");
872 return validateTransactionCommand(command,
true);
879 appendValidationIssues(result, validateTransactionCommand(transaction,
false));
886 requireEntityName(result,
"name", command.
name,
"Analysis name");
887 requireText(result,
"type", command.
type,
"Analysis type");
889 result.
addError(
"type",
"invalid",
"Analysis type is invalid.");
892 result.
addError(
"type",
"unsupported",
"Analysis type is not supported.");
894 const auto filterSpec = analysisFilterSpecFromSelection(command.
filter);
896 result.
addError(
"filterSpec",
"invalid",
"Filter specification is invalid.");
899 result.
addError(
"exportFormat",
"invalid",
"Export format is invalid.");
906 requireEntityName(result,
"name", command.
name,
"Annual name");
908 result.
addError(
"year",
"invalid",
"Year is invalid.");
917 return WorkspaceCommandService::commitCreated(*
this, catalogMutator().
addActor(mutableCatalogState(), {command.
name, toAliases(command.
aliases), command.
contractIds}));
921 auto validation =
validate(command);
922 requireId(validation,
"id", command.
id,
"Actor");
923 if (!valid(validation)) {
926 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
updateActor(mutableCatalogState(), command.
id, {command.name, toAliases(command.aliases), command.contractIds}));
930 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteActor(mutableCatalogState(),
id));
937 return WorkspaceCommandService::commitCreated(*
this, catalogMutator().
addProperty(mutableCatalogState(), {command.
name, toAliases(command.
aliases), command.
contractIds}));
941 auto validation =
validate(command);
942 requireId(validation,
"id", command.
id,
"Property");
943 if (!valid(validation)) {
946 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
updateProperty(mutableCatalogState(), command.
id, {command.name, toAliases(command.aliases), command.contractIds}));
950 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteProperty(mutableCatalogState(),
id));
957 return WorkspaceCommandService::commitCreated(*
this, catalogMutator().
addContract(mutableCatalogState(), {
968 auto validation =
validate(command);
969 requireId(validation,
"id", command.
id,
"Contract");
970 if (!valid(validation)) {
973 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
updateContract(mutableCatalogState(),
977 command.allocatableMode,
980 toAliases(command.aliases)}));
984 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteContract(mutableCatalogState(),
id));
991 return WorkspaceCommandService::commitCreated(*
this, catalogMutator().
addStatement(mutableCatalogState(), command.
name));
1000 std::vector<TransactionInput> inputs;
1003 if (!valid(validateTransactionCommand(transaction,
false))) {
1006 const auto amount = parseTransactionAmount(transaction);
1010 inputs.push_back(transactionInputFromCommand(transaction, *amount));
1013 auto& state = mutableCatalogState();
1014 const std::string statementId = catalogMutator().addStatement(state, command.
statement.
name);
1015 if (statementId.empty()) {
1018 for (
auto& input : inputs) {
1019 input.statementId = statementId;
1020 static_cast<void>(catalogMutator().addTransaction(state, input));
1022 notifyCatalogChanged();
1027 auto validation =
validate(command);
1028 requireId(validation,
"id", command.
id,
"Statement");
1029 if (!valid(validation)) {
1032 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
updateStatement(mutableCatalogState(), command.
id, command.
name));
1036 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteStatement(mutableCatalogState(),
id));
1043 const auto amount = parseTransactionAmount(command);
1048 return WorkspaceCommandService::commitCreated(*
this, catalogMutator().
addTransaction(mutableCatalogState(), input));
1052 auto validation =
validate(command);
1053 requireId(validation,
"id", command.
id,
"Transaction");
1054 if (!valid(validation)) {
1057 const auto amount = parseTransactionAmount(command);
1062 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
updateTransaction(mutableCatalogState(), command.
id, input));
1066 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteTransaction(mutableCatalogState(),
id));
1073 return WorkspaceCommandService::commitCreated(*
this, catalogMutator().
addAnalysis(mutableCatalogState(), {
1081 analysisAdjustmentsFromCommand(command)
1086 auto validation =
validate(command);
1087 requireId(validation,
"id", command.
id,
"Analysis");
1088 if (!valid(validation)) {
1091 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
updateAnalysis(mutableCatalogState(), command.
id, {
1093 core::domain::AnalysisType(command.type),
1096 core::domain::ExportFormat(command.exportFormat),
1097 command.includeCalculationAdjustments,
1098 command.snapshotTransactions,
1099 analysisAdjustmentsFromCommand(command)
1104 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteAnalysis(mutableCatalogState(),
id));
1115 auto validation =
validate(command);
1116 requireId(validation,
"id", command.
id,
"Annual");
1117 if (!valid(validation)) {
1124 WorkspaceCommandService::commitIfChanged(*
this, catalogMutator().
deleteAnnual(mutableCatalogState(),
id));
Shared alias normalization and ranking helpers for core entities.
Declares helpers for parsing imported transaction amount strings.
Domain model for persisted analysis definitions.
Shared analysis validation and normalization helpers.
Value object for analysis type labels.
Shared analysis request/config helpers for UI and application layers.
Domain model for annual aggregates.
Shared annual validation helpers.
Value object for normalized booking dates.
Domain model for contracts.
Value object for contract type labels.
Small value object for normalized entity display names.
Value object for analysis filter specifications.
Value object for monetary transaction amounts.
Domain model for properties.
Declares private stable identifier helpers for core entity creation.
Domain model for statements.
Declares private UTC timestamp helpers for core implementation code.
Domain model for transactions.
Shared transaction transition and normalization helpers.
Applies catalog commands to workspace session state and persists commits.
Declares the mutable workspace session that ties in-memory state to storage.
Value object for annual year validation.
void deleteAnalysis(const std::string &id)
Deletes analysis by id.
void updateTransaction(const core::ports::workspace::TransactionCommand &command)
Updates transaction identified by command id.
void updateStatement(const core::ports::workspace::StatementCommand &command)
Updates statement identified by command id.
WorkspaceCommandService(WorkspaceSession &session)
Creates command service bound to one workspace session.
std::string addTransaction(const core::ports::workspace::TransactionCommand &command)
Adds transaction and returns created id.
void updateContract(const core::ports::workspace::ContractCommand &command)
Updates contract identified by command id.
~WorkspaceCommandService()
void updateActor(const core::ports::workspace::ActorCommand &command)
Updates actor identified by command id.
core::ports::workspace::ValidationResult validate(const core::ports::workspace::ActorCommand &command) const
Validates actor command data without mutating state.
void deleteAnnual(const std::string &id)
Deletes annual aggregate by id.
std::string addStatementWithTransactions(const core::ports::workspace::StatementWithTransactionsCommand &command)
Adds statement and transactions in one workspace mutation.
void deleteContract(const std::string &id)
Deletes contract by id.
void deleteProperty(const std::string &id)
Deletes property by id.
void deleteStatement(const std::string &id)
Deletes statement by id.
void deleteTransaction(const std::string &id)
Deletes transaction by id.
std::string addActor(const core::ports::workspace::ActorCommand &command)
Adds actor and returns created id.
std::string addAnnual(const core::ports::workspace::AnnualCommand &command)
Adds annual aggregate and returns created id.
void deleteActor(const std::string &id)
Deletes actor by id.
std::string addContract(const core::ports::workspace::ContractCommand &command)
Adds contract and returns created id.
void updateAnnual(const core::ports::workspace::AnnualCommand &command)
Updates annual aggregate identified by command id.
std::string addProperty(const core::ports::workspace::PropertyCommand &command)
Adds property and returns created id.
void updateAnalysis(const core::ports::workspace::AnalysisCommand &command)
Updates analysis identified by command id.
std::string addAnalysis(const core::ports::workspace::AnalysisCommand &command)
Adds analysis and returns created id.
std::string addStatement(const core::ports::workspace::StatementCommand &command)
Adds statement and returns created id.
void updateProperty(const core::ports::workspace::PropertyCommand &command)
Updates property identified by command id.
Maintains the editable app state for one workspace and persists it through IStorageManager.
void commit()
Persists the session when a file is open and notifies listeners.
const core::domain::catalog::WorkspaceCatalog & catalogState() const noexcept
core::domain::catalog::WorkspaceCatalog & mutableCatalogState() noexcept
void setAliases(std::vector< Alias > value)
const std::string & id() const noexcept
void rename(EntityName value)
Renames the actor with normalized entity text.
void setContractIds(std::vector< std::string > value)
Replaces all linked contract identifiers.
void rename(EntityName value)
Renames the analysis with normalized entity text.
void setAdjustment(std::string key, double value)
Sets or updates a normalized adjustment entry.
void setExportStateJson(std::string value)
Stores the export state JSON snapshot.
void setType(AnalysisType value)
Sets the analysis type from a value object.
void setSnapshotTransactionsJson(std::string value)
Stores the snapshot transactions JSON.
void setExportFormat(ExportFormat value)
Sets the export format from a value object.
void setFilterSpec(FilterSpec value)
Sets the filter specification from a value object.
void setConfigJson(std::string value)
Stores the raw configuration JSON.
void clearAdjustments()
Clears all adjustment entries.
void setIncludeCalculationAdjustments(bool value)
Enables or disables calculation adjustments.
const std::string & value() const noexcept
static bool isValid(const std::string &value)
Checks whether a raw analysis type is valid.
void apply(std::string nameValue, int yearValue, std::vector< std::string > analysisIdsValue)
Applies the complete annual definition in one normalized domain step.
const std::string & value() const noexcept
bool empty() const noexcept
void setAliases(std::vector< Alias > value)
void setType(ContractType value)
Sets the contract type from a normalized value object.
bool containsActorId(const std::string &value) const
Checks whether an actor id exists.
bool containsPropertyId(const std::string &value) const
Checks whether a property id exists.
void removePropertyId(const std::string &value)
Removes a property id from the contract.
const std::string & allocatableMode() const noexcept
void setActorIds(std::vector< std::string > value)
Replaces the linked actor ids with normalized values.
void removeActorId(const std::string &value)
Removes an actor id from the contract.
const std::string & id() const noexcept
void setPropertyIds(std::vector< std::string > value)
Replaces the linked property ids with normalized values.
void addPropertyId(std::string value)
Adds a property id when it is not already present.
void rename(EntityName value)
Renames the contract with normalized entity text.
void setAllocatableMode(std::string value)
const std::vector< std::string > & actorIds() const noexcept
static bool isValid(const std::string &value)
Checks whether a raw contract type is valid.
static bool isValid(const std::string &value)
Checks whether a raw name is valid.
static bool isValid(const std::string &value)
Checks whether a raw export format is valid.
const std::string & value() const noexcept
static bool isValid(const std::string &value)
Checks whether a raw filter specification is valid.
static bool isValid(double value) noexcept
Checks whether a raw amount is finite.
const std::string & id() const noexcept
void addTransaction(std::string value)
Adds a normalized transaction id when it is not already present.
void removeTransaction(const std::string &value)
Removes a transaction id from the statement.
const std::vector< std::string > & transactionIds() const noexcept
void rename(EntityName value)
Renames the statement with normalized entity text.
void setAmount(MoneyAmount value)
Sets the amount from a value object.
void setStatementId(std::string value)
Sets the statement id.
void setActorId(std::string value)
Sets the actor id.
void setName(EntityName value)
Sets the transaction name from a value object.
void setStatus(Status value)
Sets the transaction status.
void setValuta(std::string value)
Sets the valuta text.
void setContractId(std::string value)
Sets the contract id.
const std::string & id() const noexcept
const std::string & name() const noexcept
const std::vector< std::string > & propertyIds() const noexcept
const std::string & statementId() const noexcept
void setPropertyIds(std::vector< std::string > value)
Replaces the property id list with normalized values.
const std::string & actorId() const noexcept
const std::string & bookingDate() const noexcept
const std::string & valuta() const noexcept
const Status & status() const noexcept
void setBookingDate(BookingDate value)
Sets the booking date from a value object.
void setAllocatable(bool value)
Sets the allocatable flag.
const double & amount() const noexcept
const std::string & contractId() const noexcept
static bool isValid(int value) noexcept
Checks whether a raw year is valid.
EntityList< core::domain::Transaction > TransactionList
void setAnnuals(AnnualList value)
Replaces all annuals in the catalog.
const PropertyList & properties() const noexcept
Returns all properties in the catalog.
void setAnalyses(AnalysisList value)
Replaces all analyses in the catalog.
void setProperties(PropertyList value)
Replaces all properties in the catalog.
void setStatements(StatementList value)
Replaces all statements in the catalog.
const AnnualList & annuals() const noexcept
Returns all annuals in the catalog.
EntityList< core::domain::Statement > StatementList
const StatementList & statements() const noexcept
Returns all statements in the catalog.
const TransactionList & transactions() const noexcept
Returns all transactions in the catalog.
void setActors(ActorList value)
Replaces all actors in the catalog.
const ActorList & actors() const noexcept
Returns all actors in the catalog.
void setContracts(ContractList value)
Replaces all contracts in the catalog.
const ContractList & contracts() const noexcept
Returns all contracts in the catalog.
const AnalysisList & analyses() const noexcept
Returns all analyses in the catalog.
void setTransactions(TransactionList value)
Replaces all transactions in the catalog.
std::string buildAnalysisConfigJson(const core::ports::analysis::AnalysisConfigInput &input)
std::optional< double > parseAmountString(const std::string &s)
std::string trimCopy(std::string value)
Trims leading and trailing whitespace from text.
bool supportsResultType(const std::string &type)
Checks whether an analysis type is supported at all.
bool hasUniqueAnalysisIds(const std::vector< std::string > &analysisIds)
Checks whether all analysis ids are unique.
bool isValidYear(int year)
Checks whether a year is valid for annual aggregates.
bool hasValidBookingDate(const std::string &value)
Checks whether a booking date value is valid.
bool hasValidAmount(double value)
Checks whether a transaction amount value is valid.
std::string buildAnalysisFilterSpec(const AnalysisFilterSelection &selection)
Serializes an analysis filter selection.
std::string makeStableId()
Generates a stable hex identifier for persisted entities.
std::string currentTimestampUtc()
Returns the current UTC timestamp in ISO-8601 format.
std::vector< std::string > contractIds
std::vector< AliasSnapshot > aliases
std::vector< TransactionSnapshot > snapshotTransactions
core::ports::analysis::AnalysisFilterSelection filter
bool includeCalculationAdjustments
std::vector< std::pair< std::string, double > > adjustments
core::ports::analysis::AnalysisConfigInput config
std::vector< std::string > assignedAnalysisIds
std::vector< std::string > actorIds
std::string allocatableMode
std::vector< std::string > propertyIds
std::vector< AliasSnapshot > aliases
std::vector< std::string > contractIds
std::vector< AliasSnapshot > aliases
Creates a statement together with its initial transactions.
StatementCommand statement
Statement creation data.
std::vector< TransactionCommand > transactions
Transaction creation data; statement ids are assigned by core.
std::string insertAfterTransactionId
std::vector< std::string > propertyIds
void addError(std::string field, std::string code, std::string message)
Adds an error issue.
bool valid() const noexcept
Reports whether the validation result has no errors.
std::vector< ValidationIssue > issues