Compare commits

...

404 Commits

Author SHA1 Message Date
Lorenz Hilpert
967df6316b Merge branch 'release/3.0' into feature/3968-Artikeldetails-Mehrwertsteuer 2023-08-31 14:11:06 +02:00
Lorenz Hilpert
b440ddbe82 Merge branch 'hotfix/4270-4269-Archiv-Artikel'
(cherry picked from commit f4df6e8799)
2023-08-30 14:38:54 +02:00
Nino
878bf44d0b #3968 Article Search Details display vat and if priceMaintained true 2023-08-28 16:51:52 +02:00
Lorenz Hilpert
d6e0d92132 (cherry picked from commit d09b5b1ce7) 2023-08-24 20:18:19 +02:00
Lorenz Hilpert
da6489eb7a Merge tag '4266-Archivartikel' into develop
Hotfix 4266 Archivartikel Preisauswahl
2023-08-24 20:06:36 +02:00
Lorenz Hilpert
819827cc4c Merge branch 'hotfix/4266-Archivartikel' 2023-08-24 20:04:40 +02:00
Lorenz Hilpert
d09b5b1ce7 #4266 Archivartikel nach Preis-Eingabe Button ausgegraut 2023-08-24 20:03:59 +02:00
Lorenz Hilpert
cc03ef4f9c #4264 Fix Ola Refresh Calls 2023-08-24 12:58:53 +02:00
Lorenz Hilpert
b4dbd8889d Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-08-24 12:12:50 +02:00
Lorenz Hilpert
483faad86a #4264 - Bestellen-Button ausgegraut 2023-08-24 11:57:47 +02:00
Michael Auer
0dbc745ed0 Merge tag '2.3' into develop
# Conflicts:
#	apps/isa-app/src/app/shell/shell.component.html
2023-08-24 11:56:11 +02:00
Michael Auer
180e93a7da Merge branch 'release/2.3' 2023-08-24 11:50:39 +02:00
Lorenz Hilpert
5c6f416391 #4263 Versand - Fehler vor Kundensuche 2023-08-23 14:56:57 +02:00
Lorenz Hilpert
d97b6afac8 #4205 Reihensuche 2023-08-23 14:31:55 +02:00
Lorenz Hilpert
771816f3af #4185 OLA Warenkorb - 500 Fix 2023-08-22 13:47:22 +02:00
Lorenz Hilpert
0626538aea #4261 Fehler bei Artikel aus Liste in Warenkorb - Weiter Button War Nicht Aktiv 2023-08-21 15:33:35 +02:00
Lorenz Hilpert
a1ad4e4a05 #4261 Fehler bei Artikel aus Liste in Warenkorb 2023-08-21 15:12:22 +02:00
Lorenz Hilpert
6df48eb555 #4255 Neue Filteroption - Erscheinungsdatum 2023-08-21 14:18:40 +02:00
Lorenz Hilpert
27ab4526e2 Logs entfernt und kleinere Änderungen rückgängig gemacht 2023-08-18 12:48:09 +02:00
Lorenz Hilpert
9a24b34fbc #4255 Verbesserung des Datumsinputs 2023-08-18 12:45:27 +02:00
Lorenz Hilpert
d01e01534b #4185 Bugfix - Bestellabschluss 2023-08-17 17:01:33 +02:00
Lorenz Hilpert
5bca1f2a81 Bugfix - zu viele aurufe bei ola 2023-08-16 15:26:08 +02:00
Lorenz Hilpert
807b300885 #4185 OLA im Warenkorb 2023-08-16 14:54:14 +02:00
Lorenz Hilpert
b16ffa4352 Merge branch 'develop' into release/3.0 2023-08-11 15:34:45 +02:00
Lorenz Hilpert
da79d04ef4 Bugfix Erscheinungsdatum 2023-08-11 15:34:09 +02:00
Lorenz Hilpert
cf619df576 Merge branch 'release/3.0' into develop 2023-08-11 10:29:47 +02:00
Lorenz Hilpert
8054c96315 #3376 Erscheinungstermin Filter Option Mit Input Box 2023-08-11 10:28:14 +02:00
Nino Righi
2363f424f5 Merged PR 1617: #3360 Show Branch Tooltip
#3360 Show Branch Tooltip
2023-08-11 08:11:16 +00:00
Lorenz Hilpert
6ab1ea2e70 #4254 Bestellungen ohne Konto werden nicht als Kunde erkannt 2023-08-10 14:03:18 +02:00
Lorenz Hilpert
c9ce7d6762 #4253 Kundensuche - Typo 2023-08-09 17:53:58 +02:00
Lorenz Hilpert
6ee1b0a7f8 #4250 Vorgänge zählen nicht hoch 2023-08-09 16:50:54 +02:00
Lorenz Hilpert
d881920312 Merge branch 'develop' into release/3.0 2023-08-07 07:07:36 +02:00
Lorenz Hilpert
516465db37 #4246 UI Searchbox Hint Erneut anzeigen
(cherry picked from commit 9671683a93)
2023-08-06 05:11:40 +02:00
Lorenz Hilpert
08e95cec55 #4245 Wannernummer-Prüfung - Leerzeichen entfernen
(cherry picked from commit 15c50779b4)
2023-08-06 05:10:46 +02:00
Lorenz Hilpert
9671683a93 #4246 UI Searchbox Hint Erneut anzeigen 2023-08-04 15:56:51 +02:00
Lorenz Hilpert
d909d6e804 #4236 Kulturpass - Artikel ohne Preisbindung erhalten günstigeren Preis
(cherry picked from commit 1d865c47d7)
2023-08-03 17:06:46 +02:00
Lorenz Hilpert
15c50779b4 #4245 Wannernummer-Prüfung - Leerzeichen entfernen 2023-08-03 17:05:45 +02:00
Lorenz Hilpert
1d865c47d7 #4236 Kulturpass - Artikel ohne Preisbindung erhalten günstigeren Preis 2023-08-03 13:57:09 +02:00
Lorenz Hilpert
5bdfec7c3f #4222 Packstückprüfung aktiviert 2023-08-02 10:55:54 +02:00
Nino Righi
6b0beba1d9 Merged PR 1616: #3378 SSC Sync PDP and Search Result List
#3378 SSC Sync PDP and Search Result List
2023-08-01 16:16:57 +00:00
Lorenz Hilpert
8aafee672e #4244 Kundenkarten-Ansicht wirf Fehler 2023-08-01 15:21:12 +02:00
Lorenz Hilpert
9d886cd33f Merge branch 'develop' into release/3.0 2023-07-31 18:31:30 +02:00
Nino Righi
95d1ea3530 Merged PR 1615: #4235 Fix Scroll Position Customer Orders
#4235 Fix Scroll Position Customer Orders
2023-07-31 14:19:53 +00:00
Lorenz Hilpert
d3014e7e9a #4243 kein Kundenkarten-Checkbox fuer HSC 2023-07-31 15:09:59 +02:00
Lorenz Hilpert
da143c3412 #4241 Seite Bestellungen von Kundendetails wird nach einige Sekunden zu Kunden Trefferliste navigiert 2023-07-31 14:36:51 +02:00
Nino Righi
b10a7a923e Merged PR 1613: #4240 Bestellbestätigung Fix Leere Kachel
#4240 Bestellbestätigung Fix Leere Kachel
2023-07-31 11:45:23 +00:00
Nino Righi
08601203df Merged PR 1614: #4238 Removed QueryChangeDebounce
#4238 Removed QueryChangeDebounce
2023-07-31 11:44:54 +00:00
Lorenz Hilpert
526ba9f2a0 Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-07-28 18:06:45 +02:00
Lorenz Hilpert
f1fc1d17a5 Message bei leerer suche 2023-07-28 18:06:15 +02:00
Nino Righi
6e07c86eed Merged PR 1612: #4228 Gruppierung Bestellbestätigung Abholung und Rücklage
#4228 Gruppierung Bestellbestätigung Abholung und Rücklage
2023-07-28 16:03:14 +00:00
Lorenz Hilpert
14199391e0 #4239 Bereich Kundenkarte hat kein Schließ-Button 2023-07-28 17:33:07 +02:00
Nino
bb834f6274 #4224 Fix Kundenbestellungen Trefferliste Splitscreen Breite der Kachel bzgl der Kundennummer angepasst 2023-07-28 16:43:22 +02:00
Nino Righi
8688935f25 Merged PR 1611: #4233 Fix branch$ should always atleast return defaultBranch if available
#4233 Fix branch$ should always atleast return defaultBranch if available
2023-07-28 14:22:14 +00:00
Lorenz Hilpert
1b7d257e97 #4172 Console.log entfernt 2023-07-28 15:49:37 +02:00
Lorenz Hilpert
fff4b222cb #4172 Keine Suchergebnisse text bei der Ergebnisliste 2023-07-28 15:48:55 +02:00
Lorenz Hilpert
c63dee8509 Merge branch 'release/2.3' into develop 2023-07-28 14:51:41 +02:00
Lorenz Hilpert
810653c4d1 #4194 Icons DR und PP hinzugefügt 2023-07-28 14:50:44 +02:00
Nino Righi
607bc320fb Merged PR 1609: #3395 Bestellbestätigung Verlinkungen und Wording
#3395 Bestellbestätigung Verlinkungen und Wording
2023-07-28 12:26:49 +00:00
Nino Righi
72393ebca5 Merged PR 1610: #4224 Fix Customer Orders Result List Card Size
#4224 Fix Customer Orders Result List Card Size
2023-07-28 12:26:20 +00:00
Lorenz Hilpert
ecef17846b #4226 #4234 Bei Einstieg in Kundensuche wird suche mit Default Filter getriggert 2023-07-28 14:10:00 +02:00
Lorenz Hilpert
45265eedd4 #4230 Keine Kachel in Trefferliste wenn ein Bestellung ohne Konto-Datensatz angelegt wird 2023-07-28 13:34:32 +02:00
Nino Righi
04da34e677 Merged PR 1608: #4233 Fix Article Search Details Fetching Branch correctly
#4233 Fix Article Search Details Fetching Branch correctly
2023-07-27 16:29:43 +00:00
Lorenz Hilpert
1e504d9e0c Merge branch 'release/3.0' into develop 2023-07-27 17:51:51 +02:00
Lorenz Hilpert
75528d37d3 #4232 Preisanzeige bei Versanbestellung
(cherry picked from commit eddff0d93f)
2023-07-27 17:51:29 +02:00
Lorenz Hilpert
eddff0d93f #4232 Preisanzeige bei Versanbestellung 2023-07-27 17:50:09 +02:00
Lorenz Hilpert
f4579ef8dc #4229 Styling und Filter Anpoassung für Kundenbereich 2023-07-27 14:01:06 +02:00
Lorenz Hilpert
fc5496fda6 #4229 Fix ScrollPosition 2023-07-27 13:32:27 +02:00
Lorenz Hilpert
5cf6f4da38 Merged PR 1607: #4148 Suche nach Versandbestellung mit Order Id
#4148 Suche nach Versandbestellung mit Order Id
2023-07-26 15:32:18 +00:00
Lorenz Hilpert
60fde8b103 #4194 Artikel Format Icon wird falsch angezeigt 2023-07-26 17:20:32 +02:00
Lorenz Hilpert
734fe33f40 #4226 Am Ende der Trefferliste fehlt den Link zum Kundendaten erfassen 2023-07-26 16:54:25 +02:00
Nino Righi
64da928c36 Merged PR 1606: #4172 Kundensuche "Keine Suchergebnisse"
#4172 Kundensuche "Keine Suchergebnisse"
2023-07-26 14:29:41 +00:00
Nino
dba0b1b3c7 Customer Orders Breadcrumb Fix, Styling Fix Result List, Adjusted Position of Address Info correctly 2023-07-26 15:53:01 +02:00
Nino Righi
073746a9bc Merged PR 1605: #4220 Responsive Design Customer Orders Search History
#4220 Responsive Design Customer Orders Search History
2023-07-26 11:58:00 +00:00
Lorenz Hilpert
45c14e3b79 Toaster ueber console erstellen und schließen 2023-07-25 16:49:22 +02:00
Nino Righi
7023fe747b Merged PR 1604: #4219 RD Customer Orders Result List Display OrderNumber at item and BuyerNum...
#4219 RD Customer Orders Result List Display OrderNumber at item and BuyerNumber at customer name
2023-07-25 12:58:24 +00:00
Lorenz Hilpert
141c7fe1d6 #4221 Scanner - Adapter sind nicht bereit
(cherry picked from commit 78e76818b5)
(cherry picked from commit 44b406fad4)
2023-07-25 14:57:40 +02:00
Lorenz Hilpert
44b406fad4 #4221 Scanner - Adapter sind nicht bereit
(cherry picked from commit 78e76818b5)
2023-07-25 14:57:09 +02:00
Lorenz Hilpert
78e76818b5 #4221 Scanner - Adapter sind nicht bereit 2023-07-25 14:52:18 +02:00
Lorenz Hilpert
f78a773fab Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-07-25 14:19:07 +02:00
Nino Righi
60d007d9eb Merged PR 1603: #3394 #3395 #4218 Responsive Design Checkout Summary
#3394 #3395 #4218 Responsive Design Checkout Summary
2023-07-25 12:18:35 +00:00
Lorenz Hilpert
1ec253333e Close Button - Text gege Icon getsuscht 2023-07-25 14:18:18 +02:00
Nino Righi
bd332b6bd9 Merged PR 1602: #4215 #4137 Alle Filter Entfernen in Kundensuche eingebaut, Alle Filter entfernen entfernt die Query nicht mehr
#4215 #4137 Alle Filter Entfernen in Kundensuche eingebaut, Alle Filter entfernen entfernt die Query nicht mehr
2023-07-24 16:20:20 +00:00
Lorenz Hilpert
bc9bdbebe3 #3860 Toaster - Platzierung 2023-07-24 18:18:49 +02:00
Lorenz Hilpert
0b471cc5bc Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-07-24 11:26:55 +02:00
Lorenz Hilpert
c2eed61b83 #4213 Trefferlsite leer - scroll index fix 2023-07-24 11:26:41 +02:00
Lorenz Hilpert
2d403b4c56 Merge branch 'release/3.0' into develop 2023-07-24 01:13:27 +02:00
Lorenz Hilpert
b3e4ca90ee Merge branch 'release/2.3' into develop 2023-07-24 01:12:38 +02:00
Nino Righi
d4a3a4bc06 Merged PR 1601: #4141 Disable Filter Anwenden CTA if no filter is selected or no query available
#4141 Disable Filter Anwenden CTA if no filter is selected or no query available
2023-07-21 13:59:01 +00:00
Lorenz Hilpert
b674b5faf6 #4216 Header - Schriftgröße über Header anpassen 2023-07-21 15:40:45 +02:00
Lorenz Hilpert
8416028113 (cherry picked from commit edb21308d4) 2023-07-21 10:52:21 +02:00
Lorenz Hilpert
edb21308d4 #4194 Remission - Artikel Format Icon wird falsch angezeigt 2023-07-21 10:50:57 +02:00
Lorenz Hilpert
26ad0153d8 #4214 Trefferliste Kunden IPad 2023-07-21 10:26:42 +02:00
Nino Righi
e9b2acca5b Merged PR 1600: #4172 #4200 Artikelsuche und Kundenbestellungen Navigation Trefferliste und Anzeige Suchbox Hint
#4172 #4200 Artikelsuche und Kundenbestellungen Navigation Trefferliste und Anzeige Suchbox Hint
2023-07-21 08:15:57 +00:00
Nino Righi
4180ee61d6 Merged PR 1598: #3922 Kundenbestellungen Bugfixes, Filter angepasst, Breadcrumb bugfix
#3922 Kundenbestellungen Bugfixes, Filter angepasst, Breadcrumb bugfix
2023-07-21 07:40:03 +00:00
Lorenz Hilpert
a442a50708 Update Test 2023-07-20 15:59:52 +02:00
Lorenz Hilpert
59e650a1f1 #4201 Bearbeitung von Bestellung ohne Konto deaktiviert 2023-07-20 14:21:14 +02:00
Lorenz Hilpert
69b6470cda Revert "#4209 - FIX - KulturPass-Einlösecode lässt Abholfrist ändern"
This reverts commit 02d60e9bd5.
2023-07-20 13:57:31 +02:00
Lorenz Hilpert
44b33c1e4c Revert "#4209 - FIX - KulturPass-Einlösecode lässt Abholfrist ändern"
This reverts commit 02d60e9bd5.
2023-07-20 13:56:08 +02:00
Lorenz Hilpert
08f00c6578 Update CheckForUpdate interval - 15 min 2023-07-20 11:49:44 +02:00
Lorenz Hilpert
51c4066222 (cherry picked from commit 6fb72e4b2f) 2023-07-20 11:46:13 +02:00
Lorenz Hilpert
6fb72e4b2f #4121 Vormerker kann nicht manuell bearbeitet werden 2023-07-20 11:42:41 +02:00
Lorenz Hilpert
c9fbbd78a8 #4213 FIX - Kundensuche Trefferliste verschwindet nach Tab wechseln 2023-07-20 10:07:22 +02:00
Nino Righi
ce5388be61 Merged PR 1599: #4206 Checkout Cart display notification channels if buyer or payer is available
#4206 Checkout Cart display notification channels if buyer or payer is available
2023-07-19 16:59:52 +00:00
Lorenz Hilpert
02d60e9bd5 #4209 - FIX - KulturPass-Einlösecode lässt Abholfrist ändern
(cherry picked from commit fce50daff6)
2023-07-19 18:42:27 +02:00
Lorenz Hilpert
fce50daff6 #4209 - FIX - KulturPass-Einlösecode lässt Abholfrist ändern 2023-07-19 18:41:06 +02:00
Lorenz Hilpert
35b7f5700f #4211 Kaufoptionen popup - Prüfung ob Artikel mit Kunden kombinierbar ist
(cherry picked from commit ddd5d50c5d)
2023-07-19 17:46:52 +02:00
Lorenz Hilpert
b954947bb7 Merge branch 'release/2.3' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into release/2.3 2023-07-19 17:45:36 +02:00
Lorenz Hilpert
ddd5d50c5d #4211 Kaufoptionen popup - Prüfung ob Artikel mit Kunden kombinierbar ist 2023-07-19 17:45:17 +02:00
Lorenz Hilpert
efec7ecb26 #4210 Änderungen werden nicht sofort angezeigt 2023-07-19 17:25:22 +02:00
Lorenz Hilpert
ee81f795fe Removed Deprecated unit tests 2023-07-19 15:14:54 +02:00
Lorenz Hilpert
ad557ff919 #4193 Bestellpostensuche Seite nicht erreichbar 2023-07-19 15:06:00 +02:00
Lorenz Hilpert
bf5fae08b2 #4203 Scrollposition auf Kundentrefferliste wird nicht gespeichert 2023-07-19 14:36:18 +02:00
Lorenz Hilpert
88321928bf #4201 Bestellung ohne Konto können Kundendaten nicht bearbeiten 2023-07-19 11:33:13 +02:00
Lorenz Hilpert
a7d50a9439 #4196 Rechnungs- und Lieferadresse ändern bei eine Bestellung für Versand führt zu Dashboard Seite 2023-07-18 16:35:27 +02:00
Lorenz Hilpert
4c6dcd15da #4198 In Kundenkarten Konto Formular der Text geht über den Rand hinaus 2023-07-18 16:27:42 +02:00
Lorenz Hilpert
84f9d14be0 #4199 Warnmeldung bei Geburtsdatumeingabe 2023-07-18 15:25:05 +02:00
Lorenz Hilpert
e2f173f250 #4201 Kunden Detail Seite des Onlinekontos - nicht bearbeitbar 2023-07-18 14:33:22 +02:00
Lorenz Hilpert
fdd9617604 #4202 Kundendetails Bearbeiten Seite von Business Konto 2023-07-18 14:25:49 +02:00
Lorenz Hilpert
bc3cedfe50 #4204 Ladekreis in Kundensuche Suchfeld verschwindet nicht 2023-07-18 14:09:04 +02:00
Lorenz Hilpert
78f9093931 Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-07-18 13:22:59 +02:00
Lorenz Hilpert
a889c768d1 #3761 Bestellposten Design 2023-07-18 13:22:22 +02:00
Nino Righi
e36319a73e Merged PR 1596: #4179 Fix Process Bar Scroll to Active Process
#4179 Fix Process Bar Scroll to Active Process
2023-07-18 11:14:59 +00:00
Nino Righi
199ae95bcd Merged PR 1597: #4186 Fix Price Update and Article Search Result List selected Select Bullet...
#4186 Fix Price Update and Article Search Result List selected Select Bullet handling improved
2023-07-18 08:22:05 +00:00
Lorenz Hilpert
30875f0491 #4195 Anzeige der Hauptseite der Kundensuche angepasst - IPad 2023-07-17 15:16:44 +02:00
Lorenz Hilpert
95d9d17aa7 Merge branch 'release/2.3' into develop 2023-07-17 01:31:46 +02:00
Lorenz Hilpert
215d7ca341 Benachrichtigung für Packstückprüfung einblenden 2023-07-17 01:31:17 +02:00
Lorenz Hilpert
1255df10e0 Benachrichtigungen für Packstückprüfung ausblenden 2023-07-17 01:30:40 +02:00
Nino Righi
4c641adeda Merged PR 1595: #4189 Dont Display Customer Name if Shipping Address is Available
#4189 Dont Display Customer Name if Shipping Address is Available
2023-07-14 15:17:51 +00:00
Lorenz Hilpert
4bd4158dab select inputs können gecleart werden 2023-07-14 17:14:44 +02:00
Nino
4965976f6c Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-07-14 16:59:36 +02:00
Nino
b43f512887 Responsive Design Container Height, Splitscreen Tailwind changes to Page Catalog, Customer-Orders, Checkout - Small Styling bugfixes 2023-07-14 16:59:15 +02:00
Lorenz Hilpert
e6f2b46fce Navigation nach Kundenanlage 2023-07-14 16:30:18 +02:00
Lorenz Hilpert
01c84b361a Kundenbereich Div Size 2023-07-14 15:47:19 +02:00
Lorenz Hilpert
ac35cc237e Leere Notifications nicht anzeigen 2023-07-14 14:50:08 +02:00
Lorenz Hilpert
28ad07b372 Filter Searchbox - Tablet - Desktop 2023-07-14 14:42:39 +02:00
Lorenz Hilpert
6ade77d458 Tailwindcss anpassung splitscreen werte 2023-07-14 14:41:18 +02:00
Lorenz Hilpert
4187e13861 Merge branch 'release/2.3' into develop 2023-07-14 13:25:05 +02:00
Lorenz Hilpert
4fe5034e1c #3666 Design Anpassung 2023-07-14 13:12:48 +02:00
Lorenz Hilpert
729451fa48 Kundennavigation angepasst 2023-07-14 12:19:03 +02:00
Lorenz Hilpert
d77fe8c540 Kundenbereich Nachname Vorname 2023-07-14 12:05:21 +02:00
Lorenz Hilpert
a257ddd8e0 Dev Scanner Entfernt 2023-07-14 11:14:19 +02:00
Lorenz Hilpert
90154bd497 desktop_ zu desktop-large_ geändert, searchprovider für kundensuche angepasst 2023-07-14 10:54:57 +02:00
Lorenz Hilpert
f96224569f Autocomplete Provider für Kundensuche 2023-07-14 03:51:31 +02:00
Lorenz Hilpert
1c695104f9 click event auf Weiter zum Warenkorb 2023-07-14 03:40:47 +02:00
Lorenz Hilpert
ab9a35dd89 Merge branch 'feature/rd-customer' into develop 2023-07-14 03:27:46 +02:00
Lorenz Hilpert
6daa96119d Filter Buttons und Navigation 2023-07-14 03:27:17 +02:00
Lorenz Hilpert
128a280dee Constants and Icon Update 2023-07-14 03:03:45 +02:00
Lorenz Hilpert
475c885344 Kundenlabels und Icons 2023-07-14 01:00:00 +02:00
Lorenz Hilpert
ee62649bf6 Positonierung Button in Details ansicht und Suche Optimiert 2023-07-14 00:29:32 +02:00
Lorenz Hilpert
109999d66f Performance und caching in Kundensuche angepasst 2023-07-13 23:32:50 +02:00
Lorenz Hilpert
9ec34b07c4 Ladeanimation beim laden der Bestellungen 2023-07-13 22:59:29 +02:00
Lorenz Hilpert
2fd2d701dd Merge branch 'feature/rd-customer' into develop 2023-07-13 19:09:53 +02:00
Lorenz Hilpert
5574252b5b Merge branch 'develop' into release/3.0 2023-07-13 19:09:05 +02:00
Lorenz Hilpert
5e79d4dc52 Merge branch 'release/3.0' into develop 2023-07-13 19:08:47 +02:00
Nino Righi
bb91782079 Merged PR 1594: #4176 Fix Order Deadline inside Purchasing Options
#4176 Fix Order Deadline inside Purchasing Options
2023-07-13 17:07:20 +00:00
Nino Righi
2bbcb15740 Merged PR 1593: #4189 Warenkorb Anzeige Änderungen
#4189 Warenkorb Anzeige Änderungen
2023-07-13 17:06:59 +00:00
Lorenz Hilpert
216d302a86 Zuweisung Kunden zum Warenkorb 2023-07-13 19:06:28 +02:00
Nino Righi
e18b9a4200 Merged PR 1592: #3730 Article Search Results Order By Adjustments
#3730 Article Search Results Order By Adjustments
2023-07-13 15:23:42 +00:00
Nino Righi
310395d166 Merged PR 1591: #4184 Fix Article Search Results Remember Scroll Position Correctly
#4184 Fix Article Search Results Remember Scroll Position Correctly
2023-07-13 15:23:24 +00:00
Nino Righi
651f44914f Merged PR 1590: #4187 RD Cart Delivery Address and Wording Change
#4187 RD Cart Delivery Address and Wording Change
2023-07-13 14:55:41 +00:00
Lorenz Hilpert
4a97800a05 Update Navigation p4m 2023-07-13 13:47:11 +02:00
Lorenz Hilpert
f2e124903c Merge branch 'release/2.3' into develop 2023-07-13 12:08:38 +02:00
Nino Righi
eec1cb5666 Merged PR 1589: #4180 Hotfix Mehrfachauswahl Für Download Artikel direkt Logistician setzen
#4180 Hotfix Mehrfachauswahl Für Download Artikel direkt Logistician setzen
2023-07-13 08:05:16 +00:00
Nino Righi
cb7334d63b Merged PR 1588: #4140 Fix Article Search Results Set Default Max Buffer Size for Scrollcontainer
#4140 Fix Article Search Results Set Default Max Buffer Size for Scrollcontainer
2023-07-13 08:03:59 +00:00
Lorenz Hilpert
b62e6e8e35 #3666 Benachrichtigung über die Glocke 2023-07-12 17:57:31 +02:00
Lorenz Hilpert
f98aac5231 Navigations Kundenbereich RD 2023-07-12 15:05:42 +02:00
Lorenz Hilpert
9c4e94ce8d Kundenkarte Customer RD 2023-07-11 21:13:51 +02:00
Lorenz Hilpert
65a19feffc Merge branch 'develop' into feature/rd-customer 2023-07-11 19:32:21 +02:00
Nino Righi
62a1be7abe Merged PR 1587: #4177 RD Purchasing Order Modal Fix Guest Customer without Account cannot ord...
#4177 RD Purchasing Order Modal Fix Guest Customer without Account cannot order via delivery option
2023-07-11 16:54:22 +00:00
Nino Righi
ad4481cfc7 Merged PR 1586: #4183 RD Cart Fix display of data from previous order
#4183 RD Cart Fix display of data from previous order
2023-07-11 16:53:53 +00:00
Nino Righi
e4c20b953d Merged PR 1585: #4169 #4170 #4140 #4182 Artikelsuche - Routing Navigation and Scrolling Bugfixes
#4169 #4170 #4140 #4182 Artikelsuche - Routing Navigation and Scrolling Bugfixes
2023-07-11 16:52:11 +00:00
Lorenz Hilpert
e8044fae1b Kundenbestellungen Seite 2023-07-11 18:50:26 +02:00
Nino Righi
b845147050 Merged PR 1584: #4180 Hotfix Add Logistician to Download Destination
#4180 Hotfix Add Logistician to Download Destination
2023-07-11 11:45:10 +00:00
Nino Righi
c4818319aa Merged PR 1580: #4174 Fix Goods Out and Customer Orders Caching and display items based on pr...
#4174 Fix Goods Out and Customer Orders Caching and display items based on process correctly
2023-07-11 11:14:23 +00:00
Michael Auer
6bc265a358 Merge branch 'release/2.3' 2023-07-11 12:20:14 +02:00
Nino Righi
8cb25d6ca1 Merged PR 1581: #4176 Order Deadline Responsive Design
#4176 Order Deadline Responsive Design
2023-07-11 08:05:44 +00:00
Nino Righi
5a14e0afbd Merged PR 1582: #4178 Changed search history results from 5 to 7 and made container scrollable
#4178 Changed search history results from 5 to 7 and made container scrollable
2023-07-11 08:03:48 +00:00
Nino Righi
0804eeeccb Merged PR 1583: #4175 Warenkorb Notification und Navigation bugfix
#4175 Warenkorb Notification und Navigation bugfix
2023-07-11 08:03:12 +00:00
Lorenz Hilpert
f015169011 Paging Kundensuche 2023-07-10 13:33:43 +02:00
Lorenz Hilpert
201ea2ee9c ANlage und bearbeiten von Adressen 2023-07-10 11:42:28 +02:00
Nino Righi
961211e638 Merged PR 1579: #4171 RD Added Fallbacks to Navigation Services if all arguments are undefined
#4171 RD Added Fallbacks to Navigation Services if all arguments are undefined
2023-07-10 09:04:51 +00:00
Nino Righi
22a494e31e Merged PR 1578: #4162 RD Customer Orders Edit Styling Fixes
#4162 RD Customer Orders Edit Styling Fixes
2023-07-10 09:01:59 +00:00
Nino Righi
75e24771b3 Merged PR 1577: #4168 Fix PDP Recommendations Routing
#4168 Fix PDP Recommendations Routing
2023-07-07 14:07:39 +00:00
Lorenz Hilpert
97b30d5b14 Merge branch 'release/2.3' into develop 2023-07-06 17:14:00 +02:00
Lorenz Hilpert
ca5dbb9d6f Merge branch 'develop' into release/3.0 2023-07-06 16:58:04 +02:00
Nino Righi
e065c1a8da Merged PR 1576: #4095 #4159 Responsive Design PDP Styling fix and implemented Page Scrolling
#4095 #4159 Responsive Design PDP Styling fix and implemented Page Scrolling
2023-07-06 14:57:09 +00:00
Nino Righi
fc76f34d38 Merged PR 1575: #3399 #3398 #3397 Responsive Design Checkout Cart Review
#3399 #3398 #3397 Responsive Design Checkout Cart Review
2023-07-06 14:53:39 +00:00
Nino Righi
98e963d782 Merged PR 1574: #4160 Hotfix Preselect InStore PurchasingOption Tile
#4160 Hotfix Preselect InStore PurchasingOption Tile
2023-07-06 14:34:42 +00:00
Lorenz Hilpert
27e5afacde Merge branch 'develop' into release/3.0 2023-07-06 16:33:14 +02:00
Lorenz Hilpert
8a4fe7aedd Merge branch 'release/2.3' into develop 2023-07-06 16:32:12 +02:00
Lorenz Hilpert
90268b4ec1 #4165 console log entfernt 2023-07-06 16:30:32 +02:00
Lorenz Hilpert
034693df98 #4165 Performance Fix 2023-07-06 16:30:02 +02:00
Lorenz Hilpert
5b31661f8d Fix Kulturpass in der Warenaugabe und Eingang - Datum nicht bearbeitbar 2023-07-06 13:47:30 +02:00
Lorenz Hilpert
ba01807add Merge branch 'develop' into release/3.0 2023-07-05 22:06:55 +02:00
Lorenz Hilpert
3b89777648 Merge branch 'release/2.3' into develop 2023-07-05 22:05:51 +02:00
Lorenz Hilpert
bb510788eb Merge branch 'develop' into release/3.0 2023-07-05 17:44:32 +02:00
Lorenz Hilpert
d48b59b374 Scandit Lizenz 2023-07-05 13:12:04 +02:00
Lorenz Hilpert
7d72fc56db Remission Routing fix 2023-07-04 19:04:24 +02:00
Lorenz Hilpert
90edb7dd7e Scanner Fix 2023-07-04 18:28:57 +02:00
Lorenz Hilpert
7ee0c4d145 #4164 Wannennummer scannen beim Öffnen eines WBS ohne Wannenummer 2023-07-04 17:15:38 +02:00
Lorenz Hilpert
67f2ff54be #4163 WBS abschließen ohne Wannennummer möglich 2023-07-04 15:51:26 +02:00
Nino Righi
1b85c8ff50 Merged PR 1572: #4143 Fix Page Product Search, Page Customer Orders, combine Filter and Searc...
#4143 Fix Page Product Search, Page Customer Orders, combine Filter and Searchquery in Splitscreen #4155 Fix Autocomplete inside Customer Orders
2023-07-04 08:07:36 +00:00
Lorenz Hilpert
f0470d3faa #4161 Artikel ohne Bestand sollen nicht mit dem Wertcode einlösbar sein 2023-07-03 16:53:22 +02:00
Nino Righi
4d5e81a638 Merged PR 1571: #4142 Fix Open Filter after Clearing Query navigates to filter page properly...
#4142 Fix Open Filter after Clearing Query navigates to filter page properly and does not trigger a search. Searchbox stays clear
2023-07-03 09:01:25 +00:00
Nino Righi
7676ae8143 Merged PR 1573: #4158 RD Customer Orders Details Select Bullet Fixed, Styling Adjusted
#4158 RD Customer Orders Details Select Bullet Fixed, Styling Adjusted
2023-07-03 08:52:58 +00:00
Lorenz Hilpert
fb97db99b0 #4151 Aktivierung Packstückprüfung 2023-07-02 11:18:17 +02:00
Lorenz Hilpert
92aad95603 #4157 Warnungstext auf Artikelebene überlappt Menge 2023-06-29 15:52:39 +02:00
Lorenz Hilpert
513cef2a66 #4153 EAN ISBN soll bleiben wenn Artikel nicht gefunden wurde 2023-06-29 15:49:21 +02:00
Lorenz Hilpert
bdf3bbc530 #4153 Artikel können hinzugefügt werden auch ohne Bestand 2023-06-29 14:14:20 +02:00
Nino Righi
9a17f95026 Merged PR 1570: #4135 #4144 Responsive Design Product Search Result List Select Bullet Logic...
#4135 #4144 Responsive Design Product Search Result List Select Bullet Logic updated
2023-06-28 16:10:01 +00:00
Nino Righi
e6b44d8365 Merged PR 1569: #4139 Fix RD Shared Searchbox Close Autocomplete if Search triggered
#4139 Fix RD Shared Searchbox Close Autocomplete if Search triggered
2023-06-28 16:07:49 +00:00
Nino Righi
874f8f4758 Merged PR 1568: #3996 Customer Order Details and History
#3996 Customer Order Details and History
2023-06-28 16:03:23 +00:00
Lorenz Hilpert
47baf2fa89 Kulturpass - Mehrfache Artikelauswahl über EAN überschreitet verfügbare Exemplare 2023-06-28 17:06:55 +02:00
Lorenz Hilpert
57bfc523ab Kulturpass - Early Exit wenn Dialog geschlossen wird 2023-06-28 14:07:28 +02:00
Lorenz Hilpert
23edea5fa4 Merge branch 'feature/kulturpass' into release/2.3 2023-06-28 13:34:38 +02:00
Lorenz Hilpert
7b12857a35 Mark Result Item as active if customer is selected 2023-06-28 13:21:28 +02:00
Lorenz Hilpert
d6d919ed52 Kundensuche Caching 2023-06-27 17:13:50 +02:00
Lorenz Hilpert
330c59f7e9 #4134 Einlösecode- Warenkorb Pop Up 2023-06-27 15:03:07 +02:00
Lorenz Hilpert
600687f652 Version Set To Major 3 Minor 0 2023-06-27 11:01:12 +02:00
Lorenz Hilpert
0c65e9dace #4133 vsl. Lieferdatum und Zurücklegen bis deaktiviert 2023-06-26 13:58:58 +02:00
Lorenz Hilpert
ed144f0a15 Unit Test Fix 2023-06-26 13:30:18 +02:00
Lorenz Hilpert
c0c2cc86d3 Merge branch 'release/2.3' into develop 2023-06-26 13:17:52 +02:00
Lorenz Hilpert
9b8ea11866 Kulturpass - loader anzeige 2023-06-23 17:32:49 +02:00
Lorenz Hilpert
17aed38316 Kulturpass Scanner Fix 2023-06-23 16:57:35 +02:00
Lorenz Hilpert
48a7cc4dd4 Kulturpass - Shoppingcart erstellung vor dem start und checkout beim bestellen 2023-06-23 16:51:50 +02:00
Lorenz Hilpert
4417fd9f0d Kulturpass Mengenänderung Verfügbarkeit Check 2023-06-23 15:30:41 +02:00
Lorenz Hilpert
3e429cb261 Kulturpass Hinweistexte 2023-06-23 12:12:47 +02:00
Lorenz Hilpert
48e30e795f Kulturpass - Hinweis leerer Warenkorb 2023-06-23 11:47:27 +02:00
Lorenz Hilpert
953e528298 Kulturpass Warenkorb Mengenänderung und Entfernen 2023-06-23 11:36:38 +02:00
Lorenz Hilpert
4276f427b9 Kulturpass Warenkorb #4133 #4134 2023-06-23 10:39:19 +02:00
Nino Righi
4b2bfefc9b Merged PR 1567: #3993 #3994 #3995 #3996 Kundenbestellungen Splitscreen, erste Version
#3993 #3994 #3995 #3996 Kundenbestellungen Splitscreen, erste Version
2023-06-20 11:08:15 +00:00
Lorenz Hilpert
11e79c4830 Customer Edit Pages 2023-06-16 13:29:34 +02:00
Lorenz Hilpert
264d914044 #4124 Kulturpass- Abholfrist auf Bearbeitenseite 2023-06-15 16:28:44 +02:00
Lorenz Hilpert
12f1e7c3af #4124 Kulturpass - Zurücklegen bis und Abholfrist nicht ausgrauen 2023-06-15 14:33:41 +02:00
Lorenz Hilpert
9eb4fbab65 Merge branch 'release/2.3' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into release/2.3 2023-06-15 13:52:19 +02:00
Lorenz Hilpert
8d1a63e47f #4120 Marker Bezahlt über KulturPass in der Ergebnisliste 2023-06-15 13:51:57 +02:00
Nino Righi
e449e612c1 Merged PR 1566: #4112 Hotfix Manueller Preis Archivartikel
#4112 Hotfix Manueller Preis Archivartikel
2023-06-15 11:43:09 +00:00
Lorenz Hilpert
6ba65f031b #4119 Kaufoptionen - Nicht verfügbare Kaufoptionen werden ausgegraut 2023-06-15 11:56:05 +02:00
Lorenz Hilpert
f31ac4c2e3 #4117 Bug Fix Collect On Delivery 2023-06-15 11:01:39 +02:00
Lorenz Hilpert
f980f5aaf9 #4113 Wareneingang Navigation entfernt 2023-06-14 17:53:29 +02:00
Nino Righi
45989d7abd Merged PR 1565: #4077 Responsive Design Display Cart-Checkout Process Tab Correctly
#4077 Responsive Design Display Cart-Checkout Process Tab Correctly
2023-06-14 14:31:47 +00:00
Lorenz Hilpert
87a1e8a2c4 Kulturpass Handler Fix COLLECT_WITH_SMALLAMOUNTINVOICE 2023-06-14 16:30:19 +02:00
Lorenz Hilpert
ae27da1127 Styling anpassung 2023-06-14 15:14:48 +02:00
Lorenz Hilpert
ca21931d93 Customer Create Forms 2023-06-14 15:04:15 +02:00
Lorenz Hilpert
5bb9ebd6ec #3961 Bestelldeadline anzeigen 2023-06-14 10:27:20 +02:00
Lorenz Hilpert
45ab1e9cc5 Kulturpass Drucken Fix 2023-06-13 17:51:33 +02:00
Lorenz Hilpert
8d2685a8c3 Fix Kulturpass Anzeige 2023-06-13 17:34:27 +02:00
Lorenz Hilpert
d38c41a99d Kulturpass - Fix - erneut drucken 2023-06-13 16:08:42 +02:00
Lorenz Hilpert
ff3dacde39 #4101 Kulturpass 2023-06-13 15:25:08 +02:00
Lorenz Hilpert
5c9f4c5b21 Merged PR 1564: Customer RD 2023-06-13 11:45:47 +00:00
Lorenz Hilpert
c134f645ef Merge branch 'develop' into feature/rd-customer 2023-06-13 13:45:00 +02:00
Lorenz Hilpert
6f0933a350 Fix Unit Tests 2023-06-13 13:25:37 +02:00
Nino Righi
c9a90211ee Merged PR 1563: #4099 RD Fix Disable Chrome Autocomplete prompt
#4099 RD Fix Disable Chrome Autocomplete prompt
2023-06-13 08:06:15 +00:00
Nino Righi
95d96dd295 Merged PR 1562: #4097 Fix Goods In Out Details CTA layout
#4097 Fix Goods In Out Details CTA layout
2023-06-13 08:05:37 +00:00
Nino Righi
86bf079f6f Merged PR 1561: #4098 Fix RD Article Search Results closing all Processes dont navigate to old result breadcrumb anymore
#4098 Fix RD Article Search Results closing all Processes dont navigate to old result breadcrumb anymore
2023-06-13 08:05:18 +00:00
Lorenz Hilpert
c202490555 Kundentyp-Auswahl 2023-06-12 17:04:19 +02:00
Lorenz Hilpert
da0100dd35 Icon lib moved to shared 2023-06-12 16:12:28 +02:00
Lorenz Hilpert
b634247463 Merge branch 'develop' into feature/rd-customer 2023-06-12 10:48:56 +02:00
Lorenz Hilpert
84df6493f6 Side View 2023-06-12 10:46:37 +02:00
Nino Righi
90b752e185 Merged PR 1558: #4092 Fix updateNotificationsGroup get orderId from first Item not from initi...
#4092 Fix updateNotificationsGroup get orderId from first Item not from initial form
2023-06-09 12:52:28 +00:00
Nino Righi
d3858c731c Merged PR 1559: #4092 Fix updateNotificationsGroup get orderId from first Item not from initi...
#4092 Fix updateNotificationsGroup get orderId from first Item not from initial form
2023-06-09 12:52:19 +00:00
Nino Righi
f247ac641c Merged PR 1560: #4082 Sidenav Arrow Navigation Fix
#4082 Sidenav Arrow Navigation Fix
2023-06-09 12:45:45 +00:00
Nino Righi
be1a9e8f7e Merged PR 1556: #4067 RD Artikelsuche Ergebnisliste Performance und Scrollposition Update
#4067 RD Artikelsuche Ergebnisliste Performance und Scrollposition Update
2023-06-09 09:11:10 +00:00
Nino Righi
d86f595b1f Merged PR 1555: #4074 Implemented Changes from ISA-Integration to ISA-Test
#4074 Implemented Changes from ISA-Integration to ISA-Test
2023-06-07 13:30:14 +00:00
Nino Righi
3ed9227508 Merged PR 1553: #4074 Bugfixes
#4074 Bugfixes
2023-06-06 16:12:56 +00:00
Nino Righi
74bf2133c6 Merged PR 1554: #4078 Fix Searchbox Clear
#4078 Fix Searchbox Clear
2023-06-06 16:07:58 +00:00
Nino Righi
e4570946c4 Merged PR 1551: #4088 Responsive Design Fixed Width of Filter Overlays
#4088 Responsive Design Fixed Width of Filter Overlays
2023-06-06 15:33:02 +00:00
Andreas Schickinger
a8213d79fd Merged PR 1552: #4087 Warenausgabe/Abholfach - Label Breite angepasst
#4087 Warenausgabe/Abholfach - Label Breite angepasst

