FOSSredder 0.5.0
Loading...
Searching...
No Matches
ImportViewModel.cpp
Go to the documentation of this file.
1
5
7
8#include <QFileInfo>
9
10#include "ui/i18n/Text.h"
14#include "ui/shell/AppActions.h"
15#include "ui/shell/Navigation.h"
16#include "ui/shell/Settings.h"
17#include "ui/shell/Status.h"
24
25namespace ui {
26
27namespace {
28
29constexpr int kSuggestionDanger = 0;
30constexpr int kSuggestionWarning = 1;
31constexpr int kSuggestionSuccess = 2;
32
33} // namespace
34
36 : QObject(parent),
37 contractAllocatableMode_(payload::contract_allocatable_mode::kMixed) {}
38
40 if (importWorkflow_ == value) {
41 return;
42 }
43 bindImportWorkflow(value);
44 if (importWorkflow_) {
45 importWorkflow_->setWorkspaceRoles(commands_, selectors_);
46 }
47 syncTransactionDraftFromWorkflow();
48 updateManualPathFromWorkflow();
49 applyDefaultImportSelection();
50 emit changed();
51}
52
54 if (settings_ == value) {
55 return;
56 }
57 bindSettings(value);
58 applyDefaultImportSelection();
59 emit changed();
60}
61
63 if (actions_ == value) {
64 return;
65 }
66 bindActions(value);
67 emit changed();
68}
69
71 if (navigation_ == value) {
72 return;
73 }
74 navigation_ = value;
75 emit changed();
76}
77
79 if (status_ == value) {
80 return;
81 }
82 status_ = value;
83 emit changed();
84}
85
87 WorkspaceCommands* commands,
88 WorkspaceSelection* selection,
89 WorkspaceSelectors* selectors) {
90 if (store_ == store && commands_ == commands && selection_ == selection &&
91 selectors_ == selectors) {
92 return;
93 }
94 bindWorkspaceRoles(store, commands, selection, selectors);
95 if (importWorkflow_) {
96 importWorkflow_->setWorkspaceRoles(commands_, selectors_);
97 }
98 applyDefaultImportSelection();
99 emit changed();
100}
101
102void ImportViewModel::bindImportWorkflow(ImportWorkflow* value) {
103 if (importWorkflow_) {
104 disconnect(importWorkflow_, nullptr, this, nullptr);
105 }
106 importWorkflow_ = value;
107 if (!importWorkflow_) {
108 return;
109 }
110 connect(importWorkflow_, &ImportWorkflow::stateChanged, this, [this]() {
111 updateManualPathFromWorkflow();
112 syncTransactionDraftFromWorkflow();
113 emit changed();
114 });
115 connect(importWorkflow_, &ImportWorkflow::importCanceled, this, [this]() {
116 setStatusText(tr("Import canceled"));
117 });
118 connect(importWorkflow_, &ImportWorkflow::importFinished, this, [this]() {
119 setStatusText(tr("Import finished"));
120 });
121 connect(importWorkflow_, &ImportWorkflow::importFailed, this,
122 [this](const QString& error) {
123 setStatusText(error.isEmpty() ? tr("Import failed") : error);
124 });
125}
126
127void ImportViewModel::bindSettings(Settings* value) {
128 if (settings_) {
129 disconnect(settings_, nullptr, this, nullptr);
130 }
131 settings_ = value;
132 if (settings_) {
133 connect(settings_, &Settings::importDefaultPathChanged, this, [this]() {
134 applyDefaultImportSelection();
135 emit changed();
136 });
137 }
138}
139
140void ImportViewModel::bindActions(Actions* value) {
141 if (actions_) {
142 disconnect(actions_, nullptr, this, nullptr);
143 }
144 actions_ = value;
145 if (!actions_) {
146 return;
147 }
148 connect(actions_, &Actions::importFileSelected, this,
149 [this](const QString& path) {
150 manualPathText_ = path;
151 setSelectedImportFiles(QStringList{path});
152 });
153 connect(actions_, &Actions::importFilesSelected, this,
154 [this](const QStringList& paths) {
155 manualPathText_ = paths.isEmpty() ? QString{} : paths.front();
156 setSelectedImportFiles(paths);
157 });
158 connect(actions_, &Actions::importFileDropped, this,
159 [this](const QString& path) {
160 queueImportFiles(QStringList{path});
161 });
162 connect(actions_, &Actions::importFilesDropped, this,
163 [this](const QStringList& paths) {
164 queueImportFiles(paths);
165 });
166}
167
168void ImportViewModel::bindWorkspaceRoles(WorkspaceStore* store,
169 WorkspaceCommands* commands,
170 WorkspaceSelection* selection,
171 WorkspaceSelectors* selectors) {
172 if (store_) {
173 disconnect(store_, nullptr, this, nullptr);
174 }
175 store_ = store;
176 commands_ = commands;
177 selection_ = selection;
178 selectors_ = selectors;
179 if (store_) {
180 connect(store_, &WorkspaceStore::dataRevisionChanged, this, [this]() {
181 applyDefaultImportSelection();
182 reloadCurrentTransactionView();
183 emit changed();
184 });
185 }
186}
187
188void ImportViewModel::setManualPathText(const QString& value) {
189 if (manualPathText_ == value) {
190 return;
191 }
192 manualPathText_ = value;
193 selectedImportFiles_.clear();
194 emit changed();
195}
196
197QStringList ImportViewModel::importFiles() const {
198 QStringList files;
199 if (!importWorkflow_) {
200 return files;
201 }
202 if (!importWorkflow_->selectedFile().isEmpty()) {
203 files.push_back(importWorkflow_->selectedFile());
204 }
205 files.append(importWorkflow_->queuedFiles());
206 return files;
207}
208
210 const QStringList files = importFiles();
211 if (files.isEmpty()) {
212 return {};
213 }
214
215 QStringList names;
216 names.reserve(files.size());
217 for (const QString& file : files) {
218 const QString name = QFileInfo(file).fileName();
219 names.push_back(name.isEmpty() ? file : name);
220 }
221 return tr("Selected: %1").arg(names.join(QStringLiteral(", ")));
222}
223
225 applyDefaultImportSelection();
226}
227
228void ImportViewModel::applyDefaultImportSelection() {
229 if (!importWorkflow_ || !settings_ || importWorkflow_->isRunning()) {
230 return;
231 }
232 if (importWorkflow_->queuedCount() > 0) {
233 return;
234 }
235 const QString currentFile = importWorkflow_->selectedFile();
236 const QString defaultPath = settings_->importDefaultPath();
237 const bool canReplaceSelection =
238 currentFile.isEmpty() || currentFile == appliedDefaultImportPath_;
239 if (!canReplaceSelection || currentFile == defaultPath) {
240 return;
241 }
242 importWorkflow_->setSelectedFile(defaultPath);
243 appliedDefaultImportPath_ = defaultPath;
244 updateManualPathFromWorkflow();
245 emit changed();
246}
247
249 if (actions_) {
250 actions_->browseImportPdf();
251 }
252}
253
255 QStringList files = selectedImportFiles_;
256 if (files.isEmpty() && !manualPathText_.trimmed().isEmpty()) {
257 files.push_back(manualPathText_);
258 }
259 queueImportFiles(files);
260 if (!files.isEmpty()) {
261 manualPathText_.clear();
262 selectedImportFiles_.clear();
263 emit changed();
264 }
265}
266
267void ImportViewModel::queueImportFiles(const QStringList& paths) {
268 if (!importWorkflow_) {
269 return;
270 }
271 const QStringList supported = supportedImportFiles(paths);
272 if (supported.isEmpty()) {
273 return;
274 }
276 "ImportViewModel::queueImportFiles", "Import files queued",
277 {{observability::context::kQueuedCount, std::to_string(supported.size())},
278 {observability::context::kFirstFile, supported.front().toStdString()}});
279 importWorkflow_->addFiles(supported);
280 selectedImportFiles_.clear();
281 emit changed();
282}
283
284void ImportViewModel::updateManualPathFromWorkflow() {
285 if (!importWorkflow_ || !selectedImportFiles_.isEmpty()) {
286 return;
287 }
288 const QString selectedFile = importWorkflow_->selectedFile();
289 if (manualPathText_ != selectedFile) {
290 manualPathText_ = selectedFile;
291 }
292}
293
294void ImportViewModel::setSelectedImportFiles(const QStringList& paths) {
295 selectedImportFiles_ = paths;
296 emit changed();
297}
298
299QStringList
300ImportViewModel::supportedImportFiles(const QStringList& paths) const {
301 QStringList supported;
302 for (const QString& path : paths) {
303 const QString trimmed = path.trimmed();
304 if (trimmed.isEmpty()) {
305 continue;
306 }
307 if (QFileInfo(trimmed).suffix().compare(QStringLiteral("pdf"),
308 Qt::CaseInsensitive) == 0) {
309 supported.push_back(trimmed);
310 }
311 }
312 return supported;
313}
314
315int ImportViewModel::contentIndex() const noexcept {
316 return hasDraft() ? 1 : 0;
317}
318
320 return importWorkflow_ != nullptr;
321}
322
323bool ImportViewModel::hasDraft() const noexcept {
324 return importWorkflow_ && importWorkflow_->hasDraft();
325}
326
328 return selectors_ && !selectors_->attachedImportDraftIds().isEmpty();
329}
330
331bool ImportViewModel::canClearImport() const noexcept {
332 return importWorkflow_ && !importWorkflow_->isRunning();
333}
334
335bool ImportViewModel::canCancel() const noexcept {
336 return importWorkflow_ && importWorkflow_->isRunning();
337}
338
339bool ImportViewModel::canPause() const noexcept {
340 return importWorkflow_ && importWorkflow_->isRunning();
341}
342
343bool ImportViewModel::canStart() const noexcept {
344 if (!importWorkflow_ || importWorkflow_->isRunning()) {
345 return false;
346 }
347 return !importWorkflow_->selectedFile().isEmpty() ||
348 importWorkflow_->queuedCount() > 0;
349}
350
351bool ImportViewModel::importRunning() const noexcept {
352 return importWorkflow_ && importWorkflow_->isRunning();
353}
354
355bool ImportViewModel::importPaused() const noexcept {
356 return importWorkflow_ && importWorkflow_->isPaused();
357}
358
360 return importWorkflow_ && importWorkflow_->isPaused() ? tr("Resume")
361 : tr("Pause");
362}
363
365 if (!importWorkflow_) {
366 return tr("Ready");
367 }
368 if (!importWorkflow_->error().isEmpty()) {
369 return importWorkflow_->error();
370 }
371 return importWorkflow_->phase().isEmpty() ? tr("Ready")
372 : importWorkflow_->phase();
373}
374
376 return importWorkflow_ && !importWorkflow_->error().isEmpty();
377}
378
379double ImportViewModel::progressValue() const noexcept {
380 return importWorkflow_ ? importWorkflow_->progress() : 0.0;
381}
382
383int ImportViewModel::queuedCount() const noexcept {
384 return importWorkflow_ ? importWorkflow_->queuedCount() : 0;
385}
386
387QVariantList ImportViewModel::importLogs() const {
388 return selectors_ ? selectors_->importLogRows() : QVariantList{};
389}
390
392 return importWorkflow_ ? importWorkflow_->currentDraftId() : QString();
393}
394
396 return {tr("PDF")};
397}
398
400 return {tr("Commerzbank26")};
401}
402
404 manualPathText_.clear();
405 selectedImportFiles_.clear();
406 appliedDefaultImportPath_.clear();
407 if (importWorkflow_) {
408 importWorkflow_->resetStatus();
409 }
410 emit changed();
411}
412
414 if (importWorkflow_) {
415 importWorkflow_->cancelImport();
416 }
417}
418
420 if (importWorkflow_) {
421 importWorkflow_->cancelQueuedImports();
422 }
423}
424
426 if (importWorkflow_ && importWorkflow_->isRunning() &&
427 !importWorkflow_->isPaused()) {
428 importWorkflow_->pauseImport();
429 }
430}
431
433 if (importWorkflow_ && importWorkflow_->isRunning() &&
434 importWorkflow_->isPaused()) {
435 importWorkflow_->resumeImport();
436 }
437}
438
440 if (importWorkflow_) {
441 importWorkflow_->startStatementImport();
442 }
443}
444
445int ImportViewModel::activeDraftStackIndex() const {
446 if (!importWorkflow_ || !selectors_) {
447 return -1;
448 }
449 const auto ids = selectors_->attachedImportDraftIds();
450 if (ids.isEmpty() || !importWorkflow_->hasDraft() ||
451 importWorkflow_->currentDraftId().isEmpty()) {
452 return -1;
453 }
454 return ids.indexOf(importWorkflow_->currentDraftId());
455}
456
457bool ImportViewModel::openDraftAtStackIndex(int index) {
458 if (!importWorkflow_ || !selectors_) {
459 return false;
460 }
461 const auto ids = selectors_->attachedImportDraftIds();
462 if (index < 0 || index >= ids.size()) {
463 return false;
464 }
465 return importWorkflow_->openStoredDraft(ids.at(index));
466}
467
469 if (!importWorkflow_ || !selectors_) {
470 return;
471 }
472 const auto ids = selectors_->attachedImportDraftIds();
473 if (ids.isEmpty()) {
474 return;
475 }
476 const int index = activeDraftStackIndex();
477 if (index < 0 || index >= ids.size()) {
478 openDraftAtStackIndex(ids.size() - 1);
479 return;
480 }
481 if (index == 0) {
482 importWorkflow_->clearDraft();
483 emit changed();
484 return;
485 }
486 openDraftAtStackIndex((index + ids.size() - 1) % ids.size());
487 emit changed();
488}
489
491 if (!importWorkflow_ || !selectors_) {
492 return;
493 }
494 const auto ids = selectors_->attachedImportDraftIds();
495 if (ids.isEmpty()) {
496 return;
497 }
498 const int index = activeDraftStackIndex();
499 if (index < 0 || index >= ids.size()) {
500 openDraftAtStackIndex(0);
501 return;
502 }
503 if (index == ids.size() - 1) {
504 importWorkflow_->clearDraft();
505 emit changed();
506 return;
507 }
508 openDraftAtStackIndex((index + 1) % ids.size());
509 emit changed();
510}
511
512void ImportViewModel::openImportLog(const QString& logId, bool draftAttached,
513 const QString& statementId,
514 const QString& draftId) {
515 if (!importWorkflow_) {
516 return;
517 }
518 if (draftAttached) {
519 const QString targetDraftId = !draftId.isEmpty() ? draftId : logId;
520 observability::traceViewModel("ImportViewModel::openImportLog",
521 "Import draft log opened",
522 {{"logId", logId.toStdString()},
523 {"draftId", targetDraftId.toStdString()}});
524 const QString currentDraftId = importWorkflow_->currentDraftId();
525 if (targetDraftId != currentDraftId) {
526 importWorkflow_->openStoredDraft(targetDraftId);
527 }
528 if (navigation_) {
529 navigation_->setSection(Navigation::Section::Import);
530 }
531 return;
532 }
533
534 if (statementId.isEmpty() || !selection_) {
535 return;
536 }
537 selection_->selectTransaction(statementId, {});
538 observability::traceViewModel("ImportViewModel::openImportLog",
539 "Import statement log opened",
540 {{"logId", logId.toStdString()},
541 {"statementId", statementId.toStdString()}});
542 if (navigation_) {
543 navigation_->setSection(Navigation::Section::Booking);
544 }
545}
546
547void ImportViewModel::deleteImportLog(const QString& logId, bool draftAttached,
548 const QString& draftId) {
549 if (importWorkflow_) {
550 importWorkflow_->removeAttachedImportLog(logId, draftAttached, draftId);
551 } else if (commands_ && !logId.isEmpty()) {
552 commands_->deleteImportLog(logId);
553 }
554}
555
556void ImportViewModel::setStatusText(const QString& text) {
557 if (status_) {
558 status_->setText(text);
559 }
560 emit changed();
561}
562
564 return importWorkflow_ ? importWorkflow_->currentStatementName() : QString();
565}
566
567void ImportViewModel::setStatementName(const QString& value) {
568 if (!importWorkflow_ || statementName() == value) {
569 return;
570 }
571 if (importWorkflow_->renameCurrentStatementDraft(value)) {
572 emit changed();
573 }
574}
575
577 if (!hasDraft()) {
578 return 0;
579 }
580 return importWorkflow_->currentTransactionIndex() + 1;
581}
582
584 return importWorkflow_ ? importWorkflow_->transactionCount() : 0;
585}
586
588 return importWorkflow_ && importWorkflow_->transactionCount() > 1;
589}
590
592 return importWorkflow_ && importWorkflow_->currentTransactionIndex() > 0;
593}
594
596 return importWorkflow_ && importWorkflow_->currentTransactionIndex() <
597 importWorkflow_->transactionCount() - 1;
598}
599
601 if (!importWorkflow_) {
602 return;
603 }
604 importWorkflow_->pauseActiveDraft();
605 emit changed();
606}
607
609 if (!importWorkflow_) {
610 return;
611 }
612 importWorkflow_->discardActiveDraft();
613 emit changed();
614}
615
617 if (!hasDraft() || !importWorkflow_) {
618 return;
619 }
620 if (importWorkflow_->insertTransactionAfterCurrent() >= 0) {
621 emit changed();
622 }
623}
624
626 if (!canDeleteTransaction() || !importWorkflow_) {
627 return;
628 }
629 if (importWorkflow_->removeCurrentTransaction() >= 0) {
630 emit changed();
631 }
632}
633
635 if (!importWorkflow_) {
636 return;
637 }
638 importWorkflow_->finalizeActiveDraft();
639 emit changed();
640}
641
644 return;
645 }
646 importWorkflow_->setCurrentTransactionIndex(
647 importWorkflow_->currentTransactionIndex() - 1);
648}
649
652 return;
653 }
654 importWorkflow_->setCurrentTransactionIndex(
655 importWorkflow_->currentTransactionIndex() + 1);
656}
657
658void ImportViewModel::syncTransactionDraftFromWorkflow() {
659 const QString previousId = lastTransactionId_;
660 reloadCurrentTransactionView();
661 const QString id = currentTransactionView_.id;
662 if (!id.isEmpty() && id == previousId) {
663 return;
664 }
665 lastTransactionId_ = id;
666 resetTransactionDraftFields();
667}
668
669void ImportViewModel::resetTransactionDraftFields() {
670 nameText_ = currentTransactionView_.name;
671 bookingDateText_ = currentTransactionView_.bookingDate;
672 valutaText_ = currentTransactionView_.valuta;
673 amountText_ = currentTransactionView_.amountText;
674 actorName_.clear();
675 contractName_.clear();
676 contractType_.clear();
677 contractAllocatableMode_ = payload::contract_allocatable_mode::kMixed;
678 propertyName_.clear();
679}
680
681void ImportViewModel::reloadCurrentTransactionView() {
682 currentTransactionView_ = {};
683 if (!importWorkflow_) {
684 return;
685 }
686 currentTransactionView_ = importWorkflow_->currentTransactionView();
687}
688
689void ImportViewModel::setNameText(const QString& value) {
690 if (nameText_ == value) {
691 return;
692 }
693 nameText_ = value;
694 emit changed();
695}
696
697void ImportViewModel::setBookingDateText(const QString& value) {
698 if (bookingDateText_ == value) {
699 return;
700 }
701 bookingDateText_ = value;
702 emit changed();
703}
704
705void ImportViewModel::setValutaText(const QString& value) {
706 if (valutaText_ == value) {
707 return;
708 }
709 valutaText_ = value;
710 emit changed();
711}
712
713void ImportViewModel::setAmountText(const QString& value) {
714 if (amountText_ == value) {
715 return;
716 }
717 amountText_ = value;
718 emit changed();
719}
720
728
731 statusOptions(), currentTransactionView_.status);
732}
733
735 return currentTransactionView_.metadata;
736}
737
739 return currentTransactionView_.proofSource;
740}
741
743 return currentTransactionView_.effectiveAllocatable;
744}
745
747 if (!importWorkflow_ || nameText_ == currentTransactionView_.name) {
748 return;
749 }
750 importWorkflow_->commitCurrentTransactionName(nameText_);
751}
752
754 if (!importWorkflow_ ||
755 bookingDateText_ == currentTransactionView_.bookingDate) {
756 return;
757 }
758 importWorkflow_->commitCurrentTransactionBookingDate(bookingDateText_);
759}
760
762 if (!importWorkflow_ || valutaText_ == currentTransactionView_.valuta) {
763 return;
764 }
765 importWorkflow_->commitCurrentTransactionValuta(valutaText_);
766}
767
769 if (!importWorkflow_) {
770 return;
771 }
772 importWorkflow_->applyCurrentTransactionAmountText(amountText_);
773}
774
776 if (!importWorkflow_) {
777 return;
778 }
779 importWorkflow_->setCurrentTransactionStatus(
781}
782
784 if (!importWorkflow_) {
785 return;
786 }
787 importWorkflow_->setCurrentTransactionAllocatable(!effectiveAllocatable());
788}
789
790QVariantList ImportViewModel::actorOptions() const {
791 return selectors_ ? selectors_->actorDropdownRows() : QVariantList{};
792}
793
796 currentTransactionActorId());
797}
798
799void ImportViewModel::setActorName(const QString& value) {
800 if (actorName_ == value) {
801 return;
802 }
803 actorName_ = value;
804 emit changed();
805}
806
808 return selectors_ && !strings::normalizedText(actorName_).isEmpty() &&
809 selectors_->actorIdByName(actorName_).isEmpty();
810}
811
813 if (!importWorkflow_) {
814 return;
815 }
816 const QString id =
818 if (id.isEmpty()) {
819 importWorkflow_->clearCurrentTransactionActor();
820 } else {
821 importWorkflow_->selectCurrentTransactionActor(id);
822 }
823}
824
826 if (!canAddActor() || !importWorkflow_) {
827 return;
828 }
829 importWorkflow_->createActorForCurrentTransaction(actorName_);
830}
831
833 return selectors_ ? selectors_->propertyDropdownRows() : QVariantList{};
834}
835
836void ImportViewModel::setPropertyName(const QString& value) {
837 if (propertyName_ == value) {
838 return;
839 }
840 propertyName_ = value;
841 emit changed();
842}
843
845 return selectors_ && !strings::normalizedText(propertyName_).isEmpty() &&
846 selectors_->propertyIdByName(propertyName_).isEmpty();
847}
848
849bool ImportViewModel::isPropertySelected(const QString& propertyId) const {
850 return currentTransactionPropertyIds().contains(propertyId);
851}
852
853void ImportViewModel::setPropertySelected(const QString& propertyId,
854 bool selected) {
855 if (importWorkflow_) {
856 importWorkflow_->setCurrentTransactionPropertySelected(propertyId,
857 selected);
858 }
859}
860
862 if (!canAddProperty() || !importWorkflow_) {
863 return;
864 }
865 if (importWorkflow_->createPropertyForCurrentTransaction(propertyName_)) {
866 propertyName_.clear();
867 emit changed();
868 }
869}
870
872 return selectors_ ? selectors_->contractDropdownRows() : QVariantList{};
873}
874
877 currentTransactionView_.contractId);
878}
879
884
886 if (!importWorkflow_) {
887 return;
888 }
889 const QString id =
891 if (id.isEmpty()) {
892 importWorkflow_->clearCurrentTransactionContract();
893 } else {
894 importWorkflow_->selectCurrentTransactionContract(id);
895 }
896}
897
898void ImportViewModel::setContractName(const QString& value) {
899 if (contractName_ == value) {
900 return;
901 }
902 contractName_ = value;
903 emit changed();
904}
905
906void ImportViewModel::setContractType(const QString& value) {
907 if (contractType_ == value) {
908 return;
909 }
910 contractType_ = value;
911 emit changed();
912}
913
915 if (selectors_) {
916 return selectors_->nextContractName();
917 }
918 return tr("Contract 1");
919}
920
923 tr("Mixed"), tr("All allocatable"), tr("Never allocatable"));
924}
925
930
933 contractAllocatableModes(), index);
934 if (contractAllocatableMode_ == mode) {
935 return;
936 }
937 contractAllocatableMode_ = mode;
938 emit changed();
939}
940
942 if (!selectors_ || strings::normalizedText(contractType_).isEmpty()) {
943 return false;
944 }
945 const QString actorId = currentTransactionActorId();
946 QStringList actorIds;
947 if (!actorId.trimmed().isEmpty()) {
948 actorIds.push_back(actorId.trimmed());
949 }
950 const QString effectiveName = contractName_.trimmed().isEmpty()
951 ? selectors_->nextContractName()
952 : contractName_.trimmed();
953 return selectors_
954 ->contractIdBySignature(effectiveName, contractType_, actorIds,
955 currentTransactionPropertyIds())
956 .isEmpty();
957}
958
960 if (!canAddContract() || !importWorkflow_) {
961 return;
962 }
963 if (importWorkflow_->createOrSelectContractForCurrentTransaction(
964 contractName_, contractType_, contractAllocatableMode_)) {
965 emit changed();
966 }
967}
968
969QString ImportViewModel::displaySuggestionSummary(const QString& value) const {
970 return value.isEmpty() ? tr("0% Confidence - No suggestion") : value;
971}
972
973QString ImportViewModel::currentTransactionId() const {
974 return currentTransactionView_.id;
975}
976
977QStringList ImportViewModel::currentTransactionPropertyIds() const {
978 return currentTransactionView_.propertyIds;
979}
980
981QString ImportViewModel::currentTransactionActorId() const {
982 return currentTransactionView_.actorId;
983}
984
985int ImportViewModel::suggestionTone(double confidence) const {
986 if (confidence >= 0.9) {
987 return kSuggestionSuccess;
988 }
989 if (confidence >= 0.4) {
990 return kSuggestionWarning;
991 }
992 return kSuggestionDanger;
993}
994
996 return currentTransactionView_.actorSuggestionConfidence;
997}
998
1000 return displaySuggestionSummary(
1001 currentTransactionView_.actorSuggestionSummary);
1002}
1003
1005 return currentTransactionView_.propertySuggestionConfidence;
1006}
1007
1009 return displaySuggestionSummary(
1010 currentTransactionView_.propertySuggestionSummary);
1011}
1012
1014 return currentTransactionView_.contractSuggestionConfidence;
1015}
1016
1018 return displaySuggestionSummary(
1019 currentTransactionView_.contractSuggestionSummary);
1020}
1021
1023 return currentTransactionView_.allocatableSuggestionConfidence;
1024}
1025
1027 return displaySuggestionSummary(
1028 currentTransactionView_.allocatableSuggestionSummary);
1029}
1030
1031} // namespace ui
Declares QAction wrappers exposed to the UI layer and QML.
Declares the QML API for import overview and draft review.
Coordinates asynchronous statement imports and in-memory draft sessions.
Declarations for the UI Navigation component.
Declarations for the UI Origins component.
Declarations for the UI payload mapper helpers.
Declares the centralized UI settings view model exposed to QML.
Declarations for the UI Status component.
Declares lightweight conversions between common Qt string types and standard strings.
Provides translated C++ UI strings for shell, workflow, adapter and view model code.
Declarations for the UI Trace component.
Declares the workspace selection state synchronized with the store.
Declares read-only workspace selectors for QML payloads.
Declares the UI workspace snapshot store.
Owns the main window actions and exposes them to QML.
Definition AppActions.h:18
void importFileSelected(const QString &path)
Emitted after a single import file was selected by the user.
void importFileDropped(const QString &path)
Emitted when a file was dropped onto an import target in QML.
void importFilesSelected(const QStringList &paths)
Emitted after multiple import files were selected by the user.
void importFilesDropped(const QStringList &paths)
Emitted when multiple files were dropped onto an import target in QML.
Q_INVOKABLE void initializeImportView()
Initializes import view state when the view is opened.
void setSettings(Settings *value)
Sets settings used for import defaults.
Q_INVOKABLE void commitAmountText()
Commits the amount field to the workflow draft.
Q_INVOKABLE void startImport()
Starts importing the selected files.
Q_INVOKABLE void finalize()
Finalizes the active statement draft through the import workflow.
void setImportWorkflow(ImportWorkflow *value)
Sets the import workflow used for import runs and draft review.
void setAmountText(const QString &value)
Updates the amount field.
QStringList importSourceLabels
Q_INVOKABLE void discard()
Discards the active statement draft.
void setWorkspaceRoles(WorkspaceStore *store, WorkspaceCommands *commands, WorkspaceSelection *selection, WorkspaceSelectors *selectors)
Sets workspace roles used for import logs, catalog and selection.
QVariantList actorOptions
Q_INVOKABLE void selectStatusAtIndex(int index)
Selects a transaction status option.
Q_INVOKABLE void toggleAllocatable()
Toggles the current draft allocatable state.
Q_INVOKABLE void selectContractAtIndex(int index)
Selects a contract option.
Q_INVOKABLE void deleteImportLog(const QString &logId, bool draftAttached, const QString &draftId)
Deletes an import log and attached draft state when requested.
Q_INVOKABLE void selectNextDraft()
Selects the next statement draft.
Q_INVOKABLE void addContract()
Creates and selects a contract for the current draft.
QVariantList statusOptions
void setStatementName(const QString &value)
Updates the active statement draft name field.
Q_INVOKABLE void addProperty()
Creates and selects a property for the current draft.
Q_INVOKABLE void commitValutaText()
Commits the valuta field to the workflow draft.
Q_INVOKABLE void returnToImport()
Returns from draft review to the import overview.
Q_INVOKABLE void pauseImport()
Pauses the current import job.
ImportViewModel(QObject *parent=nullptr)
Creates the import view model.
Q_INVOKABLE void selectPreviousTransactionDraft()
Selects the previous transaction draft.
Q_INVOKABLE void cancelCurrentImport()
Cancels the current import job.
Q_INVOKABLE void commitBookingDateText()
Commits the booking date field to the workflow draft.
void setStatus(Status *value)
Sets shell status output used by import actions.
Q_INVOKABLE void openImportLog(const QString &logId, bool draftAttached, const QString &statementId, const QString &draftId)
Opens an import log from the sidebar.
Q_INVOKABLE void setPropertySelected(const QString &propertyId, bool selected)
Updates whether a property is selected for the current draft.
Q_INVOKABLE int suggestionTone(double confidence) const
Maps suggestion confidence to a presentation tone.
void setContractType(const QString &value)
Updates the quick-create contract type field.
Q_INVOKABLE void addActor()
Creates and selects an actor for the current draft.
QVariantList contractAllocatableModes
Q_INVOKABLE void resumeImport()
Resumes a paused import job.
Q_INVOKABLE void browseImportPdf()
Opens a file browser for import PDFs.
void setNameText(const QString &value)
Updates the transaction name field.
Q_INVOKABLE void commitNameText()
Commits the transaction name field to the workflow draft.
void setPropertyName(const QString &value)
Updates the quick-create property name field.
bool canSelectPreviousTransactionDraft READ canSelectPreviousTransactionDraft
void changed()
Emitted when import view model state changed.
Q_INVOKABLE void addTransactionAfterCurrent()
Adds a transaction draft after the current one.
QVariantList propertyOptions
void setManualPathText(const QString &value)
Updates the manual import path field.
Q_INVOKABLE bool isPropertySelected(const QString &propertyId) const
Returns whether a property is selected for the current draft.
Q_INVOKABLE void selectNextTransactionDraft()
Selects the next transaction draft.
double propertySuggestionConfidence READ propertySuggestionConfidence
Q_INVOKABLE void selectPreviousDraft()
Selects the previous statement draft.
QStringList statementStrategyLabels
Q_INVOKABLE void addSelectedImportFiles()
Adds the manual path field to the selected import files.
double contractSuggestionConfidence READ contractSuggestionConfidence
double allocatableSuggestionConfidence READ allocatableSuggestionConfidence
Q_INVOKABLE void deleteCurrentTransaction()
Deletes the current transaction draft.
void setNavigation(Navigation *value)
Sets shell navigation used by import transitions.
void setContractName(const QString &value)
Updates the quick-create contract name field.
bool canSelectNextTransactionDraft READ canSelectNextTransactionDraft
void setBookingDateText(const QString &value)
Updates the booking date field.
QVariantList importLogs
Q_INVOKABLE void cancelQueuedImports()
Cancels queued import jobs.
void setValutaText(const QString &value)
Updates the valuta field.
Q_INVOKABLE void clearImport()
Clears the local import selection and progress display.
Q_INVOKABLE void selectActorAtIndex(int index)
Selects an actor option.
void setContractAllocatableModeIndex(int index)
Updates selected contract allocatable mode index.
QVariantList contractOptions
void setActorName(const QString &value)
Updates the quick-create actor name field.
void setActions(Actions *value)
Sets shell actions used for browsing files.
Runs PDF imports and holds the active in-memory statement draft session.
QString currentDraftId() const
Returns the active draft id.
void importFailed(const QString &error)
Emitted when an import failed.
bool isRunning() const noexcept
Reports whether an import is running.
bool hasDraft() const noexcept
Reports whether an active statement draft exists.
int queuedCount() const noexcept
Returns queued import file count.
void stateChanged()
Emitted when import workflow state changed.
void importFinished()
Emitted when an import reached a finished state.
void importCanceled()
Emitted when an import was canceled.
Stores the active top-level shell section and settings sub-section.
Definition Navigation.h:15
Stores and exposes globally persisted UI settings for settings-related views.
Definition Settings.h:19
void importDefaultPathChanged()
Exposes the shell status text shown by the main window.
Definition Status.h:16
void setText(const QString &value)
Updates the current status text.
Definition Status.h:39
Maps UI intent to core workspace writer commands.
Tracks the currently selected workspace entities.
Projects workspace store data into QML-facing read models.
QStringList attachedImportDraftIds() const
Returns ids of import logs that have attached statement drafts.
Owns the current UI-side workspace snapshot and revision lifecycle.
void dataRevisionChanged()
constexpr auto kFirstFile
Definition Trace.h:27
constexpr auto kQueuedCount
Definition Trace.h:36
void traceViewModel(const char *origin, std::string message, core::errors::ErrorContext context={})
Emits a view model trace event.
Definition Trace.h:97
QVariantList options(const QString &mixed, const QString &allocatable, const QString &nonAllocatable)
Builds contract allocatable mode options.
QString modeAt(const QVariantList &options, int index)
Reads the allocatable mode at an option index.
int indexForMode(const QVariantList &options, const QString &mode)
Finds the option index for an allocatable mode.
QVariantMap mapAt(const QVariantList &rows, int index)
Returns a map at an index in a row list.
int indexById(const QVariantList &rows, const QString &id)
Finds the index of a row id.
QString rowType(const QVariantMap &row)
Reads a row type.
QString rowId(const QVariantMap &row)
Reads a row id.
QVariantList options(const QString &neutral, const QString &unverified, const QString &verified, const QString &completed)
Builds transaction status options.
int indexForStatus(const QVariantList &options, int status)
Finds the option index for a transaction status.
int statusAt(const QVariantList &options, int index)
Reads the status value at an option index.
QString normalizedText(const QString &value)
Normalizes text for case-insensitive UI comparisons.
QString verified()
Label for verified transaction status.
Definition Text.h:462
QString neutral()
Label for neutral transaction status.
Definition Text.h:454
QString unverified()
Label for unverified transaction status.
Definition Text.h:458
QString completed()
Label for completed transaction status.
Definition Text.h:466
Declares UI-side workspace command submission.