Related work items: #4087
2023-06-06 15:23:46 +00:00
Nino Righi
13ec323ac4 Merged PR 1550: #4083 Develop Goods In Out Order Edit Bestellkanal orderSource from Order not...
#4083 Develop Goods In Out Order Edit Bestellkanal orderSource from Order not from first item
2023-06-06 14:58:02 +00:00
Nino Righi
9cfe8176d4 Merged PR 1548: #4083 Goods In Out Order Edit Bestellkanal orderSource from Order not from fi...
#4083 Goods In Out Order Edit Bestellkanal orderSource from Order not from first item
2023-06-06 14:53:47 +00:00
Andreas Schickinger
c544cebba9 Merged PR 1549: #4082 Navi Dropdown Pfeil
#4082 Navi Dropdown Pfeil

Related work items: #4082
2023-06-06 14:52:54 +00:00
Andreas Schickinger
74dffe8af2 Merged PR 1547: #4081 Vorgangsleiste scrollen
#4081 Vorgangsleiste scrollen

Related work items: #4081
2023-06-06 14:46:57 +00:00
Nino Righi
3999b8f623 Merged PR 1544: #4074 Kaufoptionen Manuelle Preiseingabe
#4074 Kaufoptionen Manuelle Preiseingabe
2023-06-06 13:28:57 +00:00
Nino Righi
9d3bb9dcf3 Merged PR 1546: #4080 Responsive Design Article Search Filter Navigation
#4080 Responsive Design Article Search Filter Navigation
2023-06-06 09:39:53 +00:00
Nino Righi
05e58aa060 Merged PR 1545: #4076 RD Navigation Wording Change based on Email Johanna
#4076 RD Navigation Wording Change based on Email Johanna
2023-06-05 15:01:32 +00:00
Andreas Schickinger
f74d14d573 Merged PR 1542: #4075 TK zum Kalender Button Breite angepasst
#4075 TK zum Kalender Button Breite angepasst

Related work items: #4075
2023-06-05 14:25:29 +00:00
Andreas Schickinger
741e651a20 Merged PR 1543: #4079 Kaufoptionen Popup Text überlappt
#4079 Kaufoptionen Popup Text überlappt

Related work items: #4079
2023-06-05 14:24:49 +00:00
Andreas Schickinger
4e1bd89378 Merged PR 1541: #4073 Fix PP Filter wird zurückgesetzt, wenn nicht vollständig geladen
#4073 Fix PP Filter wird zurückgesetzt, wenn nicht vollständig geladen

Related work items: #4073
2023-06-02 14:35:06 +00:00
Andreas Schickinger
c8f54b8be5 Merged PR 1540: #4073 Hotfix PP Filter wird zurückgesetzt, wenn nicht vollständig geladen
#4073 Hotfix PP Filter wird zurückgesetzt, wenn nicht vollständig geladen

Related work items: #4073
2023-06-02 14:34:52 +00:00
Nino Righi
413d2f5178 Merged PR 1539: #4048 Changed clientChannel to orderSource
#4048 Changed clientChannel to orderSource
2023-06-02 11:48:23 +00:00
Andreas Schickinger
503f44891f Merged PR 1538: #4050 Fix Kaufoptionen Popup - Weiterleiten zur Kundensuche
#4050 Weiterleiten zur Kundensuche fix

Related work items: #4050
2023-06-02 11:24:02 +00:00
Andreas Schickinger
35c2a6a046 Merged PR 1537: #4050 Hotfix Kaufoptionen Popup - Weiterleiten zur Kundensuche
#4050 Hotfix Kaufoptionen Popup - Weiterleiten zur Kundensuche

Related work items: #4050
2023-06-02 11:23:21 +00:00
Andreas Schickinger
5bf326f680 Merged PR 1535: #4068 Fix Develop Warenkorb Rücklage Menge ändern
Related work items: #4068
2023-06-01 15:42:32 +00:00
Andreas Schickinger
1df201525c Merged PR 1536: #4068 Hotfix Warenkorb Rücklage Menge ändern
#4068 Warenkorb Rücklage Menge ändern hotfix
2023-06-01 15:42:19 +00:00
Lorenz Hilpert
e7793b15e3 Bugfix Shell und UiSvgIcon 2023-05-31 16:36:18 +02:00
Lorenz Hilpert
d2e16ca256 Update Navigation behaviour for Filial-Navigation 2023-05-31 15:58:19 +02:00
Nino Righi
31164befc9 Merged PR 1534: #4066 Responsive Design Article Search Filter Scroll Arrow Clickable and adju...
#4066 Responsive Design Article Search Filter Scroll Arrow Clickable and adjusted Styling
2023-05-31 13:35:34 +00:00
Nino Righi
8f4dfa0674 Merged PR 1533: #4065 Responsive Design Result List Correctly Render Items
#4065 Responsive Design Result List Correctly Render Items
2023-05-31 13:35:23 +00:00
Nino Righi
eb7a01907a Merged PR 1532: #4064 Responsive Design Article Result List new Grid Layout
#4064 Responsive Design Article Result List new Grid Layout
2023-05-31 13:32:48 +00:00
Nino Righi
fb1fd1ec7c Merged PR 1531: #4063 Fix Splitscreen Correctly Remove Details Breadcrumb inside Search Resul...
#4063 Fix Splitscreen Correctly Remove Details Breadcrumb inside Search Results Component
2023-05-31 13:29:27 +00:00
Nino Righi
7528c7df63 Merged PR 1530: #4062 Responsive Design Artikelsuche Filter Closing and Routing updated
#4062 Responsive Design Artikelsuche Filter Closing and Routing updated
2023-05-31 13:29:11 +00:00
Lorenz Hilpert
e6ca19ab91 Update Customer Header and Navigation 2023-05-31 13:44:59 +02:00
Lorenz Hilpert
dc3e097dfd Unit Test Anpassungen 2023-05-30 11:17:29 +02:00
Lorenz Hilpert
a5e8c06dda Update Funktionalität alle Processe Schließen 2023-05-30 11:06:30 +02:00
Lorenz Hilpert
bf7fd13ef2 Unit Test Fix 2023-05-26 18:06:35 +02:00
Lorenz Hilpert
a424e015b4 Prozess Tab font Anpassung 2023-05-26 17:17:32 +02:00
Lorenz Hilpert
c67fef64fe Styling anpassung prozess item 2023-05-26 17:15:26 +02:00
Lorenz Hilpert
12055de1fc Added Dashboard Icon 2023-05-26 16:11:54 +02:00
Lorenz Hilpert
a2ad2f8c0b Shell Prozess Tab 2023-05-26 16:01:42 +02:00
Lorenz Hilpert
af7cebda66 Unit Test Fix 2023-05-26 11:23:50 +02:00
Lorenz Hilpert
2230cf2e7b Header Anpassungen 2023-05-26 11:15:59 +02:00
Lorenz Hilpert
aa048e8d22 Added missing Icons 2023-05-25 16:36:45 +02:00
Lorenz Hilpert
4961fb9756 Fix Unit Sests ShellSideMenuComponent 2023-05-25 16:12:08 +02:00
Lorenz Hilpert
6801e3858a #3007 Side Navigation 2023-05-25 16:02:05 +02:00
Lorenz Hilpert
ef72dcf554 #3984 - Filtereinstellungen wenn Artikel für Dig-Versand in Warenkorb sind falsch
(cherry picked from commit 6717f0ee3d)
2023-05-25 10:54:08 +02:00
Michael Auer
c228147c00 Merged PR 1529: Floating Docker Branch-Tags
Es wird zusätzlich zu den bisherigen Docker-Tags, ein Docker-Tag vergeben, das den aktuellen Branch repräsentiert. Da dieses (identische) Tag für jeden neuen Build aus einem Branch wieder vergeben wird, wandert das Tag auf das neueste Docker-Image aus diesem Branch (vgl. Tag _latest_)

Beispiele:
develop => refs_head_develop
release/2.3 => refs_head_release_2.3

(cherry picked from commit 8880ed0df6)
2023-05-24 18:37:47 +02:00
Nino Righi
266358f0cc Merged PR 1528: Responsive Design Article Search
Responsive Design Article Search
2023-05-24 16:33:56 +00:00
Lorenz Hilpert
6717f0ee3d #3984 - Filtereinstellungen wenn Artikel für Dig-Versand in Warenkorb sind falsch 2023-05-24 18:21:30 +02:00
Michael Auer
8880ed0df6 Merged PR 1529: Floating Docker Branch-Tags
Es wird zusätzlich zu den bisherigen Docker-Tags, ein Docker-Tag vergeben, das den aktuellen Branch repräsentiert. Da dieses (identische) Tag für jeden neuen Build aus einem Branch wieder vergeben wird, wandert das Tag auf das neueste Docker-Image aus diesem Branch (vgl. Tag _latest_)

Beispiele:
develop => refs_head_develop
release/2.3 => refs_head_release_2.3
2023-05-24 16:12:28 +00:00
Lorenz Hilpert
4b56b973c8 #3979 SSC Nummer Anzeigen 2023-05-24 17:53:54 +02:00
Lorenz Hilpert
28a00b9f22 Merge branch 'release/2.3' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into release/2.3 2023-05-24 17:38:57 +02:00
Nino Righi
b1fe692de5 Merged PR 1527: #4009 Filter reset and Branch Selector Dropdown Bugfixes
#4009 Filter reset and Branch Selector Dropdown Bugfixes
2023-05-23 11:55:14 +00:00
Lorenz Hilpert
08b2f6cbc9 removed console log 2023-05-23 13:32:28 +02:00
Lorenz Hilpert
10e1db388f #3979 Meldenummer in UI anzeigen 2023-05-23 13:32:05 +02:00
Lorenz Hilpert
cd7f71b968 #4044 Handlungsanweisung im Status fehlt 2023-05-22 16:13:57 +02:00
Lorenz Hilpert
395fd544e5 #4048 Bestellkanal - Umstellung auf orderSource 2023-05-22 15:44:06 +02:00
Lorenz Hilpert
2c10d6bf10 Kundenbestellung navigation Fix 2023-05-22 14:07:45 +02:00
Lorenz Hilpert
9361a631dd Merge branch 'release/2.3' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into release/2.3 2023-05-22 10:46:34 +02:00
Lorenz Hilpert
59c5abfd93 Deadline Pipe Fix 2023-05-22 10:46:10 +02:00
Nino Righi
633c23a6f0 Merged PR 1526: #4009 Clear Filter Release
#4009 Clear Filter Release
2023-05-18 22:27:32 +00:00
Lorenz Hilpert
779e7323e2 #3965 HSC ISA - Kundenkarten anlegen raus 2023-05-17 15:51:35 +02:00
Lorenz Hilpert
6e7fbd940b #3961 Order Deadline Popup 2023-05-17 14:56:25 +02:00
Lorenz Hilpert
6878b608fc #4035 branch slector fix 2023-05-17 13:23:43 +02:00
Lorenz Hilpert
a4fab8b64e #4035 Filiale wird bei Reservierung setzen 2023-05-16 15:32:38 +02:00
Lorenz Hilpert
21c0cc8794 #4039 - Irrläufer verschwinden nicht von der Liste 2023-05-16 13:30:51 +02:00
Lorenz Hilpert
7ea11ea0c4 #4039 Neu laden der Liste wenn man im Popup auf erledigt klickt 2023-05-12 16:19:21 +02:00
Lorenz Hilpert
d2c307b08a Updated Breadcrumb for Kundensuche 2023-05-12 13:10:00 +02:00
Lorenz Hilpert
4dc98f7980 Shell Styling 2023-05-11 16:42:37 +02:00
Lorenz Hilpert
c89ee18db3 Update env service added matcher for screen sizes 2023-05-11 16:10:05 +02:00
Lorenz Hilpert
c4aa7999a6 Shell auf max breite 1440px und zentriert 2023-05-11 15:41:09 +02:00
Lorenz Hilpert
778343f636 #4036 Bugfix scaling von texten 2023-05-09 13:03:02 +02:00
Lorenz Hilpert
d2fb3b6c85 #4036 - Kaufoptionen 2023-05-09 10:33:21 +02:00
Lorenz Hilpert
a8bfedcd5d Added Create Customer Components 2023-05-08 15:38:31 +02:00
Lorenz Hilpert
4c7b5eec38 #4016 Kaufoptionen - Preis bei Versandbestellungen 2023-05-03 16:22:51 +02:00
Lorenz Hilpert
35068e23cd #4021 PP - Suche nach Packstuecken oeffnet details bei einem treffer 2023-05-02 11:33:56 +02:00
Lorenz Hilpert
bc30b86cce #4020 PP - Label wird auf IPad nicht merh zwei zeilig angezeigt 2023-05-02 11:24:36 +02:00
Lorenz Hilpert
461f166e33 #4017 PP - scanId wird beim aender des status mit uebermittelt 2023-05-02 11:14:22 +02:00
Lorenz Hilpert
628dbd5227 Merge branch 'develop' into feature/rd-customer 2023-04-27 18:09:40 +02:00
Lorenz Hilpert
c05b290e49 Searchbox 2023-04-27 18:09:12 +02:00
Lorenz Hilpert
696015b6a4 Styling for Searchbox 2023-04-27 18:08:18 +02:00
Lorenz Hilpert
f2f70e1d83 Searchbox Update 2023-04-27 17:14:49 +02:00
Lorenz Hilpert
b4d967f721 Merge branch 'develop' into feature/rd-customer 2023-04-27 16:10:40 +02:00
Lorenz Hilpert
bf760677ef RD fur customer bereich 2023-04-27 16:06:59 +02:00
Lorenz Hilpert
4d1dbaa2f3 Moved searchbox and filter to shared 2023-04-27 14:26:50 +02:00
Lorenz Hilpert
595bb27d99 Shell Max Content Width 2023-04-26 10:42:15 +02:00
Lorenz Hilpert
ad95faffa7 Merge branch 'release/2.3' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into release/2.3 2023-04-24 23:09:21 +02:00
Michael Auer
a0eb3c0459 Revert "Update Remi Api Url"
This reverts commit ea9920c4d5.
2023-04-24 16:53:01 +02:00
Lorenz Hilpert
fea435a6d2 Bugfix - Hor-Scroll removed 2023-04-24 16:41:52 +02:00
Lorenz Hilpert
7b72532c9e Added Config - Missing Icons 2023-04-24 16:31:25 +02:00
Lorenz Hilpert
ea9920c4d5 Update Remi Api Url 2023-04-24 16:19:50 +02:00
Lorenz Hilpert
6b756fe893 Merge branch 'release/2.3' into develop 2023-04-24 15:35:34 +02:00
Lorenz Hilpert
54c7f51766 #3008 - Fix Process Tab Close 2023-04-24 15:34:29 +02:00
Lorenz Hilpert
94b787655e #3008 Navigation durch Bereich wechseln CTA 2023-04-24 15:29:58 +02:00
Lorenz Hilpert
259d0f1648 #3999 Kaufoptionen - Anzeigefehler in Titel/Format 2023-04-24 15:19:52 +02:00
Lorenz Hilpert
872d3ff383 #3391 - Filiale mit Klick auswählen 2023-04-24 14:57:16 +02:00
Lorenz Hilpert
cf1c4d37b9 Update Package Lock 2023-04-24 14:45:53 +02:00
Lorenz Hilpert
ada16bac6c Merge branch 'develop' into feature/rd-navigation-shell 2023-04-24 14:35:31 +02:00
Michael Auer
d68055f8a9 ~ Version Bump: 2.3 2023-04-24 11:52:12 +02:00
Michael Auer
8d98dcf7e7 Merge tag '2.2' into develop 2023-04-24 11:16:13 +02:00
Lorenz Hilpert
eefb6062c7 removed fdescribed 2023-04-21 18:49:57 +02:00
Lorenz Hilpert
470a451168 Unit Tests for ShellSideMenuComponent 2023-04-21 18:49:37 +02:00
Lorenz Hilpert
e3b018c5f7 remove fdescribe 2023-04-21 17:45:12 +02:00
Lorenz Hilpert
bd695e21d4 RD Navigation Unit Tests - ProcessBar 2023-04-21 17:44:49 +02:00
Lorenz Hilpert
6311ebe467 Show Navigation for Package-inspection 2023-04-21 10:33:34 +02:00
Lorenz Hilpert
f8a5ceed97 #3391 Fix - Tablet Kaufoptionen PopUp 2023-04-20 13:55:21 +02:00
Lorenz Hilpert
0420bda5da Bugfix - Default Branch in Kaufoptionen 2023-04-20 11:07:45 +02:00
Lorenz Hilpert
6dc532f40e Merge branch 'develop' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into develop 2023-04-20 08:31:50 +02:00
Lorenz Hilpert
0560d01f30 Merge branch 'release/2.2' into develop 2023-04-20 08:31:42 +02:00
Lorenz Hilpert
aaf156cee3 Merge branch 'develop' into feature/rd-navigation-shell 2023-04-18 14:11:34 +02:00
Lorenz Hilpert
e8020ffde6 RD Shell - Navigation 2023-04-18 14:09:36 +02:00
Nino Righi
8aa870dddd Merged PR 1521: #3506 Fix Removed PackageCode from Payload of ReturnFinalizeReceipt
#3506 Fix Removed PackageCode from Payload of ReturnFinalizeReceipt
2023-04-18 08:44:40 +00:00
Nino Righi
26a3c76d5f Merged PR 1520: #3906 Fix Instock Bug Article Search Results
#3906 Fix Instock Bug Article Search Results
2023-04-17 12:25:29 +00:00
Lorenz Hilpert
bba50ccbcc Merge branch 'release/2.2' into develop 2023-04-13 14:11:53 +02:00
Lorenz Hilpert
88a06628e3 #3973 added missing tabindex 2023-04-12 18:24:07 +02:00
Lorenz Hilpert
37ceb30ffb #3973 Bedienung per Tastatur funktioniert fehlerhaft 2023-04-12 13:23:48 +02:00
Nino Righi
ece5d0fa0d Merged PR 1519: #3957 Fix Develop Branch Selector Implementation with new purchasing options...
#3957 Fix Develop Branch Selector Implementation with new purchasing options modal
2023-04-11 14:26:23 +00:00
Lorenz Hilpert
6be214c6cd #3977 Fehlermeldung erscheint an falscher Stelle 2023-04-11 16:25:23 +02:00
Lorenz Hilpert
c470453ea4 Merge branch 'release/2.2' into develop 2023-04-05 11:58:29 +02:00
Lorenz Hilpert
27961bb4e5 Checkbox Styling Kaufoptionen 2023-04-05 11:09:41 +02:00
Lorenz Hilpert
74e4016625 #3928 Kaufoptionen - Filialen die IS_ORDERING_ENABLED true sind können ausgewählt werden 2023-04-03 13:14:58 +02:00
Lorenz Hilpert
c389008811 #3967 Fix - Nicht bestellbaren Artikel löschen führt zu Fehlermeldung 2023-04-03 10:21:21 +02:00
Nino Righi
d067f925b9 Merged PR 1517: #3927 #3929 #3964 Remission Wannennummer Changes
#3927 #3929 #3964 Remission Wannennummer Changes
2023-03-31 15:05:21 +00:00
Lorenz Hilpert
dd04a1f2af #3963 Fix Falsche Verfügbarkeiten 2023-03-31 14:05:15 +02:00
Lorenz Hilpert
9caabb6cc0 #3960 Buttons Alle auswählen and Alle abwählen will now work correctly. 2023-03-31 13:34:00 +02:00
Nino Righi
33b28d5f41 Merged PR 1515: #3244 Remission Removed "Are you sure you want to remit" - Popup
#3244 Remission Removed "Are you sure you want to remit" - Popup
2023-03-31 11:21:28 +00:00
Lorenz Hilpert
475f9b5e34 Mark PurchaseOptionsModalComponent Fetching if Availabilities are being fetched 2023-03-31 11:29:42 +02:00
Lorenz Hilpert
447456d7a6 #3946 Anzeige lieferbare Menge nur in Popup 2023-03-30 11:22:07 +02:00
Lorenz Hilpert
241a34d7a8 Merge branch 'release/2.2' into develop 2023-03-30 11:04:04 +02:00
Lorenz Hilpert
8bc2ea8373 #3385 Preiseingabe Geschenkkarte 2023-03-30 10:39:40 +02:00
Lorenz Hilpert
e066da3762 #3386 Canadd Wurde fuer Download Artikel falsch hinterlegt 2023-03-29 11:54:19 +02:00
Lorenz Hilpert
ad96278956 #3688 List Styling angepasst 2023-03-29 10:29:32 +02:00
Lorenz Hilpert
83406277ad #3936 - Kundenbestellung Leere Edit Seite 2023-03-28 14:40:49 +02:00
Lorenz Hilpert
9e89348381 #3958 Wahl Rücklage Kaufoption wirft Fehler 2023-03-28 14:10:25 +02:00
Lorenz Hilpert
0fb7419598 #3385 HFI Gutschein 2023-03-27 11:19:09 +02:00
Lorenz Hilpert
1790298cb4 #3931 Löschen von Positionen in der Kaufoption 2023-03-24 11:28:53 +01:00
Lorenz Hilpert
ffe8e39c85 #3934 - Anzeige Message Wenn Keine Verfügbarkeiten Existieren 2023-03-24 11:20:14 +01:00
Lorenz Hilpert
67e0f4bd46 #3945 Reinfolge von verfügbar als-Daten ist nicht fest 2023-03-23 19:24:22 +01:00
Lorenz Hilpert
e7b3a58da3 #3946 Fehler Lieferbare Exemplare 2023-03-23 19:20:24 +01:00
Lorenz Hilpert
598f9f3777 #3385 HFI Gutschein Anzeige Kaufoptionen 2023-03-23 18:25:51 +01:00
Lorenz Hilpert
4b342778df #3365 Navigation angepasst 2023-03-22 15:32:20 +01:00
Lorenz Hilpert
10e8fd904a #3933 2023-03-22 14:29:57 +01:00
Lorenz Hilpert
1de342fd3b Update Add To Shopping Cart from PDP
(cherry picked from commit 4a5dd23561fdec458447c19c93faa1654ab80c7c)
2023-03-21 11:21:35 +01:00
Lorenz Hilpert
f4c1c3dd7f Merged PR 1513: Kaufoptionen
Related work items: #3365, #3366, #3385, #3386, #3391
2023-03-20 17:11:53 +00:00
Nino Righi
80bfc59356 Merged PR 1500: #3506 Remission Wanne Scanner nach Start der Remission
#3506 Remission Wanne Scanner nach Start der Remission
2023-03-17 09:25:43 +00:00
1404 changed files with 39336 additions and 14603 deletions

View File

@@ -3,6 +3,5 @@
"johnpapa.angular2",
"esbenp.prettier-vscode",
"angular.ng-template",
"eg2.vscode-npm-script"
]
}

View File

@@ -375,37 +375,6 @@
}
}
},
"@shell/breadcrumb": {
"projectType": "library",
"root": "apps/shell/breadcrumb",
"sourceRoot": "apps/shell/breadcrumb/src",
"prefix": "shell",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/shell/breadcrumb/tsconfig.lib.json",
"project": "apps/shell/breadcrumb/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/breadcrumb/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "apps/shell/breadcrumb/tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
}
}
},
"@domain/defs": {
"projectType": "library",
"root": "apps/domain/defs",
@@ -840,37 +809,6 @@
}
}
},
"@shell/header": {
"projectType": "library",
"root": "apps/shell/header",
"sourceRoot": "apps/shell/header/src",
"prefix": "shell",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"tsConfig": "apps/shell/header/tsconfig.lib.json",
"project": "apps/shell/header/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/header/tsconfig.lib.prod.json"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "apps/shell/header/tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
}
}
},
"@modal/reorder": {
"projectType": "library",
"root": "apps/modal/reorder",
@@ -1058,74 +996,6 @@
}
}
},
"@shell/footer": {
"projectType": "library",
"root": "apps/shell/footer",
"sourceRoot": "apps/shell/footer/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/footer/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/footer/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/footer/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "apps/shell/footer/tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
}
}
},
"@shell/process": {
"projectType": "library",
"root": "apps/shell/process",
"sourceRoot": "apps/shell/process/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/process/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/process/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/process/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "apps/shell/process/tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
}
}
},
"@domain/isa": {
"projectType": "library",
"root": "apps/domain/isa",
@@ -1160,40 +1030,6 @@
}
}
},
"@shell/filter-overlay": {
"projectType": "library",
"root": "apps/shell/filter-overlay",
"sourceRoot": "apps/shell/filter-overlay/src",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/filter-overlay/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/filter-overlay/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "apps/shell/filter-overlay/tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
}
}
},
"@store/search-component-store": {
"projectType": "library",
"root": "apps/store/search-component-store",
@@ -1634,6 +1470,42 @@
}
}
}
},
"shell": {
"projectType": "library",
"root": "apps/shell",
"sourceRoot": "apps/shell/src",
"prefix": "shell",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "apps/shell/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "apps/shell/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "apps/shell/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "apps/shell/tsconfig.spec.json",
"polyfills": [
"zone.js",
"zone.js/testing"
]
}
}
}
}
},
"cli": {
"analytics": false
}
}

View File

@@ -11,13 +11,10 @@ export class DevScanAdapter implements ScanAdapter {
constructor(private _modal: UiModalService, private _environmentService: EnvironmentService) {}
async init(): Promise<boolean> {
if (this._environmentService.isTablet()) {
return new Promise((resolve, reject) => {
resolve(isDevMode());
});
}
return false;
return Promise.resolve(false);
// return new Promise((resolve, reject) => {
// resolve(isDevMode());
// });
}
scan(): Observable<string> {

View File

@@ -14,7 +14,6 @@ export class ScanAdapterService {
async init(): Promise<void> {
for (const adapter of this.scanAdapters) {
const isReady = await adapter.init();
console.log('ScanAdapterService.init', adapter.name, isReady);
this._readyAdapters[adapter.name] = isReady;
}
}
@@ -24,42 +23,30 @@ export class ScanAdapterService {
}
getAdapter(name: string): ScanAdapter | undefined {
return this.scanAdapters.find((adapter) => adapter.name === name);
return this._readyAdapters[name] && this.scanAdapters.find((adapter) => adapter.name === name);
}
// return true if at least one adapter is ready
isReady(): boolean {
return Object.values(this._readyAdapters).some((ready) => ready);
}
scan(ops: { use?: string; include?: string[]; exclude?: string[] } = { exclude: ['Dev'] }): Observable<string> {
scan(): Observable<string> {
const adapterOrder = ['Native', 'Scandit', 'Dev'];
let adapter: ScanAdapter;
if (ops.use == undefined) {
// get the first adapter that is ready to use
adapter = this.scanAdapters
.filter((adapter) => {
if (ops.include?.length) {
return ops.include.includes(adapter.name);
} else if (ops.exclude?.length) {
return !ops.exclude.includes(adapter.name);
} else {
return true;
}
})
.find((adapter) => this._readyAdapters[adapter.name]);
} else {
adapter = this.getAdapter(ops.use);
for (const name of adapterOrder) {
adapter = this.getAdapter(name);
if (adapter) {
break;
}
}
if (!adapter) {
return throwError('No adapter found');
}
if (this._readyAdapters[adapter.name] == false) {
return throwError('Adapter is not ready');
}
return adapter.scan();
}
}

View File

@@ -2,8 +2,8 @@ import { NgModule } from '@angular/core';
import { ProductImagePipe } from './product-image.pipe';
@NgModule({
declarations: [ProductImagePipe],
imports: [],
declarations: [],
imports: [ProductImagePipe],
exports: [ProductImagePipe],
})
export class ProductImageModule {}

View File

@@ -3,6 +3,8 @@ import { ProductImageService } from './product-image.service';
@Pipe({
name: 'productImage',
standalone: true,
pure: true,
})
export class ProductImagePipe implements PipeTransform {
constructor(private imageService: ProductImageService) {}

View File

@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
import { DomainAvailabilityService } from '@domain/availability';
import { Store } from '@ngrx/store';
import { BranchDTO } from '@swagger/checkout';
import { isBoolean, isNumber } from '@utils/common';
@@ -16,19 +15,18 @@ import {
selectActivatedProcess,
patchProcess,
patchProcessData,
selectTitle,
setTitle,
} from './store';
@Injectable()
export class ApplicationService {
/** @deprecated */
private activatedProcessIdSubject = new BehaviorSubject<number>(undefined);
/** @deprecated */
get activatedProcessId() {
return this.activatedProcessIdSubject.value;
}
/** @deprecated */
get activatedProcessId$() {
return this.activatedProcessIdSubject.asObservable();
}
@@ -48,6 +46,14 @@ export class ApplicationService {
return this.store.select(selectSection);
}
getTitle$() {
return this.getSection$().pipe(
map((section) => {
return section === 'customer' ? 'Kundenbereich' : 'Filialbereich';
})
);
}
/** @deprecated */
getActivatedProcessId$() {
return this.store.select(selectActivatedProcess).pipe(map((process) => process?.id));

View File

@@ -3,6 +3,8 @@ import { ApplicationProcess } from '..';
const prefix = '[CORE-APPLICATION]';
export const setTitle = createAction(`${prefix} Set Title`, props<{ title: string }>());
export const setSection = createAction(`${prefix} Set Section`, props<{ section: 'customer' | 'branch' }>());
export const addProcess = createAction(`${prefix} Add Process`, props<{ process: ApplicationProcess }>());

View File

@@ -1,9 +1,18 @@
import { Action, createReducer, on } from '@ngrx/store';
import { setSection, addProcess, removeProcess, setActivatedProcess, patchProcess, patchProcessData } from './application.actions';
import {
setSection,
addProcess,
removeProcess,
setActivatedProcess,
patchProcess,
patchProcessData,
setTitle,
} from './application.actions';
import { ApplicationState, INITIAL_APPLICATION_STATE } from './application.state';
const _applicationReducer = createReducer(
INITIAL_APPLICATION_STATE,
on(setTitle, (state, { title }) => ({ ...state, title })),
on(setSection, (state, { section }) => ({ ...state, section })),
on(addProcess, (state, { process }) => ({ ...state, processes: [...state.processes, { data: {}, ...process }] })),
on(removeProcess, (state, { processId }) => {

View File

@@ -2,6 +2,8 @@ import { createFeatureSelector, createSelector } from '@ngrx/store';
import { ApplicationState } from './application.state';
export const selectApplicationState = createFeatureSelector<ApplicationState>('core-application');
export const selectTitle = createSelector(selectApplicationState, (s) => s.title);
export const selectSection = createSelector(selectApplicationState, (s) => s.section);
export const selectProcesses = createSelector(selectApplicationState, (s) => s.processes);

View File

@@ -1,11 +1,13 @@
import { ApplicationProcess } from '../defs';
export interface ApplicationState {
title: string;
processes: ApplicationProcess[];
section: 'customer' | 'branch';
}
export const INITIAL_APPLICATION_STATE: ApplicationState = {
title: '',
processes: [],
section: 'customer',
};

View File

@@ -135,9 +135,9 @@ export class BreadcrumbService {
crumbs.forEach((crumb) => this.removeBreadcrumb(crumb.id));
}
getLatestBreadcrumbForSection(section: 'customer' | 'branch') {
getLatestBreadcrumbForSection(section: 'customer' | 'branch', predicate: (crumb: Breadcrumb) => boolean = (_) => true) {
return this.store
.select(selectors.selectBreadcrumbsBySection, { section })
.pipe(map((crumbs) => crumbs.sort((a, b) => b.changed - a.changed).find((f) => true)));
.pipe(map((crumbs) => crumbs.sort((a, b) => b.timestamp - a.timestamp).find((f) => predicate(f))));
}
}

View File

@@ -22,7 +22,7 @@ export interface Breadcrumb {
/**
* Url
*/
path: string;
path: string | any[];
/**
* Query Parameter

View File

@@ -1,4 +1,6 @@
import { CommandService } from './command.service';
export abstract class ActionHandler<T = any> {
constructor(readonly action: string) {}
abstract handler(data: T): Promise<T>;
abstract handler(data: T, service?: CommandService): Promise<T>;
}

View File

@@ -1,8 +1,12 @@
import { ModuleWithProviders, NgModule, Type } from '@angular/core';
import { ModuleWithProviders, NgModule, Provider, Type } from '@angular/core';
import { ActionHandler } from './action-handler.interface';
import { CommandService } from './command.service';
import { FEATURE_ACTION_HANDLERS, ROOT_ACTION_HANDLERS } from './tokens';
export function provideActionHandlers(actionHandlers: Type<ActionHandler>[]): Provider[] {
return [CommandService, actionHandlers.map((handler) => ({ provide: FEATURE_ACTION_HANDLERS, useClass: handler, multi: true }))];
}
@NgModule({})
export class CoreCommandModule {
static forRoot(actionHandlers: Type<ActionHandler>[]): ModuleWithProviders<CoreCommandModule> {

View File

@@ -16,7 +16,7 @@ export class CommandService {
throw new Error('Action Handler does not exist');
}
data = await handler.handler(data);
data = await handler.handler(data, this);
}
return data;
}

View File

@@ -1,17 +1,77 @@
import { Injectable } from '@angular/core';
import { Platform } from '@angular/cdk/platform';
import { NativeContainerService } from 'native-container';
import { BreakpointObserver } from '@angular/cdk/layout';
import { map } from 'rxjs/operators';
const MATCH_TABLET = '(max-width: 1023px)';
const MATCH_DESKTOP_SMALL = '(min-width: 1024px) and (max-width: 1439px)';
const MATCH_DESKTOP = '(min-width: 1280px)';
const MATCH_DESKTOP_LARGE = '(min-width: 1440px)';
const MATCH_DESKTOP_XLARGE = '(min-width: 1920px)';
const MATCH_DESKTOP_XXLARGE = '(min-width: 2736px)';
@Injectable({
providedIn: 'root',
})
export class EnvironmentService {
constructor(private _platform: Platform, private _nativeContainer: NativeContainerService) {}
constructor(
private _platform: Platform,
private _nativeContainer: NativeContainerService,
private _breakpointObserver: BreakpointObserver
) {}
matchTablet(): boolean {
return this._breakpointObserver.isMatched(MATCH_TABLET);
}
matchTablet$ = this._breakpointObserver.observe(MATCH_TABLET).pipe(map((result) => result.matches));
matchDesktopSmall(): boolean {
return this._breakpointObserver.isMatched(MATCH_DESKTOP_SMALL);
}
matchDesktopSmall$ = this._breakpointObserver.observe(MATCH_DESKTOP_SMALL).pipe(map((result) => result.matches));
matchDesktop(): boolean {
return this._breakpointObserver.isMatched(MATCH_DESKTOP);
}
matchDesktop$ = this._breakpointObserver.observe(MATCH_DESKTOP).pipe(map((result) => result.matches));
matchDesktopLarge(): boolean {
return this._breakpointObserver.isMatched(MATCH_DESKTOP_LARGE);
}
matchDesktopLarge$ = this._breakpointObserver.observe(MATCH_DESKTOP_LARGE).pipe(map((result) => result.matches));
matchDesktopXLarge(): boolean {
return this._breakpointObserver.isMatched(MATCH_DESKTOP_XLARGE);
}
matchDesktopXLarge$ = this._breakpointObserver.observe(MATCH_DESKTOP_XLARGE).pipe(map((result) => result.matches));
matchDesktopXXLarge(): boolean {
return this._breakpointObserver.isMatched(MATCH_DESKTOP_XXLARGE);
}
matchDesktopXXLarge$ = this._breakpointObserver.observe(MATCH_DESKTOP_XXLARGE).pipe(map((result) => result.matches));
/**
* @deprecated Use `matchDesktopSmall` or 'matchDesktop' instead.
*/
isDesktop(): boolean {
return !this.isTablet();
}
/**
* @deprecated Use `matchTablet` instead.
*/
isTablet(): boolean {
return this.isNative() || this.isSafari();
}
@@ -21,6 +81,6 @@ export class EnvironmentService {
}
isSafari(): boolean {
return (this._platform.ANDROID || this._platform.IOS) && this._platform.SAFARI;
return this._platform.IOS && this._platform.SAFARI;
}
}

View File

@@ -1,14 +0,0 @@
import { AnimationTriggerMetadata, trigger, state, transition, style, animate } from '@angular/animations';
export const slideAnimationTime = 150;
export const toastAnimations: {
readonly slideToast: AnimationTriggerMetadata;
} = {
slideToast: trigger('slideAnimation', [
state('default', style({ transform: 'translateY(0%)' })),
transition('void => *', [style({ transform: 'translateY(-100%)' }), animate(`${slideAnimationTime}ms ease-in`)]),
transition('default => closing', animate(`${slideAnimationTime}ms ease-in`, style({ transform: 'translateY(-100%)' }))),
]),
};
export type ToastAnimationState = 'default' | 'closing';

View File

@@ -1,4 +0,0 @@
// start:ng42.barrel
export * from './toast';
export * from './toast-ref';
// end:ng42.barrel

View File

@@ -1,17 +0,0 @@
import { OverlayRef } from '@angular/cdk/overlay';
export class ToastRef {
constructor(private readonly _overlay: OverlayRef) {}
close() {
this._overlay.dispose();
}
isVisible() {
return this._overlay && this._overlay.overlayElement;
}
getPosition() {
return this._overlay.overlayElement.getBoundingClientRect();
}
}

View File

@@ -1,11 +0,0 @@
import { TemplateRef } from '@angular/core';
export interface Toast {
title?: string;
text?: string;
timer?: number;
position?: 'top-left' | 'top' | 'top-right' | 'bottom-right' | 'bottom' | 'bottom-left';
size?: 'width-full' | 'content';
template?: TemplateRef<any>; // For rendering dynamic content
templateContext?: {}; // For rendering dynamic content
}

View File

@@ -1,8 +0,0 @@
// start:ng42.barrel
export * from './toast.component';
export * from './toast.module';
export * from './toast.service';
export * from './defs';
export * from './animation';
export * from './tokens';
// end:ng42.barrel

View File

@@ -1,15 +0,0 @@
<div class="toast-main" [style.width]="width" [@slideAnimation]="{ value: animationState }" (@slideAnimation.done)="onSlideFinished()">
<button class="absolute top-2 right-2 p-6 border-none bg-transparent" (click)="close()">
<ui-icon icon="close" size="20px"></ui-icon>
</button>
<div class="toast-content flex flex-col justify-center items-center">
<h1 class="text-card-sub font-bold text-center py-3 whitespace-pre-wrap">{{ data.title }}</h1>
<ng-container *ngIf="data.text; else templateRef">
<p class="block text-base overflow-y-hidden pb-3 text-center overflow-x-hidden">{{ data.text }}</p>
</ng-container>
</div>
</div>
<ng-template #templateRef>
<ng-container *ngTemplateOutlet="data.template; context: data.templateContext"> </ng-container>
</ng-template>

View File

@@ -1,12 +0,0 @@
.toast-main {
@apply block relative mx-auto box-border text-white p-4;
background-color: var(--toast-background);
min-width: 18.75rem;
max-width: calc(100vw - 2rem);
min-height: 5rem;
border-radius: 25px;
}
.toast-content {
min-height: 3rem;
}

View File

@@ -1,48 +0,0 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from '@angular/core';
import { toastAnimations, ToastAnimationState, slideAnimationTime } from './animation';
import { Toast, ToastRef } from './defs';
import { TOAST_CONFIG_TOKEN } from './tokens';
@Component({
selector: 'lib-toast',
templateUrl: 'toast.component.html',
styleUrls: ['toast.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [toastAnimations.slideToast],
})
export class ToastComponent implements OnInit, OnDestroy {
timeoutRef?: any;
animationState: ToastAnimationState = 'default';
width = '55.25rem';
constructor(
@Inject(TOAST_CONFIG_TOKEN) public readonly data: Toast,
private readonly _ref: ToastRef,
private readonly _cdr: ChangeDetectorRef
) {}
ngOnInit(): void {
if (this.data?.size) {
this.width = this.data?.size === 'width-full' ? '100vw' : '55.25rem';
}
this.timeoutRef = setTimeout(() => {
this.close();
this._cdr.markForCheck();
}, slideAnimationTime + (this.data.timer ?? 5000));
}
ngOnDestroy() {
clearTimeout(this.timeoutRef);
}
close() {
this.animationState = 'closing';
}
onSlideFinished() {
if (this.animationState === 'closing') {
this._ref.close();
}
}
}

View File

@@ -1,12 +0,0 @@
import { OverlayModule } from '@angular/cdk/overlay';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { UiIconModule } from '@ui/icon';
import { ToastComponent } from './toast.component';
@NgModule({
declarations: [ToastComponent],
imports: [CommonModule, OverlayModule, UiIconModule],
exports: [ToastComponent],
})
export class ToastModule {}

View File

@@ -1,79 +0,0 @@
import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { Injectable, Injector } from '@angular/core';
import { Toast, ToastRef } from './defs';
import { ToastComponent } from './toast.component';
import { TOAST_CONFIG_TOKEN } from './tokens';
@Injectable({
providedIn: 'root',
})
export class ToastService {
private _lastToastRef: ToastRef;
get lastToastRef() {
return this._lastToastRef;
}
set lastToastRef(toastRef: ToastRef) {
this._lastToastRef = toastRef;
}
constructor(private readonly _overlay: Overlay, private readonly _injector: Injector) {}
create(data: Toast) {
const positionStrategy = this.getPositionStrategy(data);
const overlayRef = this._overlay.create({ positionStrategy });
this.lastToastRef = new ToastRef(overlayRef);
const injector = this.getInjector(data, this.lastToastRef);
const toastPortal = new ComponentPortal(ToastComponent, null, injector);
overlayRef.attach(toastPortal);
return this.lastToastRef;
}
getInjector(data: Toast, ref: ToastRef) {
return Injector.create({
parent: this._injector,
providers: [
{ provide: TOAST_CONFIG_TOKEN, useValue: data },
{ provide: ToastRef, useValue: ref },
],
});
}
getPositionStrategy(data: Toast) {
switch (data?.position) {
case 'top':
return this._overlay.position().global().top(this.getNextPosition()).centerHorizontally();
case 'top-left':
return this._overlay.position().global().top(this.getNextPosition()).left('1rem');
case 'top-right':
return this._overlay.position().global().top(this.getNextPosition()).right('1rem');
case 'bottom':
return this._overlay.position().global().bottom(this.getNextPosition(true)).centerHorizontally();
case 'bottom-left':
return this._overlay.position().global().bottom(this.getNextPosition(true)).left('1rem');
case 'bottom-right':
return this._overlay.position().global().bottom(this.getNextPosition(true)).right('1rem');
default:
return this._overlay.position().global().top(this.getNextPosition()).centerHorizontally();
}
}
getNextPosition(fromBottom?: boolean) {
const lastToastIsVisible = this.lastToastRef && this.lastToastRef.isVisible();
let position = fromBottom ? 6 : 9;
if (lastToastIsVisible && fromBottom) {
position = (window.innerHeight - this.lastToastRef.getPosition().bottom + this.lastToastRef.getPosition().height + 16) / 16;
} else if (lastToastIsVisible) {
position = (this.lastToastRef.getPosition().bottom + 16) / 16;
}
return position + 'rem';
}
}

View File

@@ -1,4 +0,0 @@
import { InjectionToken } from '@angular/core';
import { Toast } from './defs';
export const TOAST_CONFIG_TOKEN = new InjectionToken<Toast>('TOAST_DATA');

View File

@@ -1,5 +0,0 @@
/*
* Public API Surface of toast
*/
export * from './lib';

View File

@@ -8,7 +8,7 @@ import {
StoreCheckoutSupplierService,
SupplierDTO,
} from '@swagger/checkout';
import { combineLatest, Observable, of } from 'rxjs';
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
import {
AvailabilityRequestDTO,
AvailabilityService,
@@ -21,11 +21,16 @@ import { isArray, memorize } from '@utils/common';
import { LogisticianDTO, LogisticianService } from '@swagger/oms';
import { ResponseArgsOfIEnumerableOfStockInfoDTO, StockDTO, StockInfoDTO, StockService } from '@swagger/remi';
import { PriceDTO } from '@swagger/availability';
import { AvailabilityByBranchDTO, ItemData } from './defs';
import { AvailabilityByBranchDTO, ItemData, Ssc } from './defs';
import { Availability } from './defs/availability';
import { isEmpty } from 'lodash';
@Injectable()
export class DomainAvailabilityService {
// Ticket #3378 Keep Result List Items and Details Page SSC in sync
sscs$ = new BehaviorSubject<Array<Ssc>>([]);
sscsObs$ = this.sscs$.asObservable();
constructor(
private _availabilityService: AvailabilityService,
private _logisticanService: LogisticianService,
@@ -34,6 +39,11 @@ export class DomainAvailabilityService {
private _branchService: StoreCheckoutBranchService
) {}
@memorize({ ttl: 10000 })
memorizedAvailabilityShippingAvailability(request: Array<AvailabilityRequestDTO>) {
return this._availabilityService.AvailabilityShippingAvailability(request).pipe(shareReplay(1));
}
@memorize()
getSuppliers(): Observable<SupplierDTO[]> {
return this._supplierService.StoreCheckoutSupplierGetSuppliers({}).pipe(
@@ -140,6 +150,7 @@ export class DomainAvailabilityService {
);
}
@memorize({ ttl: 10000 })
getTakeAwayAvailability({
item,
quantity,
@@ -160,7 +171,7 @@ export class DomainAvailabilityService {
),
map(([response, supplier, defaultBranch]) => {
const price = item?.price;
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch.id ?? defaultBranch.id, quantity, price });
return this._mapToTakeAwayAvailability({ response, supplier, branchId: branch?.id ?? defaultBranch?.id, quantity, price });
}),
shareReplay(1)
);
@@ -249,57 +260,53 @@ export class DomainAvailabilityService {
@memorize({ ttl: 10000 })
getDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
return this._availabilityService
.AvailabilityShippingAvailability([
{
ean: item?.ean,
itemId: item?.itemId ? String(item?.itemId) : null,
price: item?.price,
qty: quantity,
},
])
.pipe(
timeout(5000),
map((r) => this._mapToShippingAvailability(r.result)?.find((_) => true)),
shareReplay(1)
);
return this.memorizedAvailabilityShippingAvailability([
{
ean: item?.ean,
itemId: item?.itemId ? String(item?.itemId) : null,
price: item?.price,
qty: quantity,
},
]).pipe(
timeout(5000),
map((r) => this._mapToShippingAvailability(r.result)?.find((_) => true)),
shareReplay(1)
);
}
@memorize({ ttl: 10000 })
getDigDeliveryAvailability({ item, quantity }: { item: ItemData; quantity: number }): Observable<AvailabilityDTO> {
return this._availabilityService
.AvailabilityShippingAvailability([
{
qty: quantity,
ean: item?.ean,
itemId: item?.itemId ? String(item?.itemId) : null,
price: item?.price,
},
])
.pipe(
timeout(5000),
map((r) => {
const availabilities = r.result;
const preferred = availabilities?.find((f) => f.preferred === 1);
return this.memorizedAvailabilityShippingAvailability([
{
qty: quantity,
ean: item?.ean,
itemId: item?.itemId ? String(item?.itemId) : null,
price: item?.price,
},
]).pipe(
timeout(5000),
map((r) => {
const availabilities = r.result;
const preferred = availabilities?.find((f) => f.preferred === 1);
const availability: AvailabilityDTO = {
availabilityType: preferred?.status,
ssc: preferred?.ssc,
sscText: preferred?.sscText,
supplier: { id: preferred?.supplierId },
isPrebooked: preferred?.isPrebooked,
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
estimatedDelivery: preferred?.estimatedDelivery,
price: preferred?.price,
logistician: { id: preferred?.logisticianId },
supplierProductNumber: preferred?.supplierProductNumber,
supplierInfo: preferred?.requestStatusCode,
lastRequest: preferred?.requested,
};
return availability;
}),
shareReplay(1)
);
const availability: AvailabilityDTO = {
availabilityType: preferred?.status,
ssc: preferred?.ssc,
sscText: preferred?.sscText,
supplier: { id: preferred?.supplierId },
isPrebooked: preferred?.isPrebooked,
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
estimatedDelivery: preferred?.estimatedDelivery,
price: preferred?.price,
logistician: { id: preferred?.logisticianId },
supplierProductNumber: preferred?.supplierProductNumber,
supplierInfo: preferred?.requestStatusCode,
lastRequest: preferred?.requested,
};
return availability;
}),
shareReplay(1)
);
}
@memorize({ ttl: 10000 })
@@ -333,37 +340,35 @@ export class DomainAvailabilityService {
@memorize({ ttl: 10000 })
getDownloadAvailability({ item }: { item: ItemData }): Observable<AvailabilityDTO> {
return this._availabilityService
.AvailabilityShippingAvailability([
{
ean: item?.ean,
itemId: item?.itemId ? String(item?.itemId) : null,
price: item?.price,
qty: 1,
},
])
.pipe(
map((r) => {
const availabilities = r.result;
const preferred = availabilities?.find((f) => f.preferred === 1);
return this.memorizedAvailabilityShippingAvailability([
{
ean: item?.ean,
itemId: item?.itemId ? String(item?.itemId) : null,
price: item?.price,
qty: 1,
},
]).pipe(
map((r) => {
const availabilities = r.result;
const preferred = availabilities?.find((f) => f.preferred === 1);
const availability: AvailabilityDTO = {
availabilityType: preferred?.status,
ssc: preferred?.ssc,
sscText: preferred?.sscText,
supplier: { id: preferred?.supplierId },
isPrebooked: preferred?.isPrebooked,
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
price: preferred?.price,
supplierProductNumber: preferred?.supplierProductNumber,
logistician: { id: preferred?.logisticianId },
supplierInfo: preferred?.requestStatusCode,
lastRequest: preferred?.requested,
};
return availability;
}),
shareReplay(1)
);
const availability: AvailabilityDTO = {
availabilityType: preferred?.status,
ssc: preferred?.ssc,
sscText: preferred?.sscText,
supplier: { id: preferred?.supplierId },
isPrebooked: preferred?.isPrebooked,
estimatedShippingDate: preferred?.requestStatusCode === '32' ? preferred?.altAt : preferred?.at,
price: preferred?.price,
supplierProductNumber: preferred?.supplierProductNumber,
logistician: { id: preferred?.logisticianId },
supplierInfo: preferred?.requestStatusCode,
lastRequest: preferred?.requested,
};
return availability;
}),
shareReplay(1)
);
}
@memorize({ ttl: 10000 })
@@ -401,7 +406,7 @@ export class DomainAvailabilityService {
@memorize({ ttl: 10000 })
getDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
return this._availabilityService.AvailabilityShippingAvailability(payload).pipe(
return this.memorizedAvailabilityShippingAvailability(payload).pipe(
timeout(20000),
map((response) => this._mapToShippingAvailability(response.result))
);
@@ -409,7 +414,7 @@ export class DomainAvailabilityService {
@memorize({ ttl: 10000 })
getDigDeliveryAvailabilities(payload: AvailabilityRequestDTO[]) {
return this._availabilityService.AvailabilityShippingAvailability(payload).pipe(
return this.memorizedAvailabilityShippingAvailability(payload).pipe(
timeout(20000),
map((response) => this._mapToShippingAvailability(response.result))
);
@@ -447,6 +452,9 @@ export class DomainAvailabilityService {
}
isAvailable({ availability }: { availability: AvailabilityDTO }) {
if (availability?.supplier?.id === 16 && availability?.inStock == 0) {
return false;
}
return [2, 32, 256, 1024, 2048, 4096].some((code) => availability?.availabilityType === code);
}
@@ -476,6 +484,10 @@ export class DomainAvailabilityService {
};
}
private _priceIsEmpty(price: PriceDTO) {
return isEmpty(price?.value) || isEmpty(price?.vat);
}
private _mapToTakeAwayAvailability({
response,
supplier,
@@ -496,7 +508,7 @@ export class DomainAvailabilityService {
inStock: inStock,
supplierSSC: quantity <= inStock ? '999' : '',
supplierSSCText: quantity <= inStock ? 'Filialentnahme' : '',
price: price ?? stockInfo?.retailPrice,
price: this._priceIsEmpty(price) ? stockInfo?.retailPrice : price,
supplier: { id: supplier?.id },
// TODO: Change after API Update
// LH: 2021-03-09 preis Property hat nun ein Fallback auf retailPrice
@@ -538,6 +550,7 @@ export class DomainAvailabilityService {
return preferred.map((p) => {
return [
{
orderDeadline: p?.orderDeadline,
availabilityType: p?.status,
ssc: p?.ssc,
sscText: p?.sscText,
@@ -559,7 +572,6 @@ export class DomainAvailabilityService {
private _mapToShippingAvailability(availabilities: SwaggerAvailabilityDTO[]) {
const preferred = availabilities.filter((f) => f.preferred === 1);
return preferred.map((p) => {
return {
availabilityType: p?.status,
@@ -573,6 +585,7 @@ export class DomainAvailabilityService {
supplierInfo: p?.requestStatusCode,
lastRequest: p?.requested,
itemId: p.itemId,
priceMaintained: p.priceMaintained,
};
});
}

View File

@@ -1,3 +1,4 @@
export * from './availability-by-branch-dto';
export * from './availability';
export * from './item-data';
export * from './ssc';

View File

@@ -0,0 +1,5 @@
export interface Ssc {
itemId?: number;
ssc?: string;
sscText?: string;
}

View File

@@ -26,23 +26,56 @@ import {
StoreCheckoutBuyerService,
StoreCheckoutPayerService,
StoreCheckoutBranchService,
ItemsResult,
ShoppingCartItemDTO,
} from '@swagger/checkout';
import { DisplayOrderDTO, DisplayOrderItemDTO, OrderCheckoutService, ReorderValues } from '@swagger/oms';
import {
DisplayOrderDTO,
DisplayOrderItemDTO,
OrderCheckoutService,
ReorderValues,
ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString,
} from '@swagger/oms';
import { isNullOrUndefined, memorize } from '@utils/common';
import { combineLatest, Observable, of, concat, isObservable, throwError } from 'rxjs';
import { bufferCount, catchError, filter, first, map, mergeMap, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
import { combineLatest, Observable, of, concat, isObservable, throwError, interval, zip, EMPTY, Subscription } from 'rxjs';
import {
bufferCount,
catchError,
debounceTime,
distinctUntilChanged,
filter,
first,
map,
mergeMap,
share,
shareReplay,
switchMap,
take,
tap,
withLatestFrom,
} from 'rxjs/operators';
import * as DomainCheckoutSelectors from './store/domain-checkout.selectors';
import * as DomainCheckoutActions from './store/domain-checkout.actions';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainAvailabilityService, ItemData } from '@domain/availability';
import { HttpErrorResponse } from '@angular/common/http';
import { ApplicationService } from '@core/application';
import { CustomerDTO, EntityDTOContainerOfAttributeDTO } from '@swagger/crm';
import { CustomerDTO } from '@swagger/crm';
import { Config } from '@core/config';
import parseDuration from 'parse-duration';
import { CheckoutEntity } from './store/defs/checkout.entity';
import { isEqual } from 'lodash';
@Injectable()
export class DomainCheckoutService {
get olaExpiration() {
const exp = this._config.get('@domain/checkout.olaExpiration') ?? '5m';
return parseDuration(exp);
}
constructor(
private store: Store<any>,
private _config: Config,
private applicationService: ApplicationService,
private storeCheckoutService: StoreCheckoutService,
private orderCheckoutService: OrderCheckoutService,
@@ -112,14 +145,14 @@ export class DomainCheckoutService {
})
.pipe(
map((response) => response.result),
tap((shoppingCart) =>
tap((shoppingCart) => {
this.store.dispatch(
DomainCheckoutActions.setShoppingCart({
processId,
shoppingCart,
})
)
),
);
}),
tap((shoppingCart) => this.updateProcessCount(processId, shoppingCart?.items?.length))
)
)
@@ -198,7 +231,15 @@ export class DomainCheckoutService {
);
}
canAddItems({ processId, payload, orderType }: { processId: number; payload: ItemPayload[]; orderType: string }) {
canAddItems({
processId,
payload,
orderType,
}: {
processId: number;
payload: ItemPayload[];
orderType: string;
}): Observable<ItemsResult[]> {
return this.getShoppingCart({ processId }).pipe(
first(),
withLatestFrom(this.store.select(DomainCheckoutSelectors.selectCustomerFeaturesByProcessId, { processId })),
@@ -217,7 +258,8 @@ export class DomainCheckoutService {
})
.pipe(
map((response) => {
return response.result;
// TODO: remove this when the API is fixed
return (response.result as unknown) as ItemsResult[];
})
);
})
@@ -233,11 +275,24 @@ export class DomainCheckoutService {
shoppingCartItemId: number;
availability: AvailabilityDTO;
}) {
return this._shoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability({
shoppingCartId,
shoppingCartItemId,
availability,
});
return this._shoppingCartService
.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability({
shoppingCartId,
shoppingCartItemId,
availability,
})
.pipe(
map((response) => response.result),
tap((shoppingCart) => {
this.store.dispatch(
DomainCheckoutActions.addShoppingCartItemAvailabilityToHistoryByShoppingCartId({
shoppingCartId,
availability,
shoppingCartItemId,
})
);
})
);
}
updateItemInShoppingCart({
@@ -249,7 +304,7 @@ export class DomainCheckoutService {
shoppingCartItemId: number;
update: UpdateShoppingCartItemDTO;
}): Observable<ShoppingCartDTO> {
return this.getShoppingCart({ processId }).pipe(
return this.getShoppingCart({ processId, latest: true }).pipe(
first(),
mergeMap((shoppingCart) =>
this._shoppingCartService
@@ -260,8 +315,21 @@ export class DomainCheckoutService {
})
.pipe(
map((response) => response.result),
tap((shoppingCart) => this.store.dispatch(DomainCheckoutActions.setShoppingCart({ processId, shoppingCart }))),
tap((shoppingCart) => this.updateProcessCount(processId, shoppingCart?.items?.length))
tap((shoppingCart) => {
this.store.dispatch(DomainCheckoutActions.setShoppingCart({ processId, shoppingCart }));
if (update.availability) {
this.store.dispatch(
DomainCheckoutActions.addShoppingCartItemAvailabilityToHistory({
processId,
availability: update.availability,
shoppingCartItemId,
})
);
}
this.updateProcessCount(processId, shoppingCart?.items?.length);
})
)
)
);
@@ -362,8 +430,9 @@ export class DomainCheckoutService {
_setBuyer({ processId, buyer }: { processId: number; buyer: BuyerDTO }): Observable<CheckoutDTO> {
return this.getCheckout({ processId }).pipe(
first(),
mergeMap((checkout) =>
this._buyerService
mergeMap((checkout) => {
console.log('checkout', checkout, processId);
return this._buyerService
.StoreCheckoutBuyerSetBuyerPOST({
checkoutId: checkout?.id,
buyerDTO: buyer,
@@ -371,8 +440,8 @@ export class DomainCheckoutService {
.pipe(
map((response) => response.result),
tap((checkout) => this.store.dispatch(DomainCheckoutActions.setCheckout({ processId, checkout })))
)
)
);
})
);
}
@@ -530,6 +599,172 @@ export class DomainCheckoutService {
);
}
async refreshAvailability({
processId,
shoppingCartItemId,
}: {
processId: number;
shoppingCartItemId: number;
}): Promise<AvailabilityDTO> {
const shoppingCart = await this.getShoppingCart({ processId }).pipe(first()).toPromise();
const item = shoppingCart?.items.find((item) => item.id === shoppingCartItemId)?.data;
if (!item) {
return;
}
const itemData: ItemData = {
ean: item.product.ean,
itemId: Number(item.product.catalogProductNumber),
price: item.availability.price,
};
let availability: AvailabilityDTO;
switch (item.features.orderType) {
case 'Abholung':
const abholung = await this.availabilityService
.getPickUpAvailability({
item: itemData,
branch: item.destination?.data?.targetBranch?.data,
quantity: item.quantity,
})
.toPromise();
availability = abholung[0];
break;
case 'Rücklage':
const ruecklage = await this.availabilityService
.getTakeAwayAvailability({
item: itemData,
quantity: item.quantity,
branch: item.destination?.data?.targetBranch?.data,
})
.toPromise();
availability = ruecklage;
break;
case 'Download':
const download = await this.availabilityService
.getDownloadAvailability({
item: itemData,
})
.toPromise();
availability = download;
break;
case 'Versand':
const versand = await this.availabilityService
.getDeliveryAvailability({
item: itemData,
quantity: item.quantity,
})
.toPromise();
availability = versand;
break;
case 'DIG-Versand':
const digVersand = await this.availabilityService
.getDigDeliveryAvailability({
item: itemData,
quantity: item.quantity,
})
.toPromise();
availability = digVersand;
break;
case 'B2B-Versand':
const b2bVersand = await this.availabilityService
.getB2bDeliveryAvailability({
item: itemData,
quantity: item.quantity,
})
.toPromise();
availability = b2bVersand;
break;
}
await this.updateItemInShoppingCart({
processId,
update: { availability },
shoppingCartItemId: item.id,
}).toPromise();
return availability;
}
/**
* Check if the availability of all items is valid
* @param param0 Process Id
* @returns true if the availability of all items is valid
*/
validateOlaStatus({ processId, interval }: { processId: number; interval?: number }): Observable<boolean> {
return new Observable((observer) => {
const enity$ = this.store.select(DomainCheckoutSelectors.selectCheckoutEntityByProcessId, { processId });
const olaExpiration = this.olaExpiration;
let timeout: any;
let subscription: Subscription;
function check() {
const now = Date.now();
subscription?.unsubscribe();
subscription = enity$.pipe(take(1)).subscribe((entity) => {
if (!entity || !entity.shoppingCart || !entity.shoppingCart.items) {
return;
}
const itemAvailabilityTimestamp = entity.itemAvailabilityTimestamp ?? {};
const shoppingCart = entity.shoppingCart;
const timestamps = shoppingCart.items
?.map((i) => i.data)
?.filter((item) => !!item?.features?.orderType)
?.map((item) => itemAvailabilityTimestamp[`${item.id}_${item.features.orderType}`]);
if (timestamps?.length > 0) {
const oldestTimestamp = Math.min(...timestamps);
observer.next(now - oldestTimestamp < olaExpiration);
}
timeout = setTimeout(() => {
check.call(this);
}, interval ?? olaExpiration / 10);
});
}
check.call(this);
return () => {
subscription?.unsubscribe();
clearTimeout(timeout);
};
});
}
validateAvailabilities({ processId }: { processId: number }): Observable<boolean> {
return this.getShoppingCart({ processId }).pipe(
map((shoppingCart) => {
const items = shoppingCart?.items?.map((item) => item.data) || [];
return items.every((i) => this.availabilityService.isAvailable({ availability: i.availability }));
})
);
}
checkoutIsValid({ processId }: { processId: number }): Observable<boolean> {
const olaStatus$ = this.validateOlaStatus({ processId, interval: 250 });
const availabilities$ = this.validateAvailabilities({ processId });
return combineLatest([olaStatus$, availabilities$]).pipe(map(([olaStatus, availabilities]) => olaStatus && availabilities));
}
completeCheckout({ processId }: { processId: number }): Observable<DisplayOrderDTO[]> {
const refreshShoppingCart$ = this.getShoppingCart({ processId, latest: true }).pipe(first());
const refreshCheckout$ = this.getCheckout({ processId, refresh: true }).pipe(first());
@@ -683,21 +918,64 @@ export class DomainCheckoutService {
)
);
return updateDestination$
.pipe(tap(console.log.bind(window, 'updateDestination$')))
return of(undefined)
.pipe(
mergeMap((_) => updateDestination$.pipe(tap(console.log.bind(window, 'updateDestination$')))),
mergeMap((_) => refreshShoppingCart$.pipe(tap(console.log.bind(window, 'refreshShoppingCart$')))),
mergeMap((_) => setSpecialComment$.pipe(tap(console.log.bind(window, 'setSpecialComment$')))),
mergeMap((_) => refreshCheckout$.pipe(tap(console.log.bind(window, 'refreshCheckout$')))),
mergeMap((_) => checkAvailabilities$.pipe(tap(console.log.bind(window, 'checkAvailabilities$')))),
mergeMap((_) => updateAvailabilities$.pipe(tap(console.log.bind(window, 'updateAvailabilities$')))),
mergeMap((_) => updateAvailabilities$.pipe(tap(console.log.bind(window, 'updateAvailabilities$'))))
)
.pipe(
mergeMap((_) => setBuyer$.pipe(tap(console.log.bind(window, 'setBuyer$')))),
mergeMap((_) => setNotificationChannels$.pipe(tap(console.log.bind(window, 'setNotificationChannels$')))),
mergeMap((_) => setPayer$.pipe(tap(console.log.bind(window, 'setPayer$')))),
mergeMap((_) => setPaymentType$.pipe(tap(console.log.bind(window, 'setPaymentType$')))),
mergeMap((_) => setDestination$.pipe(tap(console.log.bind(window, 'setDestination$'))))
mergeMap((_) => setDestination$.pipe(tap(console.log.bind(window, 'setDestination$')))),
mergeMap((_) => completeOrder$.pipe(tap(console.log.bind(window, 'completeOrder$'))))
);
}
completeKulturpassOrder({
processId,
orderItemSubsetId,
}: {
processId: number;
orderItemSubsetId: number;
}): Observable<ResponseArgsOfValueTupleOfIEnumerableOfDisplayOrderDTOAndIEnumerableOfKeyValueDTOOfStringAndString> {
const refreshShoppingCart$ = this.getShoppingCart({ processId, latest: true }).pipe(first());
const refreshCheckout$ = this.getCheckout({ processId, refresh: true }).pipe(first());
const setBuyer$ = this.getBuyer({ processId }).pipe(
first(),
mergeMap((buyer) => this._setBuyer({ processId, buyer }))
);
const setPayer$ = this.getPayer({ processId }).pipe(
first(),
mergeMap((payer) => this._setPayer({ processId, payer }))
);
const checkAvailabilities$ = this.checkAvailabilities({ processId });
const updateAvailabilities$ = this.updateAvailabilities({ processId });
return refreshShoppingCart$.pipe(
mergeMap((_) => refreshCheckout$),
mergeMap((_) => checkAvailabilities$),
mergeMap((_) => updateAvailabilities$),
mergeMap((_) => setBuyer$),
mergeMap((_) => setPayer$),
mergeMap((checkout) =>
this.orderCheckoutService.OrderCheckoutCreateKulturPassOrder({
payload: {
checkoutId: checkout.id,
orderItemSubsetId: String(orderItemSubsetId),
},
})
)
.pipe(mergeMap((_) => completeOrder$.pipe(tap(console.log.bind(window, 'completeOrder$')))));
);
}
updateDestination({
@@ -920,6 +1198,5 @@ export class DomainCheckoutService {
private updateProcessCount(processId: number, count: number) {
this.applicationService.patchProcessData(processId, { count });
}
//#endregion
}

View File

@@ -1,4 +1,12 @@
import { BuyerDTO, CheckoutDTO, NotificationChannel, PayerDTO, ShippingAddressDTO, ShoppingCartDTO } from '@swagger/checkout';
import {
AvailabilityDTO,
BuyerDTO,
CheckoutDTO,
NotificationChannel,
PayerDTO,
ShippingAddressDTO,
ShoppingCartDTO,
} from '@swagger/checkout';
import { CustomerDTO } from '@swagger/crm';
import { DisplayOrderDTO } from '@swagger/oms';
@@ -14,4 +22,5 @@ export interface CheckoutEntity {
specialComment: string;
notificationChannels: NotificationChannel;
olaErrorIds: number[];
itemAvailabilityTimestamp: Record<string, number>;
}

View File

@@ -7,6 +7,7 @@ import {
ShippingAddressDTO,
BuyerDTO,
PayerDTO,
AvailabilityDTO,
} from '@swagger/checkout';
import { CustomerDTO } from '@swagger/crm';
import { DisplayOrderDTO, DisplayOrderItemDTO } from '@swagger/oms';
@@ -61,3 +62,13 @@ export const setSpecialComment = createAction(`${prefix} Set Agent Comment`, pro
export const setOlaError = createAction(`${prefix} Set Ola Error`, props<{ processId: number; olaErrorIds: number[] }>());
export const setCustomer = createAction(`${prefix} Set Customer`, props<{ processId: number; customer: CustomerDTO }>());
export const addShoppingCartItemAvailabilityToHistory = createAction(
`${prefix} Add Shopping Cart Item Availability To History`,
props<{ processId: number; shoppingCartItemId: number; availability: AvailabilityDTO }>()
);
export const addShoppingCartItemAvailabilityToHistoryByShoppingCartId = createAction(
`${prefix} Add Shopping Cart Item Availability To History By Shopping Cart Id`,
props<{ shoppingCartId: number; shoppingCartItemId: number; availability: AvailabilityDTO }>()
);

View File

@@ -10,7 +10,22 @@ const _domainCheckoutReducer = createReducer(
initialCheckoutState,
on(DomainCheckoutActions.setShoppingCart, (s, { processId, shoppingCart }) => {
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
const addedShoppingCartItems =
shoppingCart?.items?.filter((item) => !entity.shoppingCart?.items?.find((i) => i.id === item.id))?.map((item) => item.data) ?? [];
entity.shoppingCart = shoppingCart;
entity.itemAvailabilityTimestamp = entity.itemAvailabilityTimestamp ? { ...entity.itemAvailabilityTimestamp } : {};
const now = Date.now();
for (let shoppingCartItem of addedShoppingCartItems) {
if (shoppingCartItem.features?.orderType) {
entity.itemAvailabilityTimestamp[`${shoppingCartItem.id}_${shoppingCartItem.features.orderType}`] = now;
}
}
return storeCheckoutAdapter.setOne(entity, s);
}),
on(DomainCheckoutActions.setCheckout, (s, { processId, checkout }) => {
@@ -100,7 +115,40 @@ const _domainCheckoutReducer = createReducer(
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
entity.customer = customer;
return storeCheckoutAdapter.setOne(entity, s);
})
}),
on(DomainCheckoutActions.addShoppingCartItemAvailabilityToHistory, (s, { processId, shoppingCartItemId, availability }) => {
const entity = getOrCreateCheckoutEntity({ processId, entities: s.entities });
const itemAvailabilityTimestamp = entity?.itemAvailabilityTimestamp ? { ...entity?.itemAvailabilityTimestamp } : {};
const item = entity?.shoppingCart?.items?.find((i) => i.id === shoppingCartItemId)?.data;
if (!item?.features?.orderType) return s;
itemAvailabilityTimestamp[`${item.id}_${item?.features?.orderType}`] = Date.now();
entity.itemAvailabilityTimestamp = itemAvailabilityTimestamp;
return storeCheckoutAdapter.setOne(entity, s);
}),
on(
DomainCheckoutActions.addShoppingCartItemAvailabilityToHistoryByShoppingCartId,
(s, { shoppingCartId, shoppingCartItemId, availability }) => {
const entity = getCheckoutEntityByShoppingCartId({ shoppingCartId, entities: s.entities });
const itemAvailabilityTimestamp = entity?.itemAvailabilityTimestamp ? { ...entity?.itemAvailabilityTimestamp } : {};
const item = entity?.shoppingCart?.items?.find((i) => i.id === shoppingCartItemId)?.data;
if (!item?.features?.orderType) return s;
itemAvailabilityTimestamp[`${item.id}_${item?.features?.orderType}`] = Date.now();
entity.itemAvailabilityTimestamp = itemAvailabilityTimestamp;
return storeCheckoutAdapter.setOne(entity, s);
}
)
);
export function domainCheckoutReducer(state, action) {
@@ -123,8 +171,20 @@ function getOrCreateCheckoutEntity({ entities, processId }: { entities: Dictiona
notificationChannels: 0,
olaErrorIds: [],
customer: undefined,
// availabilityHistory: [],
itemAvailabilityTimestamp: {},
};
}
return { ...entity };
}
function getCheckoutEntityByShoppingCartId({
entities,
shoppingCartId,
}: {
entities: Dictionary<CheckoutEntity>;
shoppingCartId: number;
}): CheckoutEntity {
return Object.values(entities).find((entity) => entity.shoppingCart?.id === shoppingCartId);
}

View File

@@ -18,14 +18,15 @@ import {
NotificationChannel,
PayerDTO,
PayerService,
QueryTokenDTO,
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
ShippingAddressDTO,
ShippingAddressService,
} from '@swagger/crm';
import { isArray } from '@utils/common';
import { isArray, memorize } from '@utils/common';
import { PagedResult, Result } from 'apps/domain/defs/src/public-api';
import { Observable, of, ReplaySubject } from 'rxjs';
import { catchError, map, mergeMap, retry } from 'rxjs/operators';
import { catchError, map, mergeMap, retry, shareReplay } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class CrmCustomerService {
@@ -38,6 +39,14 @@ export class CrmCustomerService {
private loyaltyCardService: LoyaltyCardService
) {}
@memorize()
filterSettings() {
return this.customerService.CustomerCustomerQuerySettings().pipe(
map((res) => res.result),
shareReplay(1)
);
}
complete(queryString: string, filter?: { [key: string]: string }): Observable<Result<AutocompleteDTO[]>> {
return this.customerService.CustomerCustomerAutocomplete({
input: queryString,
@@ -66,6 +75,15 @@ export class CrmCustomerService {
});
}
getCustomersWithQueryToken(queryToken: QueryTokenDTO) {
if (queryToken.skip === undefined) queryToken.skip = 0;
if (queryToken.take === undefined) queryToken.take = 20;
if (queryToken.input === undefined) queryToken.input = { qs: '' };
if (queryToken.filter === undefined) queryToken.filter = {};
return this.customerService.CustomerListCustomers(queryToken);
}
getCustomersByCustomerCardNumber(queryString: string): Observable<PagedResult<CustomerInfoDTO>> {
return this.customerService.CustomerGetCustomerByBonuscard(!!queryString ? queryString : undefined);
}

View File

@@ -21,6 +21,7 @@ export class CollectOnDeliveryNoteActionHandler extends ActionHandler<OrderItems
const response = await this.orderService
.OrderCollectOnDeliveryNote({
data,
eagerLoading: 1,
})
.toPromise();
@@ -29,7 +30,7 @@ export class CollectOnDeliveryNoteActionHandler extends ActionHandler<OrderItems
return {
...context,
receipts: response.result,
receipts: response.result.map((r) => r.data),
};
}
}

View File

@@ -0,0 +1,35 @@
import { Injectable } from '@angular/core';
import { ActionHandler } from '@core/command';
import { OrderService } from '@swagger/oms';
import { OrderItemsContext } from './order-items.context';
@Injectable()
export class CollectWithSmallAmountinvoiceActionHandler extends ActionHandler<OrderItemsContext> {
constructor(private orderService: OrderService) {
super('COLLECT_WITH_SMALLAMOUNTINVOICE');
}
async handler(context: OrderItemsContext): Promise<OrderItemsContext> {
const data: Record<number, number> = {};
context.items.forEach((orderItemSubsetId) => {
data[orderItemSubsetId.orderItemSubsetId] =
context.itemQuantity?.get(orderItemSubsetId.orderItemSubsetId) ?? orderItemSubsetId.quantity;
});
const response = await this.orderService
.OrderCollectWithSmallAmountInvoice({
data,
eagerLoading: 1,
})
.toPromise();
// Für korrekte Navigation nach Aufruf, da ProcessingStatus Serverseitig auf abgeholt gesetzt wird
context.items?.forEach((i) => (i.processingStatus = 256));
return {
...context,
receipts: response.result.map((r) => r.data),
};
}
}

View File

@@ -1,4 +1,3 @@
// start:ng42.barrel
export * from './accepted.action-handler';
export * from './arrived.action-handler';
export * from './assembled.action-handler';
@@ -7,6 +6,10 @@ export * from './back-to-stock.action-handler';
export * from './canceled-by-buyer.action-handler';
export * from './canceled-by-retailer.action-handler';
export * from './canceled-by-supplier.action-handler';
export * from './change-order-item-status-base.action-handler';
export * from './collect-on-deliverynote.action-handler';
export * from './collect-with-smallamountinvoice.action-handler';
export * from './create-returnitem.action-handler';
export * from './create-shipping-note.action-handler';
export * from './delivered.action-handler';
export * from './determine-supplier.action-handler';
@@ -25,16 +28,15 @@ export * from './parked.action-handler';
export * from './placed.action-handler';
export * from './preperation-for-shipping.action-handler';
export * from './print-compartment-label.action-handler';
export * from './print-pricediffqrcodelabel.action-handler';
export * from './print-shipping-note.action-handler';
export * from './re-ordered.action-handler';
export * from './print-smallamountinvoice.action-handler';
export * from './re-order.action-handler';
export * from './re-ordered.action-handler';
export * from './redirected-internally.action-handler';
export * from './requested.action-handler';
export * from './reserved.action-handler';
export * from './returned-by-buyer.action-handler';
export * from './shipping-note.action-handler';
export * from './shop-with-kulturpass.action-handler';
export * from './supplier-temporarily-out-of-stock.action-handler copy';
export * from './collect-on-deliverynote.action-handler';
export * from './create-returnitem.action-handler';
export * from './print-pricediffqrcodelabel.action-handler';
// end:ng42.barrel

View File

@@ -1,4 +1,4 @@
import { OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
import { OrderItemListItemDTO, ReceiptDTO, OrderDTO } from '@swagger/oms';
export interface OrderItemsContext {
items: OrderItemListItemDTO[];
@@ -12,4 +12,6 @@ export interface OrderItemsContext {
receipts?: ReceiptDTO[];
shippingDelayComment?: string;
order?: OrderDTO;
}

View File

@@ -27,7 +27,8 @@ export class PrintShippingNoteActionHandler extends ActionHandler<OrderItemsCont
printerType: 'Label',
print: async (printer) => {
try {
for (const group of groupBy(data?.receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
const receipts = data?.receipts?.filter((r) => r?.receiptType & 1);
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
await this.domainPrinterService.printShippingNote({ printer, receipts: group?.items?.map((r) => r?.id) }).toPromise();
}
return {

View File

@@ -0,0 +1,56 @@
import { Injectable } from '@angular/core';
import { ActionHandler } from '@core/command';
import { OrderItemsContext } from './order-items.context';
import { OMSPrintService } from '@swagger/print';
import { UiModalService } from '@ui/modal';
import { PrintModalComponent, PrintModalData } from '@modal/printer';
import { NativeContainerService } from 'native-container';
import { groupBy } from '@ui/common';
@Injectable()
export class PrintSmallamountinvoiceActionHandler extends ActionHandler<OrderItemsContext> {
constructor(
private uiModal: UiModalService,
private omsPrintService: OMSPrintService,
private nativeContainerService: NativeContainerService
) {
super('PRINT_SMALLAMOUNTINVOICE');
}
async handler(data: OrderItemsContext): Promise<OrderItemsContext> {
await this.uiModal
.open({
content: PrintModalComponent,
config: { showScrollbarY: false },
data: {
printImmediately: !this.nativeContainerService.isNative,
printerType: 'Label',
print: async (printer) => {
try {
const receipts = data?.receipts?.filter((r) => r?.receiptType & 128);
for (const group of groupBy(receipts, (receipt) => receipt?.buyer?.buyerNumber)) {
await this.omsPrintService
.OMSPrintKleinbetragsrechnung({
data: group?.items?.map((r) => r?.id),
printer,
})
.toPromise();
}
return {
error: false,
};
} catch (error) {
console.error(error);
return {
error: true,
message: error?.message || error,
};
}
},
} as PrintModalData,
})
.afterClosed$.toPromise();
return data;
}
}

View File

@@ -5,7 +5,7 @@ import { UiModalService } from '@ui/modal';
import { ReorderModalComponent, ReorderResult } from '@modal/reorder';
import { DomainCheckoutService } from '@domain/checkout';
import { AvailabilityDTO2, OrderItemListItemDTO } from '@swagger/oms';
import { ToastService } from '@core/toast';
import { ToasterService } from '@shared/shell';
@Injectable()
export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
@@ -13,7 +13,7 @@ export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
private _command: CommandService,
private _domainCheckoutService: DomainCheckoutService,
private _uiModal: UiModalService,
private _toastService: ToastService
private _toastService: ToasterService
) {
super('REORDER');
}
@@ -71,8 +71,8 @@ export class ReOrderActionHandler extends ActionHandler<OrderItemsContext> {
case 'Falscher Titel geliefert (richtiges Etikett)':
break;
default:
this._toastService.create({
title: 'Artikel wurde nachbestellt',
this._toastService.open({
message: 'Artikel wurde nachbestellt',
});
}
}

View File

@@ -0,0 +1,82 @@
import { Injectable } from '@angular/core';
import { OrderItemsContext } from './order-items.context';
import { ActionHandler, CommandService } from '@core/command';
import { KulturpassOrderModalService } from '@shared/modals/kulturpass-order-modal';
import { DisplayOrderItemSubsetDTO, OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
import { DomainReceiptService } from '../receipt.service';
import { DomainGoodsService } from '../goods.service';
import { map } from 'rxjs/operators';
@Injectable()
export class ShopWithKulturpassActionHandler extends ActionHandler<OrderItemsContext> {
constructor(
private _modal: KulturpassOrderModalService,
private _receiptService: DomainReceiptService,
private _goodsService: DomainGoodsService
) {
super('SHOP_WITH_KULTURPASS');
}
async handler(data: OrderItemsContext, service: CommandService): Promise<OrderItemsContext> {
const items: OrderItemListItemDTO[] = [];
const receipts: ReceiptDTO[] = [];
let command: string;
for (const item of data.items) {
const result = await this._modal.open({ orderItemListItem: item, order: data.order }).afterClosed$.toPromise();
if (result.data == null) {
return data;
}
const displayOrder = result.data[0];
command = result.data[1];
if (displayOrder) {
const subsetItems = displayOrder.items.reduce((acc, item) => [...acc, ...item.subsetItems], [] as DisplayOrderItemSubsetDTO[]);
const orderItems = await this.getItems(displayOrder.orderNumber);
items.push(...orderItems);
const subsetItemIds = subsetItems.map((item) => item.id);
const r = await this.getReceipts(subsetItemIds);
receipts.push(...r);
}
}
if (!command) {
return {
...data,
items,
receipts,
};
} else {
return service.handleCommand(command, {
...data,
items,
receipts,
});
}
}
getReceipts(ids: number[]) {
return this._receiptService
.getReceipts({
receiptType: 128,
eagerLoading: 1,
ids,
})
.pipe(map((res) => res.result.map((data) => data.item3.data).filter((data) => !!data)))
.toPromise();
}
getItems(orderNumber: string) {
return this._goodsService
.getWarenausgabeItemByOrderNumber(orderNumber, false)
.pipe(map((res) => res.result))
.toPromise();
}
}

View File

@@ -1,5 +1,7 @@
import { Injectable } from '@angular/core';
import { AutocompleteTokenDTO, OrderService, QueryTokenDTO } from '@swagger/oms';
import { memorize } from '@utils/common';
import { map, shareReplay } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class DomainCustomerOrderService {
@@ -14,16 +16,18 @@ export class DomainCustomerOrderService {
// branch_id'
}
getOrderItemsByOrderNumber(orderNumber: string) {
getOrderItemsByOrderNumber(params: { compartmentCode?: string; orderId: number }) {
return this._orderService.OrderKundenbestellungen({
filter: { all_branches: 'true', archive: 'true' },
input: {
qs: orderNumber,
},
input: { order_id: String(params.orderId), compartment_code: params.compartmentCode },
});
}
@memorize()
settings() {
return this._orderService.OrderKundenbestellungenSettings();
return this._orderService.OrderKundenbestellungenSettings().pipe(
map((res) => res?.result),
shareReplay()
);
}
}

View File

@@ -1,6 +1,5 @@
import { Injectable } from '@angular/core';
import {
AutocompleteTokenDTO,
BranchService,
ChangeStockStatusCodeValues,
HistoryDTO,
@@ -11,9 +10,7 @@ import {
OrderItemSubsetDTO,
OrderListItemDTO,
OrderService,
QueryTokenDTO,
ReceiptService,
ResponseArgsOfIEnumerableOfHistoryDTO,
StatusValues,
StockStatusCodeService,
ValueTupleOfLongAndReceiptTypeAndEntityDTOContainerOfReceiptDTO,
@@ -22,7 +19,7 @@ import {
} from '@swagger/oms';
import { memorize } from '@utils/common';
import { Observable } from 'rxjs';
import { map, mergeMap, shareReplay } from 'rxjs/operators';
import { map, shareReplay } from 'rxjs/operators';
@Injectable()
export class DomainOmsService {
@@ -191,6 +188,10 @@ export class DomainOmsService {
);
}
getOrderSource(orderId: number): Observable<string> {
return this.getOrder(orderId).pipe(map((order) => order?.features?.orderSource));
}
updateNotifications(orderId: number, changes: { selected: NotificationChannel; email: string; mobile: string }) {
const communicationDetails = {
email: changes.email,

View File

@@ -0,0 +1,11 @@
import { PackageArrivalStatusDTO } from '@swagger/wws';
export abstract class PackageInspectionEvent {
constructor(public readonly type: string) {}
}
export class PackageStatusChangedEvent extends PackageInspectionEvent {
constructor(public readonly packageId: string, public readonly status: PackageArrivalStatusDTO) {
super('PackageStatusChangedEvent');
}
}

View File

@@ -1,10 +1,8 @@
import { Injectable } from '@angular/core';
import {
ListResponseArgsOfPackageDTO,
ListResponseArgsOfPackageDTO2,
PackageArrivalStatusDTO,
PackageDetailResponseDTO,
PackageDTO,
PackageDTO2,
QuerySettingsDTO,
QueryTokenDTO,
@@ -13,13 +11,18 @@ import {
ResponseArgsOfQuerySettingsDTO,
WareneingangService,
} from '@swagger/wws';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { PackageInspectionEvent, PackageStatusChangedEvent } from './events';
@Injectable({
providedIn: 'root',
})
export class DomainPackageInspectionService {
private _events = new Subject<PackageInspectionEvent>();
events = this._events.asObservable();
constructor(private _wareneingang: WareneingangService) {}
getQuerySettingsResponse(): Observable<ResponseArgsOfQuerySettingsDTO> {
@@ -47,23 +50,26 @@ export class DomainPackageInspectionService {
}
changePackageStatusResponse(pkg: PackageDTO2, modifier: string): Observable<ResponseArgsOfPackageArrivalStatusDTO> {
return this._wareneingang.WareneingangChangePackageStatus({
packageId: pkg.id,
payload: {
id: pkg.id,
annotation: pkg.annotation,
area: pkg.area,
arrivalChecked: pkg.arrivalChecked,
arrivalStatus: pkg.arrivalStatus,
deliveryNoteNumber: pkg.deliveryNoteNumber,
deliveryTarget: pkg.deliveryTarget,
estimatedDeliveryDate: pkg.estimatedDeliveryDate,
packageNumber: pkg.packageNumber,
supplier: pkg.supplier,
trackingNumber: pkg.trackingNumber,
},
modifier,
});
return this._wareneingang
.WareneingangChangePackageStatus({
packageId: pkg.id,
payload: {
id: pkg.id,
annotation: pkg.annotation,
area: pkg.area,
arrivalChecked: pkg.arrivalChecked,
arrivalStatus: pkg.arrivalStatus,
deliveryNoteNumber: pkg.deliveryNoteNumber,
deliveryTarget: pkg.deliveryTarget,
estimatedDeliveryDate: pkg.estimatedDeliveryDate,
packageNumber: pkg.packageNumber,
supplier: pkg.supplier,
trackingNumber: pkg.trackingNumber,
scanId: pkg.scanId,
},
modifier,
})
.pipe(tap((res) => this._events.next(new PackageStatusChangedEvent(pkg.id, res.result))));
}
changePackageStatus(pkg: PackageDTO2, modifier: string): Observable<PackageArrivalStatusDTO> {

View File

@@ -1,6 +1,6 @@
/*
* Public API Surface of package-inspection
*/
export * from './lib/events';
export * from './lib/package-inspection.service';
export * from './lib/package-inspection.module';

View File

@@ -447,7 +447,7 @@ export class DomainRemissionService {
* Create a new receipt for the given return/remission
* @param returnId Return ID
* @param receiptNumber Receipt number
* @returns ReturnDTO - ShippingDocument
* @returns ReceiptDTO
*/
async createReceipt(returnDTO: ReturnDTO, receiptNumber?: string): Promise<ReceiptDTO> {
const stock = await this._getStock();
@@ -471,14 +471,41 @@ export class DomainRemissionService {
return receipt;
}
async completeReceipt(returnId: number, receiptId: number, packageCode: string): Promise<ReceiptDTO> {
/**
* Create a new Package and assign it to a receipt
* @param returnId Return ID
* @param receiptId Receipt ID
* @param packageNumber Packagenumber
* @returns ReceiptDTO
*/
async createReceiptAndAssignPackage({
returnId,
receiptId,
packageNumber,
}: {
returnId: number;
receiptId: number;
packageNumber: string;
}): Promise<ReceiptDTO> {
const response = await this._returnService
.ReturnCreateAndAssignPackage({
returnId,
receiptId,
data: {
packageNumber,
},
})
.toPromise();
const receipt: ReceiptDTO = response.result;
return receipt;
}
async completeReceipt(returnId: number, receiptId: number): Promise<ReceiptDTO> {
const res = await this._returnService
.ReturnFinalizeReceipt({
returnId,
receiptId,
data: {
packageCode,
},
data: {},
})
.toPromise();

View File

@@ -1,4 +1,5 @@
// start:ng42.barrel
export * from './hub-notification.module';
export * from './notifications.hub';
export * from './defs';
// end:ng42.barrel

View File

@@ -4,61 +4,118 @@ import { SignalrHub, SignalRHubOptions } from '@core/signalr';
import { BehaviorSubject, merge, of } from 'rxjs';
import { filter, map, shareReplay, tap, withLatestFrom } from 'rxjs/operators';
import { EnvelopeDTO, MessageBoardItemDTO } from './defs';
import { cloneDeep } from 'lodash';
export const NOTIFICATIONS_HUB_OPTIONS = new InjectionToken<SignalRHubOptions>('hub.notifications.options');
@Injectable()
export class NotificationsHub extends SignalrHub {
updateNotification$ = new BehaviorSubject<MessageBoardItemDTO>(undefined);
get branchNo() {
return String(this._auth.getClaimByKey('branch_no') || this._auth.getClaimByKey('sub'));
}
// get sessionStoragesessionStorageKey() {
// return `NOTIFICATIONS_BOARD_${this.branchNo}`;
// }
get sessionStoragesessionStorageKey() {
return `NOTIFICATIONS_BOARD_${this.branchNo}`;
return `NOTIFICATIONS_BOARD_AREA_${this.branchNo}`;
}
messageBoardItems$ = new BehaviorSubject<Record<string, MessageBoardItemDTO[]>>({});
constructor(@Inject(NOTIFICATIONS_HUB_OPTIONS) options: SignalRHubOptions, private _auth: AuthService) {
super(options);
this.messageBoardItems$.next(this._getNotifications());
this.messageBoardItems$.subscribe((data) => {
this._storeNotifactions(data);
});
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard').subscribe((envelope) => {
if (envelope.action === 'refresh') {
this.refreshMessageBoardItems(envelope.target.area, envelope.data);
}
});
}
notifications$ = merge(
of(this._getNotifications()).pipe(filter((f) => !!f)),
this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
).pipe(
withLatestFrom(this.updateNotification$),
map(([d, update]) => {
const data = d;
if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
data.data.push(update);
refreshMessageBoardItems(targetArea: string, messages: MessageBoardItemDTO[]) {
const current = cloneDeep(this.messageBoardItems$.value);
current[targetArea] = messages ?? [];
this.messageBoardItems$.next(current);
}
notifications$ = this.messageBoardItems$.asObservable().pipe(
map((data) => {
const messages = { ...data };
const keys = Object.keys(data);
for (let key of keys) {
if (data[key].length === 0 || data[key] === undefined) {
delete messages[key];
}
}
return data;
}),
tap((data) => this._storeNotifactions(data)),
shareReplay(1)
return messages;
})
);
private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
if (data) {
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
}
}
// notifications$ = merge(
// of(this._getNotifications()).pipe(filter((f) => !!f)),
// this.listen<EnvelopeDTO<MessageBoardItemDTO[]>>('messageBoard')
// ).pipe(
// withLatestFrom(this.updateNotification$),
// map(([d, update]) => {
// console.log('notifications$', d, update);
// const data = d;
// if (update && !!data && !data?.data?.find((message) => message?.category === 'ISA-Update')) {
// data.data.push(update);
// }
// return data;
// }),
// tap((data) => this._storeNotifactions(data)),
// shareReplay(1)
// );
private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
// private _storeNotifactions(data: EnvelopeDTO<MessageBoardItemDTO[]>) {
// if (data) {
// sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
// }
// }
// private _getNotifications(): EnvelopeDTO<MessageBoardItemDTO[]> {
// const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
// if (stringData) {
// return JSON.parse(stringData);
// }
// return undefined;
// }
private _getNotifications(): Record<string, MessageBoardItemDTO[]> {
const stringData = sessionStorage.getItem(this.sessionStoragesessionStorageKey);
if (stringData) {
return JSON.parse(stringData);
}
return undefined;
return {};
}
private _storeNotifactions(data: Record<string, MessageBoardItemDTO[]>) {
if (data) {
delete data['messageBoard/isa-update'];
sessionStorage.setItem(this.sessionStoragesessionStorageKey, JSON.stringify(data));
}
}
updateNotification() {
this.updateNotification$.next({
category: 'ISA-Update',
type: 'update',
headline: 'Update Benachrichtigung',
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
});
this.refreshMessageBoardItems('messageBoard/isa-update', [
{
category: 'ISA-Update',
type: 'update',
headline: 'Update Benachrichtigung',
text: 'Es steht eine aktuellere Version der ISA bereit. Bitte aktualisieren Sie die Anwendung.',
},
]);
}
}

View File

@@ -1,10 +1,11 @@
import { isDevMode, NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DebugComponent } from './debug/debug.component';
import {
CanActivateCartGuard,
CanActivateCartWithProcessIdGuard,
CanActivateCustomerGuard,
CanActivateCustomerOrdersGuard,
CanActivateCustomerOrdersWithProcessIdGuard,
CanActivateCustomerWithProcessIdGuard,
CanActivateGoodsInGuard,
CanActivateGoodsOutGuard,
@@ -17,9 +18,9 @@ import {
} from './guards';
import { CanActivateAssortmentGuard } from './guards/can-activate-assortment.guard';
import { CanActivatePackageInspectionGuard } from './guards/can-activate-package-inspection.guard';
import { MainComponent } from './main.component';
import { PreviewComponent } from './preview';
import { BranchSectionResolver, CustomerSectionResolver, ProcessIdResolver } from './resolvers';
import { ShellComponent, ShellModule } from './shell';
import { TokenLoginComponent, TokenLoginModule } from './token-login';
const routes: Routes = [
@@ -40,7 +41,7 @@ const routes: Routes = [
children: [
{
path: 'kunde',
component: ShellComponent,
component: MainComponent,
children: [
{
path: 'dashboard',
@@ -60,22 +61,22 @@ const routes: Routes = [
{
path: 'order',
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
canActivate: [CanActivateGoodsOutGuard],
canActivate: [CanActivateCustomerOrdersGuard],
},
{
path: ':processId/order',
loadChildren: () => import('@page/customer-order').then((m) => m.CustomerOrderModule),
canActivate: [CanActivateGoodsOutWithProcessIdGuard],
canActivate: [CanActivateCustomerOrdersWithProcessIdGuard],
resolve: { processId: ProcessIdResolver },
},
{
path: 'customer',
loadChildren: () => import('@page/customer').then((m) => m.PageCustomerModule),
loadChildren: () => import('@page/customer-rd').then((m) => m.CustomerModule),
canActivate: [CanActivateCustomerGuard],
},
{
path: ':processId/customer',
loadChildren: () => import('@page/customer').then((m) => m.PageCustomerModule),
loadChildren: () => import('@page/customer-rd').then((m) => m.CustomerModule),
canActivate: [CanActivateCustomerWithProcessIdGuard],
resolve: { processId: ProcessIdResolver },
},
@@ -106,7 +107,7 @@ const routes: Routes = [
},
{
path: 'filiale',
component: ShellComponent,
component: MainComponent,
children: [
{
path: 'task-calendar',
@@ -152,7 +153,7 @@ if (isDevMode()) {
}
@NgModule({
imports: [RouterModule.forRoot(routes), ShellModule, TokenLoginModule],
imports: [RouterModule.forRoot(routes), TokenLoginModule],
exports: [RouterModule],
})
export class AppRoutingModule {}

View File

@@ -1,7 +1,3 @@
:host {
@apply block box-border;
}
button {
@apply fixed bottom-4 right-2 bg-blue-500 text-white font-bold py-2 px-4 rounded z-tooltip;
@apply block;
}

View File

@@ -116,6 +116,7 @@ export class AppComponent implements OnInit {
checkForUpdate() {
interval(this._checkForUpdates).subscribe(() => {
this._swUpdate.checkForUpdate().then((value) => {
console.log('check for update', value);
if (value) {
this._notifications.updateNotification();
}
@@ -125,6 +126,7 @@ export class AppComponent implements OnInit {
initialCheckForUpdate() {
this._swUpdate.checkForUpdate().then((value) => {
console.log('initial check for update', value);
if (value) {
location.reload();
}

View File

@@ -32,9 +32,11 @@ import { IsaErrorHandler } from './providers/isa.error-handler';
import { ScanAdapterModule, ScanAdapterService, ScanditScanAdapterModule } from '@adapter/scan';
import { RootStateService } from './store/root-state.service';
import * as Commands from './commands';
import { UiIconModule } from '@ui/icon';
import { PreviewComponent } from './preview';
import { NativeContainerService } from 'native-container';
import { ShellModule } from '@shared/shell';
import { MainComponent } from './main.component';
import { IconModule } from '@shared/components/icon';
registerLocaleData(localeDe, localeDeExtra);
registerLocaleData(localeDe, 'de', localeDeExtra);
@@ -74,11 +76,12 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
}
@NgModule({
declarations: [AppComponent],
declarations: [AppComponent, MainComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
ShellModule.forRoot(),
AppRoutingModule,
AppSwaggerModule,
AppDomainModule,
@@ -103,12 +106,7 @@ export function _notificationsHubOptionsFactory(config: Config, auth: AuthServic
ScanAdapterModule.forRoot(),
ScanditScanAdapterModule.forRoot(),
PlatformModule,
UiIconModule.forRoot({
aliases: [
{ alias: 'd-account', name: 'account' },
{ alias: 'd-no-account', name: 'package-variant-closed' },
],
}),
IconModule.forRoot(),
],
providers: [
{

View File

@@ -1,11 +1,12 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { ApplicationService } from '@core/application';
import { CheckoutNavigationService } from '@shared/services';
import { first } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class CanActivateCartGuard implements CanActivate {
constructor(private readonly _applicationService: ApplicationService, private readonly _router: Router) {}
constructor(private readonly _applicationService: ApplicationService, private _checkoutNavigationService: CheckoutNavigationService) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
@@ -21,7 +22,7 @@ export class CanActivateCartGuard implements CanActivate {
name: `Vorgang ${processes.length + 1}`,
});
}
await this._router.navigate(['/kunde', lastActivatedProcessId, 'cart']);
await this._checkoutNavigationService.navigateToCheckoutReview({ processId: lastActivatedProcessId });
return false;
}
}

View File

@@ -0,0 +1,51 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { first } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class CanActivateCustomerOrdersWithProcessIdGuard implements CanActivate {
constructor(private readonly _applicationService: ApplicationService, private readonly _breadcrumbService: BreadcrumbService) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const process = await this._applicationService
.getProcessById$(+route.params.processId)
.pipe(first())
.toPromise();
if (!process) {
await this._applicationService.createProcess({
id: +route.params.processId,
type: 'customer-order',
section: 'customer',
name: `Kundenbestellungen`,
});
}
await this.removeBreadcrumbWithSameProcessId(route);
this._applicationService.activateProcess(+route.params.processId);
return true;
}
// Fix #3292: Alle Breadcrumbs die nichts mit dem aktuellen Prozess zu tun haben, müssen removed werden
async removeBreadcrumbWithSameProcessId(route: ActivatedRouteSnapshot) {
const crumbs = await this._breadcrumbService
.getBreadcrumbByKey$(+route.params.processId)
.pipe(first())
.toPromise();
// Entferne alle Crumbs die nichts mit den Kundenbestellungen zu tun haben
if (crumbs.length > 1) {
const crumbsToRemove = crumbs.filter((crumb) => crumb.tags.find((tag) => tag === 'customer-order') === undefined);
for (const crumb of crumbsToRemove) {
await this._breadcrumbService.removeBreadcrumb(crumb.id);
}
}
}
processNumber(processes: ApplicationProcess[]) {
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
return !!processNumbers && processNumbers?.length > 0 ? Math.max(...processNumbers) + 1 : 1;
}
}

View File

@@ -0,0 +1,97 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { DomainCheckoutService } from '@domain/checkout';
import { CustomerOrdersNavigationService } from '@shared/services';
import { first } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class CanActivateCustomerOrdersGuard implements CanActivate {
constructor(
private readonly _applicationService: ApplicationService,
private readonly _checkoutService: DomainCheckoutService,
private readonly _navigationService: CustomerOrdersNavigationService
) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const processes = await this._applicationService.getProcesses$('customer').pipe(first()).toPromise();
let lastActivatedProcessId = (
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart').pipe(first()).toPromise()
)?.id;
const lastActivatedCartCheckoutProcessId = (
await this._applicationService.getLastActivatedProcessWithSectionAndType$('customer', 'cart-checkout').pipe(first()).toPromise()
)?.id;
const activatedProcessId = await this._applicationService.getActivatedProcessId$().pipe(first()).toPromise();
// Darf nur reinkommen wenn der aktuell aktive Tab ein Bestellabschluss Tab ist
if (!!lastActivatedCartCheckoutProcessId && lastActivatedCartCheckoutProcessId === activatedProcessId) {
await this.fromCartCheckoutProcess(processes, route, lastActivatedCartCheckoutProcessId);
return false;
}
if (!lastActivatedProcessId) {
await this.fromGoodsOutProcess(processes, route);
return false;
} else {
await this._navigationService.navigateToCustomerOrdersSearch({ processId: lastActivatedProcessId });
}
return false;
}
// Bei offenen Kundenbestellungen und Klick auf Kundenbestellungen
async fromGoodsOutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
const newProcessId = Date.now();
await this._applicationService.createProcess({
id: newProcessId,
type: 'cart',
section: 'customer',
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
});
await this._navigationService.navigateToCustomerOrdersSearch({ processId: newProcessId });
}
// Bei offener Bestellbestätigung und Klick auf Kundenbestellungen
async fromCartCheckoutProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot, processId: number) {
// Um alle Checkout Daten zu resetten die mit dem Prozess assoziiert sind
this._checkoutService.removeProcess({ processId });
// Ändere type cart-checkout zu customer-order
this._applicationService.patchProcess(processId, {
id: processId,
type: 'cart',
section: 'customer',
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
data: {},
});
// Navigation
await this._navigationService.navigateToCustomerOrdersSearch({ processId });
}
getUrlFromSnapshot(route: ActivatedRouteSnapshot, url: string[] = []): string[] {
url.push(...route.url.map((segment) => segment.path));
if (route.firstChild) {
return this.getUrlFromSnapshot(route.firstChild, url);
}
return url.filter((segment) => !!segment);
}
processNumber(processes: ApplicationProcess[]) {
const processNumbers = processes?.map((process) => Number(process?.name?.replace(/\D/g, '')));
return !!processNumbers && processNumbers.length > 0 ? this.findMissingNumber(processNumbers) : 1;
}
findMissingNumber(processNumbers: number[]) {
for (let missingNumber = 1; missingNumber < Math.max(...processNumbers); missingNumber++) {
if (!processNumbers.find((number) => number === missingNumber)) {
return missingNumber;
}
}
return Math.max(...processNumbers) + 1;
}
}

View File

@@ -1,7 +1,8 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { DomainCheckoutService } from '@domain/checkout';
import { ProductCatalogNavigationService } from '@shared/services';
import { first } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
@@ -9,7 +10,7 @@ export class CanActivateProductGuard implements CanActivate {
constructor(
private readonly _applicationService: ApplicationService,
private readonly _checkoutService: DomainCheckoutService,
private readonly _router: Router
private readonly _navigationService: ProductCatalogNavigationService
) {}
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
@@ -38,17 +39,17 @@ export class CanActivateProductGuard implements CanActivate {
}
if (!lastActivatedProcessId) {
await this.fromCartProcess(processes, route);
await this.fromCartProcess(processes);
return false;
} else {
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(lastActivatedProcessId)]));
await this._navigationService.navigateToProductSearch({ processId: lastActivatedProcessId });
}
return false;
}
// Bei offener Artikelsuche/Kundensuche und Klick auf Footer Artikelsuche
async fromCartProcess(processes: ApplicationProcess[], route: ActivatedRouteSnapshot) {
async fromCartProcess(processes: ApplicationProcess[]) {
const newProcessId = Date.now();
await this._applicationService.createProcess({
id: newProcessId,
@@ -57,7 +58,7 @@ export class CanActivateProductGuard implements CanActivate {
name: `Vorgang ${this.processNumber(processes.filter((process) => process.type === 'cart'))}`,
});
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(newProcessId)]));
await this._navigationService.navigateToProductSearch({ processId: newProcessId });
}
// Bei offener Warenausgabe und Klick auf Footer Artikelsuche
@@ -81,7 +82,7 @@ export class CanActivateProductGuard implements CanActivate {
});
// Navigation
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
await this._navigationService.navigateToProductSearch({ processId });
}
// Bei offener Bestellbestätigung und Klick auf Footer Artikelsuche
@@ -99,7 +100,7 @@ export class CanActivateProductGuard implements CanActivate {
});
// Navigation
await this._router.navigate(this.getUrlFromSnapshot(route, ['/kunde', String(processId)]));
await this._navigationService.navigateToProductSearch({ processId });
}
getUrlFromSnapshot(route: ActivatedRouteSnapshot, url: string[] = []): string[] {

View File

@@ -5,6 +5,8 @@ export * from './can-activate-customer.guard';
export * from './can-activate-goods-in.guard';
export * from './can-activate-goods-out-with-process-id.guard';
export * from './can-activate-goods-out.guard';
export * from './can-activate-customer-orders.guard';
export * from './can-activate-customer-orders-with-process-id.guard';
export * from './can-activate-product-with-process-id.guard';
export * from './can-activate-product.guard';
export * from './can-activate-remission.guard';

View File

@@ -52,11 +52,7 @@ export class IsAuthenticatedGuard implements CanActivate {
return undefined;
}
const result = await this._scanService
.scan({
exclude: ['Dev'],
})
?.toPromise();
const result = await this._scanService.scan()?.toPromise();
if (typeof result === 'string') {
try {

View File

@@ -0,0 +1,3 @@
<shell-root>
<router-outlet></router-outlet>
</shell-root>

View File

@@ -0,0 +1,10 @@
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-main',
templateUrl: 'main.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MainComponent {
constructor() {}
}

View File

@@ -1,4 +0,0 @@
// start:ng42.barrel
export * from './shell.component';
export * from './shell.module';
// end:ng42.barrel

View File

@@ -1,88 +0,0 @@
<div class="shell-header-wrapper">
<shell-header [section]="section$ | async" (sectionChange)="setSection($event)">
<a [routerLink]="['/kunde/dashboard']" routerLinkActive="active" class="dashboard-btn">
<ui-icon icon="dashboard" size="26px"></ui-icon>
</a>
<button class="notifications-btn" [disabled]="(notificationCount$ | async) === 0" (click)="openNotifications()">
<ui-icon icon="notification" size="26px"></ui-icon>
<span class="notification-counter" *ngIf="notificationCount$ | async; let count">{{ count }}</span>
</button>
<button (click)="logout()" class="logout-btn">
<span *ngIf="currentBranch$ | async; let currentBranch">{{ currentBranch.key | uppercase }}</span>
<ui-icon icon="logout" size="26px"></ui-icon>
</button>
</shell-header>
</div>
<div class="shell-process-wrapper">
<shell-process
[label]="addProcessLabel$ | async"
[canAddProcess]="canAddProcess$ | async"
(addProcess)="addProcess(); processTabs?.last?.triggerAnimation()"
>
<shell-process-tab
#processTabs
(activateProcess)="activateProcess($event)"
(closeProcess)="closeProcess($event)"
(processAction)="processAction($event)"
*ngFor="let process of processes$ | async; trackBy: trackByIdFn"
[isActive]="(activatedProcessId$ | async) === process.id"
[process]="process"
></shell-process-tab>
</shell-process>
</div>
<div class="main-wrapper">
<main>
<router-outlet></router-outlet>
</main>
</div>
<div class="shell-footer-wrapper">
<shell-footer *ngIf="section$ | async; let section">
<ng-container *ngIf="section === 'customer'">
<a [routerLink]="[customerBasePath$ | async, 'product']" routerLinkActive="active">
<ui-icon icon="catalog" size="30px"></ui-icon>
Artikelsuche
</a>
<a [routerLink]="[customerBasePath$ | async, 'customer']" routerLinkActive="active">
<ui-icon icon="customer" size="24px"></ui-icon>
Kundensuche
</a>
<a *ifRole="'Store'" [routerLink]="[customerBasePath$ | async, 'goods', 'out']" routerLinkActive="active">
<ui-icon icon="box_out" size="24px"></ui-icon>
Warenausgabe
</a>
<a *ifRole="'CallCenter'" [routerLink]="[customerBasePath$ | async, 'order']" routerLinkActive="active">
<ui-svg-icon icon="package-variant-closed" [size]="28"></ui-svg-icon>
Kundenbestellungen
</a>
</ng-container>
<ng-container *ngIf="section === 'branch'">
<a [routerLink]="['/filiale/assortment']" routerLinkActive="active">
<ui-svg-icon icon="shape-outline" [size]="24"></ui-svg-icon>
Sortiment
</a>
<a [routerLink]="['/filiale/task-calendar']" routerLinkActive="active">
<ui-icon icon="calendar_check" size="24px"></ui-icon>
Tätigkeitskalender
</a>
<a [routerLink]="['/filiale/goods/in']" routerLinkActive="active">
<ui-icon icon="box_return" size="24px"></ui-icon>
Abholfach
</a>
<a [routerLink]="[remissionUrl$ | async]" [queryParams]="remissionQueryParams$ | async" routerLinkActive="active">
<ui-icon icon="documents_refresh" size="24px"></ui-icon>
Remission
</a>
<!-- <a [routerLink]="['/filiale/package-inspection']" routerLinkActive="active" (click)="fetchAndOpenPackages()">
<ui-svg-icon icon="clipboard-check-outline" [size]="24"></ui-svg-icon>
Wareneingang
</a> -->
</ng-container>
</shell-footer>
</div>
<button *ngIf="isDevelopment" class="block absolute bottom-0 right-0 z-tooltip p-4 opacity-5" (click)="debugOpen = !debugOpen">
<ui-svg-icon icon="bug-outline"></ui-svg-icon>
</button>
<app-debug *ngIf="debugOpen" class="absolute inset-x-0 top-0 max-h-[calc(100vh-80px)]"></app-debug>

View File

@@ -1,60 +0,0 @@
:host {
@apply block relative min-h-screen;
}
.main-wrapper {
@apply fixed right-0 left-0 overflow-auto;
top: 8.375rem;
bottom: 5rem;
main {
@apply w-full max-w-content mx-auto px-4 self-stretch;
}
}
.shell-header-wrapper {
@apply fixed top-0 left-0 right-0 bg-white;
shell-header {
@apply w-full max-w-content mx-auto;
}
button.notifications-btn {
@apply relative;
.notification-counter {
@apply absolute flex items-center justify-center top-2 right-px-3 text-sm rounded-full w-6 h-6 font-semibold;
background-color: var(--shell-notification-counter-background);
color: var(--shell-notification-counter-text);
z-index: 10;
}
}
}
.shell-process-wrapper {
@apply fixed left-0 right-0 bg-white;
top: 5.125rem;
shell-process {
@apply w-full max-w-content mx-auto;
height: 52px;
}
}
shell-process {
height: 52px;
grid-area: process;
}
.shell-footer-wrapper {
@apply fixed bottom-0 left-0 right-0 bg-white z-fixed shadow-card;
shell-footer {
@apply w-full max-w-content mx-auto;
.active {
@apply font-bold;
color: var(--shell-footer-link-active);
}
}
}

View File

@@ -1,445 +0,0 @@
// unit test ShellComponent with Spectator
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { AuthModule, AuthService } from '@core/auth';
import { Config } from '@core/config';
import { BreadcrumbService } from '@core/breadcrumb';
import { DomainAvailabilityService } from '@domain/availability';
import { DomainDashboardService } from '@domain/isa';
import { NotificationsHub } from '@hub/notifications';
import { ModalNotificationsComponent } from '@modal/notifications';
import { Spectator, createComponentFactory, SpyObject, createSpyObject } from '@ngneat/spectator';
import { DashboardComponent } from '@page/dashboard';
import { ShellFooterComponent } from '@shell/footer';
import { ShellHeaderComponent } from '@shell/header';
import { ShellProcessComponent, ShellProcessTabComponent } from '@shell/process';
import { IconRegistry, UiIconComponent, UiIconModule } from '@ui/icon';
import { UiModalService } from '@ui/modal';
import { EnvelopeDTO, MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
import { MockComponent } from 'ng-mocks';
import { of } from 'rxjs';
import { first } from 'rxjs/operators';
import { ShellComponent } from './shell.component';
import { WrongDestinationModalService } from 'apps/page/package-inspection/src/lib/components/wrong-destination-modal/wrong-destination-modal.service';
// DummyComponent Class
@Component({
selector: 'dummy-component',
template: '<div></div>',
})
class DummyComponent {
constructor() {}
}
describe('ShellComponent', () => {
let spectator: Spectator<ShellComponent>;
let applicationServiceMock: SpyObject<ApplicationService>;
let modalServiceMock: SpyObject<UiModalService>;
let notificationsHubMock: SpyObject<NotificationsHub>;
let router: Router;
let breadcrumbServiceMock: SpyObject<BreadcrumbService>;
let authServiceMock: SpyObject<AuthService>;
const createComponent = createComponentFactory({
component: ShellComponent,
imports: [
UiIconModule,
RouterTestingModule.withRoutes([
{ path: 'kunde', component: DummyComponent },
{ path: 'kunde/dashboard', component: DashboardComponent },
]),
AuthModule,
],
declarations: [
MockComponent(ShellHeaderComponent),
MockComponent(ShellFooterComponent),
MockComponent(ShellProcessComponent),
MockComponent(ShellProcessTabComponent),
],
mocks: [
BreadcrumbService,
DomainAvailabilityService,
AuthService,
DomainDashboardService,
Config,
WrongDestinationModalService,
IconRegistry,
],
});
beforeEach(() => {
applicationServiceMock = createSpyObject(ApplicationService);
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of([]));
applicationServiceMock.getProcessById$.and.returnValue(of({ id: 4000 }));
applicationServiceMock.getActivatedProcessId$.and.returnValue(of(undefined));
applicationServiceMock.getLastActivatedProcessWithSectionAndType$.and.returnValue(of({}));
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({}));
notificationsHubMock = createSpyObject(NotificationsHub);
notificationsHubMock.notifications$ = of({});
modalServiceMock = createSpyObject(UiModalService);
authServiceMock = createSpyObject(AuthService);
spectator = createComponent({
providers: [
{ provide: ApplicationService, useValue: applicationServiceMock },
{ provide: NotificationsHub, useValue: notificationsHubMock },
{ provide: UiModalService, useValue: modalServiceMock },
{ provide: AuthService, useValue: authServiceMock },
],
});
breadcrumbServiceMock = spectator.inject(BreadcrumbService);
router = spectator.inject(Router);
});
it('should create', () => {
expect(spectator.component).toBeTruthy();
});
describe('shell-header', () => {
it('should call setSection() on sectionChange event with the section argument', () => {
spyOn(spectator.component, 'setSection');
spectator.triggerEventHandler('shell-header', 'sectionChange', 'branch');
expect(spectator.component.setSection).toHaveBeenCalledWith('branch');
});
it('should render the header buttons', () => {
// Test verhält sich anders, wenn die größe des Browserfensters kleiner ist als 640px, da
// die Buttons dann unsichtbar werden und ins Drei-Punkt Menü verschoben werden.
if (document.body.clientWidth > 639) {
expect(spectator.query('shell-header .notifications-btn')).toBeVisible();
expect(spectator.query('shell-header .dashboard-btn')).toBeVisible();
expect(spectator.query('shell-header .logout-btn')).toBeVisible();
} else {
expect(spectator.query('shell-header .notifications-btn')).not.toBeVisible();
expect(spectator.query('shell-header .dashboard-btn')).not.toBeVisible();
expect(spectator.query('shell-header .logout-btn')).not.toBeVisible();
}
});
it('should have a anchor tag which navigates to /kunde/dashboard', () => {
const anchor = spectator.query('shell-header a');
expect(anchor).toHaveAttribute('href', '/kunde/dashboard');
});
});
describe('shell-process', () => {
it('should call addProcess() on addProcess event', () => {
spyOn(spectator.component, 'addProcess');
spectator.triggerEventHandler('shell-process', 'addProcess', undefined);
expect(spectator.component.addProcess).toHaveBeenCalled();
});
describe('shell-process-tab', () => {
it('should render for each process', () => {
const processes = [{}, {}, {}];
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
spectator.detectComponentChanges();
expect(spectator.queryAll('shell-process-tab')).toHaveLength(processes.length);
});
it('should call activateProcess() on activateProcess event', () => {
const processes = [{ id: 1 }];
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
spectator.detectComponentChanges();
spyOn(spectator.component, 'activateProcess');
spectator.triggerEventHandler('shell-process-tab', 'activateProcess', processes[0].id);
expect(spectator.component.activateProcess).toHaveBeenCalledWith(1);
});
it('should call closeProcess() on closeProcess event', () => {
const processes = [{ id: 1 }];
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
spectator.detectComponentChanges();
spyOn(spectator.component, 'closeProcess');
spectator.triggerEventHandler('shell-process-tab', 'closeProcess', processes[0].id);
expect(spectator.component.closeProcess).toHaveBeenCalledWith(1);
});
});
});
describe('shell-footer', () => {
it('should render when section is set', () => {
applicationServiceMock.getSection$.and.returnValue(of('customer'));
spectator.detectComponentChanges();
expect(spectator.query('shell-footer')).toBeVisible();
});
it('should not render when section is undefined', () => {
applicationServiceMock.getSection$.and.returnValue(of(undefined));
spectator.detectComponentChanges();
expect(spectator.query('shell-footer')).not.toBeVisible();
});
xit('should display the menu items for section customer', () => {
applicationServiceMock.getSection$.and.returnValue(of('customer'));
spectator.component.customerBasePath$ = of('/kunde/1');
spectator.detectComponentChanges();
authServiceMock.hasRole.and.returnValue(true);
const anchors = spectator.queryAll('shell-footer a');
expect(anchors[0]).toHaveText('Artikelsuche');
expect(anchors[0]).toHaveAttribute('href', '/kunde/1/product');
expect(anchors[1]).toHaveText('Kundensuche');
expect(anchors[1]).toHaveAttribute('href', '/kunde/1/customer');
expect(anchors[2]).toHaveText('Warenausgabe');
expect(anchors[2]).toHaveAttribute('href', '/kunde/1/goods/out');
});
it('should display the menu items for section branch', () => {
applicationServiceMock.getSection$.and.returnValue(of('branch'));
spectator.detectComponentChanges();
const anchors = spectator.queryAll('shell-footer a');
expect(anchors[0]).toHaveText('Sortiment');
expect(anchors[0]).toHaveAttribute('href', '/filiale/assortment');
expect(anchors[1]).toHaveText('Tätigkeitskalender');
expect(anchors[1]).toHaveAttribute('href', '/filiale/task-calendar');
expect(anchors[2]).toHaveText('Abholfach');
expect(anchors[2]).toHaveAttribute('href', '/filiale/goods/in');
expect(anchors[3]).toHaveText('Remission');
expect(anchors[3]).toHaveAttribute('href', '/filiale/remission');
// expect(anchors[4]).toHaveText('Wareneingang');
// expect(anchors[4]).toHaveAttribute('href', '/filiale/package-inspection');
});
});
describe('activatedProcessId$', () => {
it('should call _appService.getActivatedProcessId$() and return its value', async () => {
applicationServiceMock.getActivatedProcessId$.and.returnValue(of(1));
const processId = await spectator.component.activatedProcessId$.pipe(first()).toPromise();
expect(processId).toBe(1);
expect(applicationServiceMock.getActivatedProcessId$).toHaveBeenCalled();
});
});
describe('section$', () => {
it('should call _appService.getSection$() and return its value', async () => {
applicationServiceMock.getSection$.and.returnValue(of('branch'));
const section = await spectator.component.section$.pipe(first()).toPromise();
expect(section).toBe('branch');
expect(applicationServiceMock.getSection$).toHaveBeenCalled();
});
});
describe('processes$', () => {
it('should call _appService.processes$() and return its value', async () => {
applicationServiceMock.getProcesses$.and.returnValue(of([{}, {}]));
const processes = await spectator.component.processes$.pipe(first()).toPromise();
expect(processes).toHaveLength(2);
expect(applicationServiceMock.getProcesses$).toHaveBeenCalledWith('customer');
});
});
describe('remissionProcess$', () => {
it('should call _appService.getProcessById$() with Remission Id and return its value', async () => {
applicationServiceMock.getProcessById$.and.returnValue(of({ id: 4000 }));
await spectator.component.remissionProcess$.pipe(first()).toPromise();
expect(applicationServiceMock.getProcessById$).toHaveBeenCalled();
});
});
describe('remissionUrl$', () => {
it('should return the correct url if process.data.active is available', async () => {
const process = {
id: 4000,
data: {
active: 9999,
},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const url = await spectator.component.remissionUrl$.pipe(first()).toPromise();
expect(url).toBe('/filiale/remission/9999/list');
});
it('should return the correct url if process.data.active is not available', async () => {
const process = {
id: 4000,
data: {},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const url = await spectator.component.remissionUrl$.pipe(first()).toPromise();
expect(url).toBe('/filiale/remission');
});
});
describe('remissionQueryParams$', () => {
it('should return the correct queryParams if process.data.active and process.data.queryParams are available', async () => {
const process = {
id: 4000,
data: {
active: 9999,
queryParams: { filter: 'test' },
},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const queryParams = await spectator.component.remissionQueryParams$.pipe(first()).toPromise();
expect(queryParams).toEqual(process.data.queryParams);
});
it('should return the correct queryParams if process.data.active and process.data.queryParams are not available', async () => {
const process = {
id: 4000,
data: {},
};
applicationServiceMock.getProcessById$.and.returnValue(of(process));
const queryParams = await spectator.component.remissionQueryParams$.pipe(first()).toPromise();
expect(queryParams).toEqual({});
});
});
describe('setSection()', () => {
it('should call _appService.setSection() with the argument section', async () => {
await spectator.component.setSection('customer');
expect(applicationServiceMock.setSection).toHaveBeenCalledWith('customer');
});
it('should call activateProcess if getLastActivatedProcessWithSection returns a value', async () => {
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({ id: 1 }));
spyOn(spectator.component, 'activateProcess');
await spectator.component.setSection('customer');
expect(spectator.component.activateProcess).toHaveBeenCalledWith(1);
});
});
describe('logout()', () => {
it('should call _authService.logout()', () => {
spectator.component.logout();
expect(authServiceMock.logout).toHaveBeenCalled();
});
});
describe('addProcess()', () => {
it('should call navigate to /kunde/{timestamp}/product', () => {
spyOn(router, 'navigate');
spyOn(Date, 'now').and.returnValue(123);
spectator.component.addProcess();
expect(router.navigate).toHaveBeenCalledWith(['/kunde', 123, 'product']);
});
});
describe('closeProcess()', () => {
it('should call _appService.removeProcess() with the processId argument', () => {
const processes = [{}, {}, {}];
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
spectator.component.closeProcess(1);
expect(applicationServiceMock.removeProcess).toHaveBeenCalledWith(1);
});
it('should navigate to kunde/dashboard if no process is available', async () => {
spyOn(router, 'navigate');
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of([]));
spectator.detectComponentChanges();
await spectator.component.closeProcess(1);
expect(router.navigate).toHaveBeenCalledWith(['/kunde', 'dashboard']);
});
it('should not navigate to kunde/dashboard if processes are available', async () => {
spyOn(router, 'navigate');
const processes = [
{ id: 1, name: 'test', section: 'customer' },
{ id: 2, name: 'test', section: 'customer' },
];
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(of({}));
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
await spectator.component.closeProcess(1);
expect(router.navigate).not.toHaveBeenCalledWith(['/kunde', 'dashboard']);
});
it('should activate the next process when it was not the last process', async () => {
spyOn(spectator.component, 'activateProcess');
applicationServiceMock.getLastActivatedProcessWithSection$.and.returnValue(
of({
id: 2,
name: 'test',
section: 'customer',
activated: 2,
})
);
const processes = [
{ id: 1, name: 'test', section: 'customer', activated: 1 },
{ id: 2, name: 'test', section: 'customer', activated: 2 },
];
applicationServiceMock.getSection$.and.returnValue(of('customer'));
applicationServiceMock.getProcesses$.and.returnValue(of(processes));
await spectator.component.closeProcess(1);
expect(spectator.component.activateProcess).toHaveBeenCalledWith(2);
});
});
describe('activateProcess()', () => {
it('should get the last activated breadcrumb by key and if it is defined it navigates to its path with queryParams', async () => {
const crumb = { path: '/kunde/product', params: { id: 1 } };
spyOn(router, 'navigate');
breadcrumbServiceMock.getLastActivatedBreadcrumbByKey$.and.returnValue(of(crumb));
await spectator.component.activateProcess(1);
expect(router.navigate).toHaveBeenCalledWith([crumb.path], { queryParams: crumb.params });
});
it('should navigate to /kunde if no breadcrumb for this process exists', async () => {
breadcrumbServiceMock.getLastActivatedBreadcrumbByKey$.and.returnValue(of(undefined));
spyOn(router, 'navigate');
await spectator.component.activateProcess(1);
expect(router.navigate).toHaveBeenCalledWith(['/kunde', 1, 'product']);
});
});
describe('processAction()', () => {
it('should navigate to cart when process type is cart', () => {
spyOn(router, 'navigate');
const process: ApplicationProcess = { id: 1, name: 'Vorgang', section: 'customer', type: 'cart' };
spectator.component.processAction(process);
expect(router.navigate).toHaveBeenCalledWith(['/kunde', process.id, 'cart']);
});
it('should not navigate to when process type is not cart', () => {
spyOn(router, 'navigate');
const process: ApplicationProcess = { id: 1, name: 'Vorgang', section: 'customer', type: 'goods-out' };
spectator.component.processAction(process);
expect(router.navigate).not.toHaveBeenCalled();
});
});
describe('openNotifications()', () => {
it('should call modalService.open() with the ModalNotificationComponent', async () => {
const notifications: EnvelopeDTO<MessageBoardItemDTO[]> = {
data: [{}, {}, {}],
};
spectator.component.notifications$ = of(notifications);
await spectator.component.openNotifications();
expect(modalServiceMock.open).toHaveBeenCalledWith({
content: ModalNotificationsComponent,
data: notifications,
config: {
showScrollbarY: false,
},
});
});
});
});

View File

@@ -1,174 +0,0 @@
import { Component, ChangeDetectionStrategy, ViewChildren, QueryList, TrackByFunction, NgZone } from '@angular/core';
import { ApplicationProcess, ApplicationService } from '@core/application';
import { first, map, shareReplay, switchMap, take, tap } from 'rxjs/operators';
import { NotificationsHub } from '@hub/notifications';
import { ModalNotificationsComponent } from '@modal/notifications';
import { UiModalService } from '@ui/modal';
import { Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { combineLatest } from 'rxjs';
import { AuthService } from '@core/auth';
import { DomainAvailabilityService } from '@domain/availability';
import { ShellProcessTabComponent } from '@shell/process';
import { Config } from '@core/config';
import { WrongDestinationModalService } from 'apps/page/package-inspection/src/lib/components/wrong-destination-modal/wrong-destination-modal.service';
@Component({
selector: 'app-shell',
templateUrl: 'shell.component.html',
styleUrls: ['shell.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShellComponent {
isDevelopment = Boolean(this._config.get('debug'));
debugOpen = false;
@ViewChildren('processTabs')
readonly processTabs: QueryList<ShellProcessTabComponent>;
notifications$ = this._notificationsHub.notifications$;
notificationCount$ = this.notifications$.pipe(map((message) => message?.data?.length));
get activatedProcessId$() {
return this._appService.getActivatedProcessId$().pipe(
tap((activatedProcessId) => {
this.processTabs?.find((process) => process?.process?.id === activatedProcessId && !process?.isActive)?.slideIntoView();
})
);
}
customerBasePath$ = this.activatedProcessId$.pipe(
switchMap((processId) => this._appService.getProcessById$(processId)),
map((process) => {
if (!!process && process.section === 'customer' && process.type !== 'cart-checkout') {
// Übernehme aktiven Prozess
return `/kunde/${process.id}`;
} else {
// Über Guards wird ein neuer Prozess erstellt
return '/kunde';
}
})
);
get section$() {
return this._appService.getSection$().pipe(shareReplay());
}
get processes$() {
return this.section$.pipe(switchMap((section) => this._appService.getProcesses$(section)));
}
get remissionProcess$() {
return this._appService.getProcessById$(this._config.get('process.ids.remission'));
}
get remissionUrl$() {
return this.remissionProcess$.pipe(
map((process) => (process?.data?.active ? `/filiale/remission/${process.data.active}/list` : '/filiale/remission'))
);
}
get remissionQueryParams$() {
return this.remissionProcess$.pipe(
map((process) => (process?.data?.active && process?.data?.queryParams ? process.data.queryParams : {}))
);
}
get addProcessLabel$() {
return combineLatest([this.section$, this.processes$]).pipe(
map(([section, processes]) => (section === 'customer' && processes.length === 0 ? 'VORGANG STARTEN' : ''))
);
}
get canAddProcess$() {
return this.section$.pipe(map((section) => section === 'customer'));
}
get currentBranch$() {
return this._availabilityService.getDefaultBranch();
}
constructor(
private readonly _appService: ApplicationService,
private readonly _config: Config,
private readonly _notificationsHub: NotificationsHub,
private readonly _modal: UiModalService,
private readonly _router: Router,
private readonly _breadcrumbService: BreadcrumbService,
private readonly _authService: AuthService,
private readonly _availabilityService: DomainAvailabilityService,
private readonly _zone: NgZone,
private readonly _wrongDestinationModalService: WrongDestinationModalService
) {}
async setSection(section: 'customer' | 'branch') {
this._appService.setSection(section);
const lastProcessId = (await this._appService.getLastActivatedProcessWithSection$(section).pipe(first()).toPromise())?.id;
if (lastProcessId) {
this.activateProcess(lastProcessId);
} else {
this._router.navigate([section === 'customer' ? '/kunde' : '/filiale']);
}
}
// Process werden über Guards erstellt und aktiviert. An dieser Stelle wird nur navigiert
async addProcess() {
const processId = Date.now();
await this._router.navigate(['/kunde', processId, 'product']);
}
async activateProcess(activatedProcessId: number) {
try {
const latestCrumb = await this._breadcrumbService?.getLastActivatedBreadcrumbByKey$(activatedProcessId)?.pipe(take(1)).toPromise();
await this._zone.run(async () => {
if (latestCrumb) {
await this._router.navigate([latestCrumb.path], { queryParams: latestCrumb.params });
} else {
await this._router.navigate(['/kunde', activatedProcessId, 'product']);
}
});
} catch (error) {}
}
async closeProcess(processId: number) {
this._appService.removeProcess(processId);
const processes = await this.processes$.pipe(first()).toPromise();
if (processes.length === 0) {
await this._router.navigate(['/kunde', 'dashboard']);
return;
}
const section = await this.section$.pipe(first()).toPromise();
const lastActivatedProcess = await this._appService.getLastActivatedProcessWithSection$(section).pipe(first()).toPromise();
this.activateProcess(lastActivatedProcess?.id);
}
processAction(process: ApplicationProcess) {
if (process?.type === 'cart') {
this._router.navigate(['/kunde', process.id, 'cart']);
}
}
async logout() {
await this._authService.logout();
}
async openNotifications() {
const notifications = await this.notifications$.pipe(first()).toPromise();
this._modal.open({
content: ModalNotificationsComponent,
data: notifications,
config: {
showScrollbarY: false,
},
});
}
trackByIdFn: TrackByFunction<ApplicationProcess> = (_, process) => process.id;
fetchAndOpenPackages = () => this._wrongDestinationModalService.fetchAndOpen();
}

View File

@@ -1,31 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OverlayModule } from '@angular/cdk/overlay';
import { ShellHeaderModule } from '@shell/header';
import { ShellProcessModule } from '@shell/process';
import { ShellFooterModule } from '@shell/footer';
import { ShellComponent } from './shell.component';
import { UiIconModule } from '@ui/icon';
import { RouterModule } from '@angular/router';
import { AuthModule } from '@core/auth';
import { DebugComponent } from '../debug/debug.component';
@NgModule({
imports: [
RouterModule,
CommonModule,
ShellHeaderModule,
ShellProcessModule,
ShellFooterModule,
UiIconModule,
OverlayModule,
AuthModule,
DebugComponent,
],
exports: [ShellComponent],
declarations: [ShellComponent],
providers: [],
})
export class ShellModule {}

View File

File diff suppressed because one or more lines are too long

View File

@@ -1,20 +0,0 @@
@font-face {
font-family: 'Material Symbols Outlined';
font-style: normal;
font-weight: 100 700;
src: url(./materials-icons-outlined.woff2) format('woff2');
}
@font-face {
font-family: 'Material Symbols Rounded';
font-style: normal;
font-weight: 100 700;
src: url(./materials-icons-rounded.woff2) format('woff2');
}
@font-face {
font-family: 'Material Symbols Sharp';
font-style: normal;
font-weight: 100 700;
src: url(./materials-icons-sharp.woff2) format('woff2');
}

View File

Binary file not shown.

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon_HC</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon_HC</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="22px" height="18px" viewBox="0 0 22 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Icon_HC</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Hugendubel_Icons" transform="translate(-29.000000, -177.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.3">
<path d="M32.725699,178.000628 C32.7430505,177.999791 32.7604307,177.999791 32.7777823,178.000628 L37.5260449,178.000628 C38.53109,178.000628 39.44018,178.547926 40.0000026,179.340692 C40.5598253,178.547926 41.4689153,178.000628 42.4739603,178.000628 L47.222223,178.000628 C47.529035,178.00066 47.7777477,178.256627 47.7777784,178.572389 L47.7777784,179.71591 L49.4444446,179.71591 C49.7512567,179.715942 49.9999694,179.971909 50,180.287671 L50,192.008763 C49.9999694,192.324524 49.7512567,192.580492 49.4444446,192.580523 L42.4739603,192.580523 C41.4766486,192.580523 40.8524541,192.949423 40.4947942,193.688309 C40.3998428,193.879608 40.208727,194 40.0000026,194 C39.7912783,194 39.6001624,193.879608 39.5052111,193.688309 C39.1475512,192.949423 38.5233566,192.580523 37.5260449,192.580523 L30.5555607,192.580523 C30.2487486,192.580492 30.0000359,192.324524 30.0000053,192.008763 L30.0000053,180.287671 C29.9987652,179.991708 30.2171687,179.743681 30.5034773,179.71591 C30.5208289,179.715072 30.5382091,179.715072 30.5555607,179.71591 L32.2222269,179.71591 L32.2222269,178.572389 C32.2209869,178.276426 32.4393904,178.028399 32.725699,178.000628 Z M33.3333377,179.14415 L33.3333377,189.43584 L36.6232674,189.43584 C37.6190746,189.43584 38.5547188,189.729711 39.2621556,190.356017 C39.3270606,190.413476 39.3849347,190.480265 39.4444472,190.543626 L39.4444472,180.957703 C39.4433388,180.936873 39.4433388,180.915996 39.4444472,180.895166 C39.4444472,180.068361 38.4768339,179.14415 37.5260449,179.14415 L33.3333377,179.14415 Z M42.4739603,179.14415 C41.5231714,179.14415 40.555558,180.068361 40.555558,180.895166 C40.5555806,180.898144 40.5555806,180.901122 40.555558,180.9041 L40.555558,190.543626 C40.6150705,190.480265 40.6729447,190.413476 40.7378497,190.356017 C41.4452864,189.729711 42.3809306,189.43584 43.3767379,189.43584 L46.6666675,189.43584 L46.6666675,179.14415 L42.4739603,179.14415 Z M31.1111161,180.859431 L31.1111161,191.437002 L37.5260449,191.437002 C38.0365968,191.437002 38.5189494,191.531483 38.9496557,191.713949 C38.8273679,191.527334 38.6888269,191.36055 38.5329891,191.222592 C38.0547048,190.799175 37.405738,190.579361 36.6232674,190.579361 L32.7777823,190.579361 C32.4709702,190.57933 32.2222575,190.323362 32.2222269,190.007601 L32.2222269,180.859431 L31.1111161,180.859431 Z M47.7777784,180.859431 L47.7777784,190.007601 C47.7777477,190.323362 47.529035,190.57933 47.222223,190.579361 L43.3767379,190.579361 C42.5942672,190.579361 41.9453004,190.799175 41.4670161,191.222592 C41.3107359,191.360944 41.1725734,191.526903 41.0503496,191.713949 C41.4810558,191.531483 41.9634085,191.437002 42.4739603,191.437002 L48.8888892,191.437002 L48.8888892,180.859431 L47.7777784,180.859431 Z M35.5,182.116677 L37.5,182.116677 C37.7761424,182.116677 38,182.340535 38,182.616677 L38,182.645847 C38,182.921989 37.7761424,183.145847 37.5,183.145847 L35.5,183.145847 C35.2238576,183.145847 35,182.921989 35,182.645847 L35,182.616677 C35,182.340535 35.2238576,182.116677 35.5,182.116677 Z M35.5,184.175016 L37.5,184.175016 C37.7761424,184.175016 38,184.398874 38,184.675016 L38,184.704185 C38,184.980328 37.7761424,185.204185 37.5,185.204185 L35.5,185.204185 C35.2238576,185.204185 35,184.980328 35,184.704185 L35,184.675016 C35,184.398874 35.2238576,184.175016 35.5,184.175016 Z M35.5,186.233355 L37.5,186.233355 C37.7761424,186.233355 38,186.457212 38,186.733355 L38,186.762524 C38,187.038666 37.7761424,187.262524 37.5,187.262524 L35.5,187.262524 C35.2238576,187.262524 35,187.038666 35,186.762524 L35,186.733355 C35,186.457212 35.2238576,186.233355 35.5,186.233355 Z M42.5,182.116677 L44.5,182.116677 C44.7761424,182.116677 45,182.340535 45,182.616677 L45,182.645847 C45,182.921989 44.7761424,183.145847 44.5,183.145847 L42.5,183.145847 C42.2238576,183.145847 42,182.921989 42,182.645847 L42,182.616677 C42,182.340535 42.2238576,182.116677 42.5,182.116677 Z M42.5,184.175016 L44.5,184.175016 C44.7761424,184.175016 45,184.398874 45,184.675016 L45,184.704185 C45,184.980328 44.7761424,185.204185 44.5,185.204185 L42.5,185.204185 C42.2238576,185.204185 42,184.980328 42,184.704185 L42,184.675016 C42,184.398874 42.2238576,184.175016 42.5,184.175016 Z M42.5,186.233355 L44.5,186.233355 C44.7761424,186.233355 45,186.457212 45,186.733355 L45,186.762524 C45,187.038666 44.7761424,187.262524 44.5,187.262524 L42.5,187.262524 C42.2238576,187.262524 42,187.038666 42,186.762524 L42,186.733355 C42,186.457212 42.2238576,186.233355 42.5,186.233355 Z" id="Icon_HC"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -16,6 +16,9 @@
"@core/logger": {
"logLevel": "debug"
},
"@domain/checkout": {
"olaExpiration": "5m"
},
"@swagger/isa": {
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
},
@@ -41,7 +44,7 @@
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
@@ -69,6 +72,8 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
}
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -1,7 +1,7 @@
{
"title": "ISA - Integration",
"silentRefresh": {
"interval": 300000
"interval": 60000
},
"@cdn/product-image": {
"url": "https://produktbilder.paragon-data.net"
@@ -15,6 +15,9 @@
"@core/logger": {
"logLevel": "debug"
},
"@domain/checkout": {
"olaExpiration": "5m"
},
"@swagger/isa": {
"rootUrl": "https://isa-integration.paragon-data.net/isa/v1"
},
@@ -40,7 +43,7 @@
"rootUrl": "https://filialinformationsystem-integration.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-integration.paragon-data.net/inv/v1"
"rootUrl": "https://isa-integration.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-integration.paragon-data.net/wws/v1"
@@ -66,8 +69,9 @@
"assortment": 6000
}
},
"checkForUpdates": 3600000,
"checkForUpdates": 900000,
"licence": {
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
}
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -42,11 +42,14 @@
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
},
"@domain/checkout": {
"olaExpiration": "30s"
},
"hubs": {
"notifications": {
"url": "https://isa-test.paragon-data.net/isa/v1/rt",
@@ -70,6 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
}
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -16,6 +16,9 @@
"@core/logger": {
"logLevel": "debug"
},
"@domain/checkout": {
"olaExpiration": "5m"
},
"@swagger/isa": {
"rootUrl": "https://isa.paragon-systems.de/isa/v1"
},
@@ -41,7 +44,7 @@
"rootUrl": "https://filialinformationsystem.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa.paragon-systems.de/inv/v1"
"rootUrl": "https://isa.paragon-systems.de/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa.paragon-systems.de/wws/v1"
@@ -69,6 +72,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
}
"scandit": "AZZzfQ+eLFl3Dzf1QSBag1lDibIoOPh4W33erRIRe3SDUMkHDX8eczEjd2TnfRMWoE5lXOBGtESCWICN9EbrmI1S9Lu5APsvvEOD+K54ADwIVawx0HNZRAc8/+9Vf/izcEGOFQFGBQJyR6vzdzFv5HcjznhxI9E3LiF+uVQPtCqsVYzpkMWIrC5VCg2uwNrj9Bw6f8zYi/lZPrDMS5yVKVcajeK7sh9QAq17dR0opjIIuP5t5nDEJ7hnITwtTR5HaM6cX/KhKpTILOgKexvLYqrK6QJWpU85sDwqwn6T7av4V68qL3XrUo60dScop4QsvraQe1HkRsffl6DkAEoX0RNMS5qVWjGerW7lvA/DQd9hsAO3jWFDR9hVDyt2VvmzzFKnHYqTYxC5qG4bCEJ0RJjy6tEP5Q7vL5SxWygVadmjPv+TwDOCS7DxzxIjcO+BXQY7gW6qn0hx9fXzyvO3avrGWqyImMlgEApZq+36ANqtRcPD/stEe4i0N9dSPhYoHPcc/9/9jpts43FozlgfY4wY8Wt5ybB3X0caISMmB/klFIJKKN7num439z3+Xk7ENB/Xvb0XAtnOt/cuxQYsGQ7fb62GOO/7Va5fdE9ZfaIJsS5ToE6oIbV04pLUssJf9cUMsyPFVELYSJmyGPQQFRz0TTxxRvPapIWrfa2x5x3hYUpNTAdY3v0fN9l/1ZqNSBmIBLH/LoXaVJQ2DydGD1/QFZ2Z/S7zTYKg5/cSEpUgiYtbwutNZSjRH29ucSizC524k+Zst95T8G7LJaWCT8SQAcKXqCnjpiEGWzD++h0jXjn6BWjUnIHi0te+27vF/z6UQL00sWco5hUIqF66EiU="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -16,6 +16,9 @@
"@core/logger": {
"logLevel": "debug"
},
"@domain/checkout": {
"olaExpiration": "5m"
},
"@swagger/isa": {
"rootUrl": "https://isa-staging.paragon-systems.de/isa/v1"
},
@@ -41,7 +44,7 @@
"rootUrl": "https://filialinformationsystem-staging.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-staging.paragon-systems.de/inv/v1"
"rootUrl": "https://isa-staging.paragon-systems.de/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-staging.paragon-systems.de/wws/v1"
@@ -69,6 +72,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AfHi/mY+RbwJD5nC7SuWn3I14pFUOfSbQ2QG//4aV3zWQjwix30kHqsqraA8ZiipDBql8YlwIyV6VPBMUiAX4s9YHDxHHsWwq2BUB3ImzDEcU1jmMH/5yakGUYpCQ68D0iZ8SG9sS0QBb3iFdCHc1r9DFr1cMTxM7zOvb/AUoIVmieHZXnx9ioUgCvczsLiuX3hwvTW3lhbvJ4uUyqTWK4sWFVwoY4AIWSFrPwwrkV2DksMKT5fMJT3GWgPypvTIGwWvpRfLWwKlc1Z3ckyb84khsnaWD2wr+hdgu/K8YIMmgGszm5KIZ/G05YfDNZtQ4jby+5RZvQwWR8rxM35rJgf73OkMSpuL9jw3T0TTAlvpkGRLzVVuCw9VjlBLqfPNEZ6VsEwFuAla9IYUvFHCsjypg2J6UpxHXrTYmbsSu5Jm8frVfS5znPPTO9D/4rF6ZVv2PxY9PgUgJUvwMa/VMc/nse3RRRf8RGT4rUItfJDFO8pujD76vVEWq/KixQRoMdLgDLyxhsFVftkxqhZhyEfFZzsEy49LSojJ28vpHpBWLeCQBmnZ7JZ4C5yOQiqSQV/assBq2zJN2q+vCDp8qy5j1rED1SX5Ec7JpgpgnU4chLIf5Zn7bP/hNGT3pEYBuXeDXXN8ke1pcc3fc3m0FysDG0o56XVCUqImZ8Ezi8eujZciKDrWbtljhKTj7cnfuJx0sVHF6Bh5i4YfgA/Z+NL+MtH2EVIF67e6hEz6PWYTcoh3ybBaJfxb2FNvGJutNKg04GwMhYq6K2IddBt0fDiBt0SGM0oSBlUP3DKCUmXcf2a6ASbrcqv6Wz1jHt0pY4U8bEpg7qSbW3VDyvdPgyQ="
}
"scandit": "AZZzfQ+eLFl3Dzf1QSBag1lDibIoOPh4W33erRIRe3SDUMkHDX8eczEjd2TnfRMWoE5lXOBGtESCWICN9EbrmI1S9Lu5APsvvEOD+K54ADwIVawx0HNZRAc8/+9Vf/izcEGOFQFGBQJyR6vzdzFv5HcjznhxI9E3LiF+uVQPtCqsVYzpkMWIrC5VCg2uwNrj9Bw6f8zYi/lZPrDMS5yVKVcajeK7sh9QAq17dR0opjIIuP5t5nDEJ7hnITwtTR5HaM6cX/KhKpTILOgKexvLYqrK6QJWpU85sDwqwn6T7av4V68qL3XrUo60dScop4QsvraQe1HkRsffl6DkAEoX0RNMS5qVWjGerW7lvA/DQd9hsAO3jWFDR9hVDyt2VvmzzFKnHYqTYxC5qG4bCEJ0RJjy6tEP5Q7vL5SxWygVadmjPv+TwDOCS7DxzxIjcO+BXQY7gW6qn0hx9fXzyvO3avrGWqyImMlgEApZq+36ANqtRcPD/stEe4i0N9dSPhYoHPcc/9/9jpts43FozlgfY4wY8Wt5ybB3X0caISMmB/klFIJKKN7num439z3+Xk7ENB/Xvb0XAtnOt/cuxQYsGQ7fb62GOO/7Va5fdE9ZfaIJsS5ToE6oIbV04pLUssJf9cUMsyPFVELYSJmyGPQQFRz0TTxxRvPapIWrfa2x5x3hYUpNTAdY3v0fN9l/1ZqNSBmIBLH/LoXaVJQ2DydGD1/QFZ2Z/S7zTYKg5/cSEpUgiYtbwutNZSjRH29ucSizC524k+Zst95T8G7LJaWCT8SQAcKXqCnjpiEGWzD++h0jXjn6BWjUnIHi0te+27vF/z6UQL00sWco5hUIqF66EiU="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -17,6 +17,9 @@
"@core/logger": {
"logLevel": "debug"
},
"@domain/checkout": {
"olaExpiration": "5m"
},
"@swagger/isa": {
"rootUrl": "https://isa-test.paragon-data.net/isa/v1"
},
@@ -42,7 +45,7 @@
"rootUrl": "https://filialinformationsystem-test.paragon-systems.de/eiswebapi/v1"
},
"@swagger/remi": {
"rootUrl": "https://isa-test.paragon-data.net/inv/v1"
"rootUrl": "https://isa-test.paragon-data.net/inv/v6"
},
"@swagger/wws": {
"rootUrl": "https://isa-test.paragon-data.net/wws/v1"
@@ -70,6 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AQZyKCc+BEkNL00Y3h3FjawGLF+INUj7cVb0My91hl8ffiW873T8FTV1k4TIZJx5RwcJlYxhgsxHVcnM4AJgSwJhbAfxJmP/3XGijLlLp3XUIRjQwFtf7UlZAFZ7Vrt1/WSf7kxxrFQ2SE2AQwLqPg9DL+hHEfd4xT/15n8p2q7qUlCKLsV6jF12Pd7koFNSWNL3ZIkRtd1ma99/321dnwAJHFGXqWg5nprJ7sYtqUqNQ8Er9SlvKbhnw3AipHzKpz0O3oNfUsr6NlZivRBhMhCZLo5WpXo1m9uIU8zLEWMNDJ+wGUctcGxE3eCptP2zLXUgxxjB+0EXOUtT/GWUc/Ip61CMiyUf7Paz026E2eYil2yWgfkTP5CUgDMNGZFuAA1T5PhB9FRW51CjAIvwOKVMCvfixJiVoUsXHnWH2ZnXqtbDR/uEZBE7OKoBlaPL4G3Lvgdqym5EjROAztUXb6wOmVDiGzzqgizyZnIcxFBSKJAownGj9Vh4/Y/Ag1xzGzNtjz3ngSRfMfIIq/q2Q51uiLiv7mBVliPvPWMUTfTjnqnK/OSBlR2ID+COJqnUKpQMedPyOT3IMznmM6gQCmyYO5KE0MkfhFh6+pdNi6oJM2iZsxK1Z1V+GRSOIwrJEoajjDJkh439XjXk8NExFvplrLjK/oL/dsHIZiG6U5GVWW92kGkuXkJCeUz1CET3paxbGqwrd53r5d6gFABbC12CtcP2JeH4YYCpHYyPQacf0prj9Hdq3wDztShC9tH+4UQS/GbaDHKcS1ANIyPuTxHmBFtPuCJ9Uagy5QBEc8eAz2nfsbfaUxYzco6u/zhNsFbqp6zgQIxs5OcqDQ=="
}
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -1,3 +1,4 @@
export const environment = {
production: true,
debug: false,
};

View File

@@ -4,6 +4,7 @@
export const environment = {
production: false,
debug: false,
};
/*

View File

@@ -7,7 +7,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link href="/assets/fonts/fonts.css" rel="stylesheet" />
<link href="/assets/icons/icons.css" rel="stylesheet" />
<link rel="manifest" href="manifest.webmanifest" />
<meta name="theme-color" content="#1976d2" />
</head>

View File

@@ -14,26 +14,28 @@ if (environment.production) {
const debugService = new DebugService();
const consoleLog = console.log;
if (environment.debug) {
const consoleLog = console.log;
console.log = (...args) => {
debugService.add({ type: 'log', args });
consoleLog(...args);
};
console.log = (...args) => {
debugService.add({ type: 'log', args });
consoleLog(...args);
};
const consoleWarn = console.warn;
const consoleWarn = console.warn;
console.warn = (...args) => {
debugService.add({ type: 'warn', args });
consoleWarn(...args);
};
console.warn = (...args) => {
debugService.add({ type: 'warn', args });
consoleWarn(...args);
};
const consoleError = console.error;
const consoleError = console.error;
console.error = (...args) => {
debugService.add({ type: 'error', args });
consoleError(...args);
};
console.error = (...args) => {
debugService.add({ type: 'error', args });
consoleError(...args);
};
}
platformBrowserDynamic([{ provide: DebugService, useValue: debugService }])
.bootstrapModule(AppModule)

View File

@@ -11,15 +11,11 @@
@import './scss/customer';
@import './scss/branch';
* {
@apply font-sans;
}
body {
background: var(--bg-color);
}
@layer base {
body {
@apply bg-background;
}
::-webkit-scrollbar {
width: 0; // remove scrollbar space
height: 0;
@@ -61,3 +57,18 @@ body {
@apply block bg-gray-300 h-6;
animation: load 1s ease-in-out infinite;
}
@layer components {
.input-control {
@apply rounded border border-solid border-[#AEB7C1] px-4 py-[1.125rem] outline-none;
}
// .input-control:focus,
// .input-control:not(:placeholder-shown) {
// @apply bg-white;
// }
.input-control.ng-touched.ng-invalid {
@apply border-brand;
}
}

View File

@@ -3,7 +3,7 @@
}
.subtitle {
@apply text-center text-regular my-6;
@apply text-center text-p2 my-6;
}
.bold {
@@ -62,7 +62,7 @@ hr {
@apply flex flex-row items-center;
.cta-reserve {
@apply absolute bg-transparent text-brand text-base font-bold border-none px-1 -mr-1;
@apply absolute bg-transparent text-brand text-p2 font-bold border-none px-1 -mr-1;
right: 85px;
}
}

View File

@@ -1,8 +1,11 @@
<div class="notification-headline">
<h1>{{ item.headline }}</h1>
<button class="notification-edit-cta" (click)="itemSelected.emit(item)">
Bearbeiten
</button>
<div class="grid grid-cols-[1fr_auto] items-center gap-4">
<div class="grid grid-flow-row gap-4">
<h1 class="text-left font-bold text-lg">{{ item.headline }}</h1>
<div class="notification-text">{{ item.text }}</div>
</div>
<div>
<button *ngIf="editButton" class="notification-edit-cta text-brand font-bold text-lg px-4 py-3" (click)="itemSelected.emit(item)">
{{ editButtonLabel }}
</button>
</div>
</div>
<div class="notification-text">{{ item.text }}</div>

View File

@@ -13,5 +13,11 @@ export class ModalNotificationsListItemComponent {
@Output()
itemSelected = new EventEmitter<MessageBoardItemDTO>();
@Input()
editButton = true;
@Input()
editButtonLabel = 'Bearbeiten';
constructor() {}
}

View File

@@ -0,0 +1,11 @@
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item
(click)="itemSelected(notification)"
[editButtonLabel]="'Packstück-Prüfung'"
[item]="notification"
(itemSelected)="itemSelected($event)"
></modal-notifications-list-item>
<hr />
</ng-container>
</div>

View File

@@ -0,0 +1,23 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Router } from '@angular/router';
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
@Component({
selector: 'modal-notifications-package-inspection-group',
templateUrl: 'notifications-package-inspection-group.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ModalNotificationsPackageInspectionGroupComponent {
@Input()
notifications: MessageBoardItemDTO[];
@Output()
navigated = new EventEmitter<void>();
constructor(private _router: Router) {}
itemSelected(item: MessageBoardItemDTO) {
this._router.navigate(['/filiale/package-inspection/packages']);
this.navigated.emit();
}
}

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<span class="notification-counter">{{ notifications.length }}</span>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>Remission</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>

View File

@@ -1,101 +0,0 @@
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
import { CommonModule } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';
import { UiIconModule } from '@ui/icon';
import { Router } from '@angular/router';
import { UiFilter } from '@ui/filter';
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
import { Component } from '@angular/core';
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
import { ModalNotificationsRemissionGroupComponent } from './notifications-remission-group.component';
// DummyComponent Class
@Component({
selector: 'dummy-component',
template: '<div></div>',
})
class DummyComponent {
constructor() {}
}
describe('ModalNotificationsRemissionGroupComponent', () => {
let spectator: Spectator<ModalNotificationsRemissionGroupComponent>;
let uiFilterMock: SpyObject<UiFilter>;
let router: Router;
const createComponent = createComponentFactory({
component: ModalNotificationsRemissionGroupComponent,
declarations: [ModalNotificationsListItemComponent],
imports: [
CommonModule,
RouterTestingModule.withRoutes([
{ path: 'filiale/goods/in/results', component: DummyComponent },
{ path: 'filiale/remission/create', component: DummyComponent },
]),
UiIconModule,
],
providers: [],
mocks: [UiFilter],
});
beforeEach(() => {
spectator = createComponent({ props: { notifications: [] } });
router = spectator.inject(Router);
uiFilterMock = spectator.inject(UiFilter);
});
it('should create', () => {
expect(spectator.component).toBeTruthy();
});
describe('notifications input', () => {
it('should display the right notification-counter value based on the length of the input array', () => {
spectator.setInput({ notifications: [{}, {}, {}] });
expect(spectator.query('.notification-counter')).toHaveText('3');
});
it('should not display notification-counter if input array has length 0', () => {
spectator.setInput({ notifications: [] });
expect(spectator.query('.notification-counter')).toHaveText('');
});
it('should render modal-notifications-list-item based on the input array', () => {
const notifications = [{}, {}];
spectator.setInput({ notifications });
spectator.detectComponentChanges();
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
});
});
describe('itemSelected()', () => {
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
spyOn(router, 'navigate');
spectator.component.itemSelected(item);
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
});
it('should emit the navigated event after select item', () => {
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
spyOn(spectator.component.navigated, 'emit');
spectator.component.itemSelected(item);
expect(spectator.component.navigated.emit).toHaveBeenCalled();
});
});
describe('actions CTA', () => {
it('should navigate to remission page after clicking the CTA', () => {
const cta = spectator.query('.cta-primary');
expect(cta).toHaveText('Zur Remission');
expect(cta).toHaveAttribute('href', '/filiale/remission/create');
});
it('should emit the navigated event after clicking the CTA', () => {
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
spyOn(spectator.component.navigated, 'emit');
spectator.click(cta);
expect(spectator.component.navigated.emit).toHaveBeenCalled();
});
});
});

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<div class="notification-counter">{{ notifications.length }}</div>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>Reservierungsanfragen</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>

View File

@@ -1,101 +0,0 @@
import { createComponentFactory, Spectator, SpyObject } from '@ngneat/spectator';
import { CommonModule } from '@angular/common';
import { ModalNotificationsReservationGroupComponent } from './notifications-reservation-group.component';
import { RouterTestingModule } from '@angular/router/testing';
import { UiIconModule } from '@ui/icon';
import { Router } from '@angular/router';
import { UiFilter } from '@ui/filter';
import { MessageBoardItemDTO } from 'apps/hub/notifications/src/lib/defs';
import { Component } from '@angular/core';
import { ModalNotificationsListItemComponent } from '../notifications-list-item/notifications-list-item.component';
// DummyComponent Class
@Component({
selector: 'dummy-component',
template: '<div></div>',
})
class DummyComponent {
constructor() {}
}
describe('ModalNotificationsReservationGroupComponent', () => {
let spectator: Spectator<ModalNotificationsReservationGroupComponent>;
let uiFilterMock: SpyObject<UiFilter>;
let router: Router;
const createComponent = createComponentFactory({
component: ModalNotificationsReservationGroupComponent,
declarations: [ModalNotificationsListItemComponent],
imports: [
CommonModule,
RouterTestingModule.withRoutes([
{ path: 'filiale/goods/in/results', component: DummyComponent },
{ path: 'filiale/goods/in/reservation', component: DummyComponent },
]),
UiIconModule,
],
providers: [],
mocks: [UiFilter],
});
beforeEach(() => {
spectator = createComponent({ props: { notifications: [] } });
router = spectator.inject(Router);
uiFilterMock = spectator.inject(UiFilter);
});
it('should create', () => {
expect(spectator.component).toBeTruthy();
});
describe('notifications input', () => {
it('should display the right notification-counter value based on the length of the input array', () => {
spectator.setInput({ notifications: [{}, {}, {}] });
expect(spectator.query('.notification-counter')).toHaveText('3');
});
it('should not display notification-counter if input array has length 0', () => {
spectator.setInput({ notifications: [] });
expect(spectator.query('.notification-counter')).toHaveText('');
});
it('should render modal-notifications-list-item based on the input array', () => {
const notifications = [{}, {}];
spectator.setInput({ notifications });
spectator.detectComponentChanges();
expect(spectator.queryAll('modal-notifications-list-item')).toHaveLength(notifications.length);
});
});
describe('itemSelected()', () => {
it('should navigate to results with queryParams from UiFilter.getQueryParamsFromQueryTokenDTO()', () => {
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
spyOn(UiFilter, 'getQueryParamsFromQueryTokenDTO').and.returnValue(item.queryToken.input);
spyOn(router, 'navigate');
spectator.component.itemSelected(item);
expect(router.navigate).toHaveBeenCalledWith(['/filiale/goods/in/results'], { queryParams: item.queryToken.input });
});
it('should emit the navigated event after select item', () => {
const item: MessageBoardItemDTO = { queryToken: { input: { main_qs: 'test' } } };
spyOn(spectator.component.navigated, 'emit');
spectator.component.itemSelected(item);
expect(spectator.component.navigated.emit).toHaveBeenCalled();
});
});
describe('actions CTA', () => {
it('should navigate to reservation page after clicking the CTA', () => {
const cta = spectator.query('.cta-primary');
expect(cta).toHaveText('Zu den Reservierungen');
expect(cta).toHaveAttribute('href', '/filiale/goods/in/reservation');
});
it('should emit the navigated event after clicking the CTA', () => {
const cta = spectator.query('.cta-primary') as HTMLAnchorElement;
spyOn(spectator.component.navigated, 'emit');
spectator.click(cta);
expect(spectator.component.navigated.emit).toHaveBeenCalled();
});
});
});

View File

@@ -1,13 +1,3 @@
<div class="header">
<div class="notification-icon">
<span class="notification-counter">{{ notifications.length }}</span>
<ui-icon icon="notification" size="26px"></ui-icon>
</div>
<h2>Tätigkeitskalender</h2>
</div>
<hr />
<div class="notification-list scroll-bar">
<ng-container *ngFor="let notification of notifications">
<modal-notifications-list-item [item]="notification" (itemSelected)="itemSelected($event)"></modal-notifications-list-item>

Some files were not shown because too many files have changed in this diff Show More