Compare commits

...

25 Commits

Author SHA1 Message Date
Nino Righi
a074b9605b Merge branch 'develop' into fix/3051-Remi-Fortsetzen-Routing 2022-05-02 13:31:52 +02:00
Andreas Schickinger
1228698fcf Merged PR 1212: #3069 Fehlende Icons in der Remission
#3069 Fehlende Icons in der Remission

Related work items: #3069
2022-05-02 08:26:38 +00:00
Andreas Schickinger
d1eba5f1e2 Merged PR 1213: #2575 AHF Remi Buttons
#2575 AHF Remi Buttons

Related work items: #2575
2022-05-02 08:24:20 +00:00
Michael Auer
08ac71dc1b Merge tag '1.7' into develop 2022-05-02 10:10:39 +02:00
Michael Auer
da579ecc3a Merge branch 'release/1.7' 2022-05-02 09:37:27 +02:00
Andreas Schickinger
f286dd1e1b Merged PR 1211: #3080 Bei Remittieren mit Menge 0 wird nun "Nicht gefunden" ausgelöst
#3080 Bei Remittieren mit Menge 0 wird nun "Nicht gefunden" ausgelöst

Related work items: #3080
2022-04-28 14:39:28 +00:00
Nino Righi
0c5aedfee8 Merged PR 1210: #3081 #3051 Remember Filter Settings on continuing Remission and Remission start
#3081 #3051 Remember Filter Settings on continuing Remission and Remission start
2022-04-28 14:24:24 +00:00
Andreas Schickinger
b7d7c88fc6 Merged PR 1209: #3069 Fehlende Icons hinzugefügt. Anzeige nur, wenn Icon vorhanden
#3069 Fehlende Icons hinzugefügt. Anzeige nur, wenn Icon vorhanden

Related work items: #3069
2022-04-28 14:12:29 +00:00
Nico Hanus
8c2671e2fb limit unittests build for develop 2022-04-28 14:08:29 +00:00
Nico Hanus
b281f7c25b limit builds for develop branch 2022-04-28 13:59:47 +00:00
Nino Righi
750caa522e Merged PR 1208: #3074 Added Spacer inside WBS View
#3074 Added Spacer inside WBS View
2022-04-28 12:56:45 +00:00
Nino Righi
62ed8affb1 Merged PR 1207: #3076 Changed PopUp Wording and Form Validation Error Message
#3076 Changed PopUp Wording and Form Validation Error Message
2022-04-28 12:33:18 +00:00
Nino Righi
92e0e90120 Merged PR 1206: #3075 Remission Option to open Filter Overlay during a search
#3075 Remission Option to open Filter Overlay during a search
2022-04-28 12:32:33 +00:00
Andreas Schickinger
9b0dea213e Merged PR 1205: #3070 TK Fotoabschluss Spinner
#3070 TK Fotoabschluss Spinner

Related work items: #3070
2022-04-28 11:56:13 +00:00
Andreas Schickinger
a73acfa4e8 Merged PR 1204: #3063 Remission unnötiger Return Aufruf bei Wechsel zu gestarteter Remi über...
#3063 Remission unnötiger Return Aufruf bei Wechsel zu gestarteter Remi über den Footer

Related work items: #3063
2022-04-28 11:55:44 +00:00
Nino Righi
833542f303 Merged PR 1203: #3062 Clear Items Cache If Navigate to Remission
#3062 Clear Items Cache If Navigate to Remission
2022-04-27 14:05:53 +00:00
Nino Righi
b666e4b38c Merged PR 1202: #3051 Fix Remission Routing after Remission Completed
#3051 Fix Remission Routing after Remission Completed
2022-04-27 13:51:21 +00:00
Nino Righi
794daf3746 #3051 Fix Remission Routing after Remission Completed 2022-04-27 15:37:41 +02:00
Nino Righi
32f2fd0754 Merged PR 1201: #3058 Fix Show Start Remission CTA only if Hits > 0
#3058 Fix Show Start Remission CTA only if Hits > 0
2022-04-27 12:41:15 +00:00
Nino Righi
04cd5e9437 Merged PR 1196: #3028 #3040 #3049 Bugfixes Remission
#3028 #3040 #3049 Bugfixes Remission
2022-04-27 10:53:48 +00:00
Nino Righi
3785ad614f Merged PR 1200: #3050 Customer Online Email Adress Validation Fix
#3050 Customer Online Email Adress Validation Fix
2022-04-27 10:39:01 +00:00
Nino Righi
4e9b4064a6 Merged PR 1199: #3053 Fix Reservieren In Andere Filiale
#3053 Fix Reservieren In Andere Filiale
2022-04-27 09:45:06 +00:00
Nino Righi
319d8b96bb Merged PR 1197: #3054 Hotfix Release 1.7 TK PDF Viewer Removed Zoom Scaling to fit the page c...
#3054 Hotfix Release 1.7 TK PDF Viewer Removed Zoom Scaling to fit the page correctly
2022-04-26 13:58:02 +00:00
Nino Righi
272824e236 Merged PR 1198: #3036 Fix NativeContainer
#3036 Fix NativeContainer
2022-04-26 13:31:18 +00:00
Nino Righi
6974324c9b #3054 Hotfix Release 1.7 TK PDF Viewer Removed Zoom Scaling to fit the page correctly 2022-04-26 14:21:39 +02:00
40 changed files with 429 additions and 144 deletions

View File

@@ -392,6 +392,8 @@ export class DomainRemissionService {
quantity,
placementType,
inStock,
impedimentComment,
remainingQuantity,
}: {
returnId: number;
receiptId: number;
@@ -399,9 +401,15 @@ export class DomainRemissionService {
quantity?: number;
placementType?: RemissionPlacementType;
inStock: number;
impedimentComment: string;
remainingQuantity: number;
}) {
return this._returnService
.ReturnAddReturnSuggestion({ returnId, receiptId, data: { returnSuggestionId, quantity, placementType, inStock } })
.ReturnAddReturnSuggestion({
returnId,
receiptId,
data: { returnSuggestionId, quantity, placementType, inStock, impedimentComment, remainingQuantity },
})
.pipe(map((r) => r.result));
}
@@ -419,6 +427,12 @@ export class DomainRemissionService {
.pipe(map((r) => r.result));
}
returnSuggestion(itemId: number) {
return this._returnService
.ReturnReturnSuggestionImpediment({ itemId, data: { comment: 'Produkt nicht gefunden' } })
.pipe(map((r) => r.result));
}
/**
* Create a new receipt for the given return/remission
* @param returnId Return ID

View File

@@ -25,6 +25,12 @@ export class CanActivateRemissionGuard implements CanActivate {
}
this._applicationService.activateProcess(this._config.get('process.ids.remission'));
return true;
if (!!process?.data?.active && !state.url.includes(`/filiale/remission/${process?.data?.active}`)) {
await this._router.navigate(['/filiale', 'remission', process?.data?.active, 'list']);
return false;
} else {
return true;
}
}
}

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="18px" height="17px" viewBox="0 0 18 17" 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>Headphone</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="UC1_06_01_Hugendubel_Instoreapp_Kunden_Artikelrecherche_Ergebnisse_1" transform="translate(-138.000000, -570.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.7">
<path d="M153.164811,579.4098 L153.040089,579.4098 L153.040089,577.125612 C153.040089,573.765256 150.338976,571.032071 147.017817,571.032071 C143.696659,571.032071 140.995546,573.765256 140.995546,577.125612 L140.995546,579.4098 L140.870824,579.4098 C139.848107,579.4098 139,580.232962 139,581.262806 L139,584.067261 C139,585.097105 139.848107,585.930958 140.870824,585.930958 L142.763029,585.930958 C143.058797,585.930958 143.311804,585.695768 143.311804,585.4 L143.311804,579.930067 C143.311804,579.634298 143.058797,579.4098 142.763029,579.4098 L142.064588,579.4098 L142.064588,577.125612 C142.064588,574.353229 144.284633,572.101114 147.017817,572.101114 C149.751002,572.101114 151.971047,574.356793 151.971047,577.125612 L151.971047,579.4098 L151.272606,579.4098 C150.976837,579.4098 150.723831,579.634298 150.723831,579.930067 L150.723831,585.4 C150.723831,585.695768 150.976837,585.930958 151.272606,585.930958 L153.164811,585.930958 C154.187528,585.930958 155,585.097105 155,584.067261 L155,581.262806 C155,580.232962 154.187528,579.4098 153.164811,579.4098 Z M142.242762,584.861915 L140.870824,584.861915 C140.439644,584.861915 140.069042,584.509131 140.069042,584.067261 L140.069042,581.262806 C140.069042,580.820935 140.439644,580.478842 140.870824,580.478842 L142.242762,580.478842 L142.242762,584.861915 Z M153.930958,584.067261 C153.930958,584.509131 153.595991,584.861915 153.164811,584.861915 L151.792873,584.861915 L151.792873,580.478842 L153.164811,580.478842 C153.595991,580.478842 153.930958,580.824499 153.930958,581.262806 L153.930958,584.067261 Z" id="Headphone"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="20px" viewBox="0 0 14 20" 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_NB</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(-33.000000, -138.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.9">
<path d="M37.4137931,139.163636 L35.9655172,142.027273 L35.9655172,144.359091 C34.6827586,144.788636 34,145.381818 34,146.056818 L34,154.709091 C34,155.997727 36.6275862,157 40,157 C43.3724138,157 46,155.997727 46,154.729545 L46,146.077273 C46,145.484091 45.4413793,144.931818 44.4482759,144.522727 L44.4482759,139 L41.5517241,139 L41.5517241,143.868182 C40.6578753,143.780758 39.758215,143.767074 38.862069,143.827273 L38.862069,142.027273 L37.4137931,139.163636 Z M37.4137931,140.084091 L38.4482759,142.129545 L38.4482759,147.877273 C37.7478333,147.81206 37.0551354,147.681943 36.3793103,147.488636 L36.3793103,142.109091 L37.4137931,140.084091 Z M35.9655172,144.809091 L35.9655172,147.365909 C34.9724138,147.018182 34.4137931,146.547727 34.4137931,146.077273 C34.4137931,145.606818 34.9931034,145.156818 35.9655172,144.809091 Z M40,156.590909 C36.6482759,156.590909 34.4137931,155.629545 34.4137931,154.729545 L34.4137931,146.915909 C35.2827586,147.754545 37.4344828,148.347727 40,148.347727 C42.5655172,148.347727 44.7172414,147.754545 45.5862069,146.915909 L45.5862069,154.709091 C45.5862069,155.629545 43.3517241,156.590909 40,156.590909 Z M44.0344828,147.365909 C43.3639001,147.595667 42.6702492,147.753394 41.9655172,147.836364 L41.9655172,141.863636 L44.0344828,141.863636 L44.0344828,147.365909 Z M45.5862069,146.077273 C45.5862069,146.465909 45.1724138,146.854545 44.4482759,147.181818 L44.4482759,144.972727 C45.1724138,145.3 45.5862069,145.688636 45.5862069,146.077273 Z M44.0344828,139.409091 L44.0344828,141.454545 L41.9655172,141.454545 L41.9655172,139.409091 L44.0344828,139.409091 Z M41.5517241,144.277273 L41.5517241,147.877273 C41.0758621,147.918182 40.5586207,147.959091 40,147.959091 L38.862069,147.918182 L38.862069,144.256818 C39.7575696,144.187775 40.6574039,144.194618 41.5517241,144.277273 Z" id="Icon_NB"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="20px" viewBox="0 0 14 20" 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_NB</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(-33.000000, -138.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.9">
<path d="M37.4137931,139.163636 L35.9655172,142.027273 L35.9655172,144.359091 C34.6827586,144.788636 34,145.381818 34,146.056818 L34,154.709091 C34,155.997727 36.6275862,157 40,157 C43.3724138,157 46,155.997727 46,154.729545 L46,146.077273 C46,145.484091 45.4413793,144.931818 44.4482759,144.522727 L44.4482759,139 L41.5517241,139 L41.5517241,143.868182 C40.6578753,143.780758 39.758215,143.767074 38.862069,143.827273 L38.862069,142.027273 L37.4137931,139.163636 Z M37.4137931,140.084091 L38.4482759,142.129545 L38.4482759,147.877273 C37.7478333,147.81206 37.0551354,147.681943 36.3793103,147.488636 L36.3793103,142.109091 L37.4137931,140.084091 Z M35.9655172,144.809091 L35.9655172,147.365909 C34.9724138,147.018182 34.4137931,146.547727 34.4137931,146.077273 C34.4137931,145.606818 34.9931034,145.156818 35.9655172,144.809091 Z M40,156.590909 C36.6482759,156.590909 34.4137931,155.629545 34.4137931,154.729545 L34.4137931,146.915909 C35.2827586,147.754545 37.4344828,148.347727 40,148.347727 C42.5655172,148.347727 44.7172414,147.754545 45.5862069,146.915909 L45.5862069,154.709091 C45.5862069,155.629545 43.3517241,156.590909 40,156.590909 Z M44.0344828,147.365909 C43.3639001,147.595667 42.6702492,147.753394 41.9655172,147.836364 L41.9655172,141.863636 L44.0344828,141.863636 L44.0344828,147.365909 Z M45.5862069,146.077273 C45.5862069,146.465909 45.1724138,146.854545 44.4482759,147.181818 L44.4482759,144.972727 C45.1724138,145.3 45.5862069,145.688636 45.5862069,146.077273 Z M44.0344828,139.409091 L44.0344828,141.454545 L41.9655172,141.454545 L41.9655172,139.409091 L44.0344828,139.409091 Z M41.5517241,144.277273 L41.5517241,147.877273 C41.0758621,147.918182 40.5586207,147.959091 40,147.959091 L38.862069,147.918182 L38.862069,144.256818 C39.7575696,144.187775 40.6574039,144.194618 41.5517241,144.277273 Z" id="Icon_NB"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="17px" viewBox="0 0 18 17" 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>Headphone</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="UC1_06_01_Hugendubel_Instoreapp_Kunden_Artikelrecherche_Ergebnisse_1" transform="translate(-138.000000, -570.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.7">
<path d="M153.164811,579.4098 L153.040089,579.4098 L153.040089,577.125612 C153.040089,573.765256 150.338976,571.032071 147.017817,571.032071 C143.696659,571.032071 140.995546,573.765256 140.995546,577.125612 L140.995546,579.4098 L140.870824,579.4098 C139.848107,579.4098 139,580.232962 139,581.262806 L139,584.067261 C139,585.097105 139.848107,585.930958 140.870824,585.930958 L142.763029,585.930958 C143.058797,585.930958 143.311804,585.695768 143.311804,585.4 L143.311804,579.930067 C143.311804,579.634298 143.058797,579.4098 142.763029,579.4098 L142.064588,579.4098 L142.064588,577.125612 C142.064588,574.353229 144.284633,572.101114 147.017817,572.101114 C149.751002,572.101114 151.971047,574.356793 151.971047,577.125612 L151.971047,579.4098 L151.272606,579.4098 C150.976837,579.4098 150.723831,579.634298 150.723831,579.930067 L150.723831,585.4 C150.723831,585.695768 150.976837,585.930958 151.272606,585.930958 L153.164811,585.930958 C154.187528,585.930958 155,585.097105 155,584.067261 L155,581.262806 C155,580.232962 154.187528,579.4098 153.164811,579.4098 Z M142.242762,584.861915 L140.870824,584.861915 C140.439644,584.861915 140.069042,584.509131 140.069042,584.067261 L140.069042,581.262806 C140.069042,580.820935 140.439644,580.478842 140.870824,580.478842 L142.242762,580.478842 L142.242762,584.861915 Z M153.930958,584.067261 C153.930958,584.509131 153.595991,584.861915 153.164811,584.861915 L151.792873,584.861915 L151.792873,580.478842 L153.164811,580.478842 C153.595991,580.478842 153.930958,580.824499 153.930958,581.262806 L153.930958,584.067261 Z" id="Headphone"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="20px" viewBox="0 0 14 20" 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_NB</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(-33.000000, -138.000000)" fill="#000000" fill-rule="nonzero" stroke="#000000" stroke-width="0.9">
<path d="M37.4137931,139.163636 L35.9655172,142.027273 L35.9655172,144.359091 C34.6827586,144.788636 34,145.381818 34,146.056818 L34,154.709091 C34,155.997727 36.6275862,157 40,157 C43.3724138,157 46,155.997727 46,154.729545 L46,146.077273 C46,145.484091 45.4413793,144.931818 44.4482759,144.522727 L44.4482759,139 L41.5517241,139 L41.5517241,143.868182 C40.6578753,143.780758 39.758215,143.767074 38.862069,143.827273 L38.862069,142.027273 L37.4137931,139.163636 Z M37.4137931,140.084091 L38.4482759,142.129545 L38.4482759,147.877273 C37.7478333,147.81206 37.0551354,147.681943 36.3793103,147.488636 L36.3793103,142.109091 L37.4137931,140.084091 Z M35.9655172,144.809091 L35.9655172,147.365909 C34.9724138,147.018182 34.4137931,146.547727 34.4137931,146.077273 C34.4137931,145.606818 34.9931034,145.156818 35.9655172,144.809091 Z M40,156.590909 C36.6482759,156.590909 34.4137931,155.629545 34.4137931,154.729545 L34.4137931,146.915909 C35.2827586,147.754545 37.4344828,148.347727 40,148.347727 C42.5655172,148.347727 44.7172414,147.754545 45.5862069,146.915909 L45.5862069,154.709091 C45.5862069,155.629545 43.3517241,156.590909 40,156.590909 Z M44.0344828,147.365909 C43.3639001,147.595667 42.6702492,147.753394 41.9655172,147.836364 L41.9655172,141.863636 L44.0344828,141.863636 L44.0344828,147.365909 Z M45.5862069,146.077273 C45.5862069,146.465909 45.1724138,146.854545 44.4482759,147.181818 L44.4482759,144.972727 C45.1724138,145.3 45.5862069,145.688636 45.5862069,146.077273 Z M44.0344828,139.409091 L44.0344828,141.454545 L41.9655172,141.454545 L41.9655172,139.409091 L44.0344828,139.409091 Z M41.5517241,144.277273 L41.5517241,147.877273 C41.0758621,147.918182 40.5586207,147.959091 40,147.959091 L38.862069,147.918182 L38.862069,144.256818 C39.7575696,144.187775 40.6574039,144.194618 41.5517241,144.277273 Z" id="Icon_NB"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -231,7 +231,11 @@
[routerLink]="['/kunde', applicationService.activatedProcessId, 'product', 'details', 'ean', format.product.ean]"
>
<span class="format-detail">
<img [src]="'/assets/images/OF_Icon_' + format.product?.format + '.svg'" alt="format icon" />
<img
*ngIf="!!format.product?.format"
[src]="'/assets/images/OF_Icon_' + format.product?.format + '.svg'"
alt="format icon"
/>
{{ format.product?.formatDetail }}
<span class="price">{{ format.catalogAvailability?.price?.value?.value | currency: '€' }}</span>
</span>

View File

@@ -9,6 +9,7 @@ import { shareReplay } from 'rxjs/operators';
selector: 'page-purchasing-options-modal-price-input',
templateUrl: 'purchasing-options-modal-price-input.component.html',
styleUrls: ['purchasing-options-modal-price-input.component.scss'],
providers: [FormBuilder],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PurchasingOptionsModalPriceInputComponent implements OnInit {

View File

@@ -170,7 +170,7 @@ export class PurchasingOptionsModalComponent {
);
quantityRange$ = combineLatest([this.option$, this.availability$]).pipe(
map(([option, availability]) => (option === 'take-away' ? availability.inStock : 999))
map(([option, availability]) => (option === 'take-away' && availability?.inStock ? availability.inStock : 999))
);
activeSpinner: string;

View File

@@ -135,7 +135,7 @@ export class CustomerCreateOnlineComponent extends CustomerCreateComponentBase i
email: fb.control(
customer?.communicationDetails?.email,
[Validators.required, validateEmail, this.emailDomainErrorValidator],
[this.emailExistsValidator]
[this.emailExistsValidator()]
),
phone: fb.control(customer?.communicationDetails?.phone, [UiValidators.phone]),
mobile: fb.control(customer?.communicationDetails?.mobile, [UiValidators.phone]),

View File

@@ -1,9 +1,9 @@
import { AbstractControl, AsyncValidatorFn, FormArray, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import { AbstractControl, AsyncValidatorFn, FormArray, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { CrmCustomerService } from '@domain/crm';
import { CountryDTO, CustomerDTO, InputOptionsDTO, KeyValueDTOOfStringAndString } from '@swagger/crm';
import { Observable } from 'rxjs';
import { first, map } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged, first, map, switchMap } from 'rxjs/operators';
import { UiModalService } from '@ui/modal';
import { BreadcrumbService } from '@core/breadcrumb';
import { ApplicationService } from '@core/application';
@@ -14,17 +14,32 @@ import { isBoolean } from '@utils/common';
import { setInvalidPropertyErrors } from '@ui/validators';
import { camelCase } from 'lodash';
import { validateEmail } from '../validators/email-validator';
import { HttpErrorResponse } from '@angular/common/http';
export abstract class CustomerCreateComponentBase {
emailExistsValidator: AsyncValidatorFn = async (control): Promise<ValidationErrors | null> => {
if (control.value) {
if ((await this.customerService.emailExists(control.value).toPromise())?.result) {
return { exists: 'E-Mail existiert bereits' };
}
}
return null;
};
emailExistsValidator(): AsyncValidatorFn {
return (control) =>
control.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap((value) => this.customerService.emailExists(value)),
map((result) => {
if (result?.result) {
return { exists: result?.message ? result.message : 'E-Mail existiert bereits' };
}
}),
catchError((error) => {
if (error instanceof HttpErrorResponse) {
if (error?.error?.invalidProperties?.email) {
return of({ invalid: error.error.invalidProperties.email });
} else {
return of({ invalid: 'E-Mail ist ungültig' });
}
}
}),
first()
);
}
type: string;
control: FormGroup;

View File

@@ -70,8 +70,4 @@
<a *ngIf="listEmpty$ | async" class="cta-action cta-action-secondary" [routerLink]="['/filiale', 'goods', 'in']">
Zur Bestellpostensuche
</a>
<a *ngIf="listEmpty$ | async" class="cta-action cta-action-primary" [routerLink]="['/filiale', 'remission', 'create']">
Zur Remission
</a>
</div>

View File

@@ -59,4 +59,12 @@
<ui-spinner [show]="(changeActionLoader$ | async) || (loading$ | async)">{{ action.label }}</ui-spinner>
</button>
</ng-container>
<a *ngIf="listEmpty$ | async" class="cta-action cta-action-secondary" [routerLink]="['/filiale', 'goods', 'in']">
Zur Bestellpostensuche
</a>
<a *ngIf="listEmpty$ | async" class="cta-action cta-action-primary" [routerLink]="['/filiale', 'remission']">
Zur Remission
</a>
</div>

View File

@@ -47,6 +47,10 @@
.cta-action-primary {
@apply bg-brand text-white;
}
.cta-action-secondary {
@apply bg-white text-brand;
}
}
shared-goods-in-out-order-group-item {

View File

@@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { GoodsInOutOrderGroupModule } from '@shared/goods-in-out';
import { UiCommonModule } from '@ui/common';
import { UiScrollContainerModule } from '@ui/scroll-container';
@@ -8,7 +9,7 @@ import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
import { GoodsInRemissionPreviewComponent } from './goods-in-remission-preview.component';
@NgModule({
imports: [CommonModule, UiCommonModule, UiScrollContainerModule, UiSpinnerModule, GoodsInOutOrderGroupModule],
imports: [CommonModule, UiCommonModule, UiScrollContainerModule, UiSpinnerModule, GoodsInOutOrderGroupModule, RouterModule],
exports: [GoodsInRemissionPreviewComponent],
declarations: [GoodsInRemissionPreviewComponent],
providers: [],

View File

@@ -17,12 +17,20 @@ export class CreateRemissionComponent implements OnInit {
@ViewChild(UiSearchboxNextComponent)
searchboxComponent: UiSearchboxNextComponent;
get processId() {
return this._config.get('process.ids.remission');
}
loading$ = new Subject<boolean>();
hint$ = new Subject<string>();
get supplierId(): number {
return +this._activatedRoute?.snapshot?.queryParams?.supplierId;
return +this._activatedRoute?.snapshot?.queryParams?.supplier;
}
get source(): string {
return this._activatedRoute?.snapshot?.queryParams?.source;
}
constructor(
@@ -34,8 +42,9 @@ export class CreateRemissionComponent implements OnInit {
private readonly _config: Config
) {}
ngOnInit(): void {
this.addBreadcrumbIfNotExists();
async ngOnInit() {
await this.removeBreadcrumbs();
await this.addBreadcrumbIfNotExists();
}
async startRemission(receiptNumber?: string) {
@@ -71,11 +80,13 @@ export class CreateRemissionComponent implements OnInit {
}
async navigateToList(returnId: number) {
await this._router.navigate(['/filiale', 'remission', returnId, 'list']);
await this._router.navigate(['/filiale', 'remission', returnId, 'list'], {
queryParams: { ...this._activatedRoute.snapshot.queryParams, supplier: this.supplierId, source: this.source },
});
}
addBreadcrumbIfNotExists() {
this._breadcrumb.addBreadcrumbIfNotExists({
async addBreadcrumbIfNotExists() {
await this._breadcrumb.addBreadcrumbIfNotExists({
key: this._config.get('process.ids.remission'),
name: 'Warenbegleitschein eröffnen',
path: '/filiale/remission/create',
@@ -84,4 +95,11 @@ export class CreateRemissionComponent implements OnInit {
tags: ['remission', 'create'],
});
}
async removeBreadcrumbs() {
await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'shipping-documents']);
await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'add-product']);
await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'finish-shipping-document']);
await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this.processId, ['remission', 'finish-remission']);
}
}

View File

@@ -1,6 +1,8 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { CacheService } from '@core/cache';
import { Config } from '@core/config';
import { DomainRemissionService } from '@domain/remission';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
@@ -11,28 +13,39 @@ import { UiErrorModalComponent, UiModalService } from '@ui/modal';
styleUrls: ['finish-remission.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FinishRemissionComponent implements OnInit {
export class FinishRemissionComponent implements OnInit, OnDestroy {
get processId() {
return this._config.get('process.ids.remission');
}
constructor(
private _activatedRoute: ActivatedRoute,
private _applicationService: ApplicationService,
private _modal: UiModalService,
private _remissionService: DomainRemissionService,
private _router: Router,
private _breadcrumb: BreadcrumbService,
private _config: Config
private _config: Config,
private _cache: CacheService
) {}
ngOnInit() {
this.addBreadcrumbIfNotExists();
}
ngOnDestroy(): void {
this._cache.delete({ processId: String(this.processId) });
}
async createRemission() {
const returnId = +this._activatedRoute.snapshot.params?.returnId;
if (returnId) {
try {
const returnDto = await this._remissionService.getReturn(returnId).toPromise();
this._router.navigate(['/filiale', 'remission', 'create', returnDto.returnGroup], {
queryParams: { supplierId: returnDto.supplier.id },
this.clearProcessData();
await this._router.navigate(['/filiale', 'remission', 'create', returnDto.returnGroup], {
queryParams: { ...this._activatedRoute.snapshot.queryParams },
});
} catch (err) {
this._modal.open({
@@ -56,7 +69,8 @@ export class FinishRemissionComponent implements OnInit {
if (returnId) {
try {
await this._remissionService.completeRemission(returnId);
this.navigateToList();
this.clearProcessData();
await this.navigateToList();
} catch (err) {
this._modal.open({
content: UiErrorModalComponent,
@@ -73,8 +87,16 @@ export class FinishRemissionComponent implements OnInit {
}
}
navigateToList() {
this._router.navigate(['/filiale', 'remission', 'list']);
async navigateToList() {
await this._router.navigate(['/filiale', 'remission', 'list']);
}
clearProcessData() {
// Muss beim Abschließen der Remission erfolgen, da er sonst auf die Liste routet (siehe remission.component.ts updateProcess())
this._applicationService.patchProcess(this.processId, {
closeable: true,
data: {},
});
}
addBreadcrumbIfNotExists() {

View File

@@ -122,7 +122,25 @@ export class FinishShippingDocumentComponent implements OnInit, OnDestroy {
}
async navigateToFinishRemission() {
await this._router.navigate(['../../', 'finish-remission'], { relativeTo: this._activatedRoute });
await this._router.navigate(['../../', 'finish-remission'], {
relativeTo: this._activatedRoute,
queryParams: { ...this.cleanupQueryParams(this._activatedRoute.snapshot.queryParams) },
});
}
cleanupQueryParams(params: Record<string, string> = {}) {
const clean = { ...params };
delete clean['scroll_position'];
for (const key in clean) {
if (Object.prototype.hasOwnProperty.call(clean, key)) {
if (clean[key] == undefined) {
delete clean[key];
}
}
}
return clean;
}
addBreadcrumbIfNotExists() {

View File

@@ -1,5 +1,7 @@
import { Component, ChangeDetectionStrategy, OnDestroy } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { CacheService } from '@core/cache';
import { Config } from '@core/config';
import { DomainRemissionService } from '@domain/remission';
import { ReturnItemDTO } from '@swagger/remi';
import { UiErrorModalComponent, UiModalRef, UiModalService } from '@ui/modal';
@@ -16,6 +18,10 @@ import { AddProductModalData } from './add-product-modal.data';
export class AddProductModalComponent implements OnDestroy {
private _onDestroy$ = new Subject();
get processId() {
return this._config.get('process.ids.remission');
}
message$ = new BehaviorSubject<string>(undefined);
item: ReturnItemDTO;
@@ -35,7 +41,9 @@ export class AddProductModalComponent implements OnDestroy {
constructor(
private _modalRef: UiModalRef<boolean, AddProductModalData>,
private _remiService: DomainRemissionService,
private _modal: UiModalService
private _modal: UiModalService,
private _config: Config,
private _cache: CacheService
) {
this.item = this._modalRef.data.item;
@@ -67,6 +75,7 @@ export class AddProductModalComponent implements OnDestroy {
try {
await this._remiService.addProductToRemit(this.item, this.selectedReason, this.form.value.quantity).pipe(first()).toPromise();
this._cache.delete({ processId: String(this.processId) });
this._modalRef.close(true);
} catch (err) {
this._modalRef.close();

View File

@@ -11,6 +11,9 @@ import { UiModalRef } from '@ui/modal';
})
export class AddProductToShippingDocumentModalComponent implements OnInit {
validateQuantity(c: FormControl): ValidationErrors | null {
if (!c.value) {
return { invalid: 'Menge wird benötigt' };
}
return c.value < 0 || c.value > 1000 ? { invalid: 'Menge ist ungültig' } : null;
}
@@ -21,8 +24,8 @@ export class AddProductToShippingDocumentModalComponent implements OnInit {
ngOnInit() {
this.form = new FormGroup({
placementType: new FormControl(''),
quantity: new FormControl(1, [Validators.required, this.validateQuantity]),
placementType: new FormControl(this._modalRef?.data?.item?.placementType ?? ''),
quantity: new FormControl(1, [this.validateQuantity]),
});
}
@@ -31,6 +34,10 @@ export class AddProductToShippingDocumentModalComponent implements OnInit {
}
async remit() {
this._modalRef.close({ action: 'remit', quantity: this.form.value.quantity, placementType: this.form.value.placementType });
if (this.form.value.quantity == 0) {
this.notFound();
} else {
this._modalRef.close({ action: 'remit', quantity: this.form.value.quantity, placementType: this.form.value.placementType });
}
}
}

View File

@@ -14,17 +14,15 @@
></ui-filter>
<div class="sticky-cta-wrapper">
<button class="cta-reset-filter" [class.loading]="store.fetching$ | async" (click)="resetFilter()">
<span *ngIf="!(store.fetching$ | async)">
<button class="cta-reset-filter" (click)="resetFilter()">
<span>
Filter zurücksetzen
</span>
<ui-icon class="spin" *ngIf="store.fetching$ | async" icon="loading" size="26px"></ui-icon>
</button>
<button class="apply-filter" [class.loading]="store.fetching$ | async" (click)="applyFilter(filter)">
<span *ngIf="!(store.fetching$ | async)">
<button class="apply-filter" (click)="applyFilter(filter)">
<span>
Filter anwenden
</span>
<ui-icon class="spin" *ngIf="store.fetching$ | async" icon="loading" size="26px"></ui-icon>
</button>
</div>
</ng-container>

View File

@@ -34,8 +34,13 @@
</div>
<div class="grid grid-flow-row gap-1 w-48">
<div class="overflow-hidden overflow-ellipsis whitespace-nowrap">
<img class="inline" src="/assets/images/Icon_{{ item.dto.product.format }}.svg" [alt]="item.formatDetail" />
<div class="overflow-hidden overflow-ellipsis whitespace-nowrap" *ngIf="!!item.formatDetail">
<img
*ngIf="!!item.dto.product.format"
class="inline"
src="/assets/images/Icon_{{ item.dto.product.format }}.svg"
[alt]="item.formatDetail"
/>
<span class="ml-1 font-bold">{{ item.formatDetail }}</span>
</div>
<div class="font-bold">

View File

@@ -53,7 +53,7 @@ export class RemissionListItemComponent implements OnDestroy {
addProductToShippingDocument() {
const modal = this._modal.open({
content: AddProductToShippingDocumentModalComponent,
title: 'Remimenge / Platzierung ändern',
title: 'Remi-Menge / Platzierung ändern',
data: {
item: this.item,
returnDto: this.returnDto,
@@ -62,7 +62,12 @@ export class RemissionListItemComponent implements OnDestroy {
modal.afterClosed$.pipe(takeUntil(this._onDestroy$)).subscribe((result) => {
if (result?.data?.action === 'remit') {
this.addReturnItemOrSuggestion({ quantity: result.data.quantity, placementType: result.data.placementType });
this.addReturnItemOrSuggestion({
quantity: result.data.quantity,
placementType: result.data.placementType,
impedimentComment: this.item.remissionQuantity > result.data.quantity ? 'Restmenge' : '',
remainingQuantity: this.item.inStock - result.data.quantity <= 0 ? null : this.item.inStock - result.data.quantity,
});
} else if (result?.data?.action === 'notFound') {
this.returnImpediment();
}
@@ -93,6 +98,8 @@ export class RemissionListItemComponent implements OnDestroy {
async removeReturnItem() {
try {
this._store.clearItems();
this._store.setFetching(true);
await this._remissionService.removeReturnItemFromList({ itemId: this.item?.dto?.id }).toPromise();
this.reload();
} catch (err) {
@@ -104,9 +111,20 @@ export class RemissionListItemComponent implements OnDestroy {
}
}
async addReturnItemOrSuggestion({ quantity, placementType }: { quantity?: number; placementType?: RemissionPlacementType }) {
async addReturnItemOrSuggestion({
quantity,
placementType,
impedimentComment,
remainingQuantity,
}: {
quantity?: number;
placementType?: RemissionPlacementType;
impedimentComment?: string;
remainingQuantity?: number;
}) {
try {
this._store.removeItem(this.item);
this._store.clearItems();
this._store.setFetching(true);
// Pflichtremission
if (this.item.dtoType === 'return') {
@@ -131,6 +149,8 @@ export class RemissionListItemComponent implements OnDestroy {
inStock: this.item.inStock,
quantity,
placementType,
impedimentComment,
remainingQuantity,
})
.toPromise();
}
@@ -147,9 +167,17 @@ export class RemissionListItemComponent implements OnDestroy {
async returnImpediment() {
try {
this._store.removeItem(this.item);
this._store.clearItems();
this._store.setFetching(true);
await this._remissionService.returnImpediment(this.item.dto?.id).toPromise();
// Pflichtremission
if (this.item.dtoType === 'return') {
await this._remissionService.returnImpediment(this.item.dto?.id).toPromise();
}
// Abteilungsremission
else if (this.item.dtoType === 'suggestion') {
await this._remissionService.returnSuggestion(this.item.dto?.id).toPromise();
}
this.reload();
} catch (err) {

View File

@@ -7,7 +7,7 @@ import { ComponentStore, tapResponse } from '@ngrx/component-store';
import { SupplierDTO } from '@swagger/remi';
import { UiFilter } from '@ui/filter';
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
import { debounceTime, filter, switchMap, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
import { debounceTime, filter, switchMap, takeLast, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
export interface RemissionState {
suppliers: SupplierDTO[];
@@ -156,13 +156,12 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
}
initSearch() {
combineLatest([this._sourceOrSupplierChange$, this._filterChange$, this._activatedRoute.queryParams])
combineLatest([this._sourceOrSupplierChange$, this._filterChange$])
.pipe(debounceTime(500), takeUntil(this._onDestroy$))
.subscribe(([change, filter, queryParams]) => {
const data = this.getCachedData(queryParams);
.subscribe(([change, filter]) => {
const data = this.getCachedData();
if (change || data.items?.length === 0 || filter) {
this.setFetching(true);
this.setSearchResult({ result: [], hits: 0 });
this.clearItems();
this.search({ newSearch: true });
}
});
@@ -220,9 +219,9 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
loadFilter = this.effect(($) =>
$.pipe(
tap((_) => this.setFetching(true)),
withLatestFrom(this.selectedSupplier$, this.selectedSource$),
withLatestFrom(this.selectedSupplier$, this.selectedSource$, this._activatedRoute.queryParams),
filter(([, selectedSupplier, selectedSource]) => !!selectedSupplier?.id && !!selectedSource),
switchMap(([, selectedSupplier, selectedSource]) =>
switchMap(([, selectedSupplier, selectedSource, queryParams]) =>
this._domainRemissionService
.getQuerySettings({
supplierId: selectedSupplier.id,
@@ -234,7 +233,13 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
// Filtergruppen ausblenden, wenn keine Werte innerhalb des Filters für die Anzeige vorhanden sind
settings?.filter?.forEach((filter) => (filter.input = filter.input?.filter((input) => input.options?.values?.length > 0)));
this.setFilter(UiFilter.create(settings));
const filter = UiFilter.create(settings);
if (!!queryParams) {
filter?.fromQueryParams(queryParams);
}
this.setFilter(filter);
this.items ? this.setFetching(false) : '';
},
(err) => {}
@@ -342,39 +347,28 @@ export class RemissionListComponentStore extends ComponentStore<RemissionState>
requiredCapacities,
}));
cacheCurrentData(params: Record<string, string> = {}) {
const qparams = this.cleanupQueryParams({ ...params, processId: String(this.processId) });
this._cache.set(qparams, {
items: this.items,
hits: this.hits,
});
cacheCurrentData() {
this._cache.set(
{ processId: String(this.processId) },
{
items: this.items,
hits: this.hits,
}
);
}
getCachedData(params: Record<string, string> = {}) {
const qparams = this.cleanupQueryParams({ ...params, processId: String(this.processId) });
getCachedData() {
return (
this._cache.get<{
items: RemissionListItem[];
hits: number;
}>(qparams) || { items: [], hits: 0 }
}>({ processId: String(this.processId) }) || { items: [], hits: 0 }
);
}
cleanupQueryParams(params: Record<string, string> = {}) {
const clean = { ...params };
delete clean['scroll_position'];
for (const key in clean) {
if (Object.prototype.hasOwnProperty.call(clean, key)) {
if (clean[key] == undefined) {
delete clean[key];
}
}
}
return clean;
clearItems() {
this.setFetching(true);
this.setSearchResult({ result: [], hits: 0 });
}
async setSupplier(supplier: SupplierDTO) {

View File

@@ -1,4 +1,4 @@
<button [disabled]="fetching$ | async" class="filter" (click)="shellFilterOverlay.open()">
<button class="filter" (click)="shellFilterOverlay.open()">
<ui-icon size="20px" icon="filter_alit"></ui-icon>
<span class="label">Filter</span>
</button>
@@ -81,7 +81,7 @@
<a
*ngIf="showStartRemissionAction$ | async"
routerLink="../create"
[queryParams]="{ supplierId: selectedSupplierId$ | async }"
[queryParams]="queryParams$ | async"
routerLinkParam
class="bg-brand text-white font-bold text-lg px-6 py-3 rounded-full"
>

View File

@@ -3,6 +3,7 @@ import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild, ViewC
import { ActivatedRoute, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { Config } from '@core/config';
import { RemissionListItem } from '@domain/remission';
import { SupplierDTO } from '@swagger/remi';
import { Subject, combineLatest, BehaviorSubject } from 'rxjs';
@@ -25,6 +26,10 @@ export class RemissionListComponent implements OnInit, OnDestroy {
private _onDestroy$ = new Subject();
get processId() {
return this._config.get('process.ids.remission');
}
get suppliers$() {
return this._remissionListStore.suppliers$;
}
@@ -65,17 +70,24 @@ export class RemissionListComponent implements OnInit, OnDestroy {
return this._remissionStore.return$;
}
get queryParams$() {
return this._activatedRoute.queryParams.pipe(
withLatestFrom(this._remissionListStore.filter$, this.selectedSupplierId$, this.selectedSource$),
map(([params, filter, supplier, source]) => {
let queryParams = params;
if (filter) {
queryParams = { ...filter.getQueryParams(), ...params, supplier, source };
}
return queryParams;
})
);
}
get returnCount$() {
return this._remissionStore.returnCount$;
}
get queryParams$() {
return this._activatedRoute.queryParams;
}
showStartRemissionAction$ = combineLatest([this.fetching$, this.hits$, this.return$]).pipe(
map(([fetching, hits, r]) => !fetching && hits > 0 && !r)
);
showStartRemissionAction$ = combineLatest([this.hits$, this.return$]).pipe(map(([hits, r]) => hits > 0 && !r));
filteredSuppliers$ = combineLatest([this._remissionStore.uncompleted$, this.suppliers$, this.selectedSupplier$]).pipe(
map(([uncompleted, suppliers, selectedSupplier]) => {
@@ -96,7 +108,8 @@ export class RemissionListComponent implements OnInit, OnDestroy {
private readonly _router: Router,
private readonly _activatedRoute: ActivatedRoute,
private readonly _breadcrumb: BreadcrumbService,
private readonly _applicationService: ApplicationService
private readonly _applicationService: ApplicationService,
private readonly _config: Config
) {}
ngOnInit() {
@@ -105,11 +118,12 @@ export class RemissionListComponent implements OnInit, OnDestroy {
if (supplier) {
this._remissionListStore.setSelectedSupplierId(+supplier);
}
if (source) {
this._remissionListStore.setSelectedSource(source);
}
const data = this._remissionListStore.getCachedData(queryParams);
const data = this._remissionListStore.getCachedData();
if (data.items?.length !== 0) {
this._remissionListStore.setItems(data.items);
this._remissionListStore.setHits(data.hits);
@@ -131,8 +145,10 @@ export class RemissionListComponent implements OnInit, OnDestroy {
this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
const id = +params.returnId;
if (!!id) {
// Remission wurde gestartet
this._remissionStore.getReturn(id);
} else {
// Für die Anzahl der Warenbegleitscheine, wenn keine Remission gestartet wurde
this._remissionStore.getReturns(false);
}
});
@@ -156,8 +172,8 @@ export class RemissionListComponent implements OnInit, OnDestroy {
this._onDestroy$.complete();
if (!!this._remissionStore.return) {
this._remissionListStore.cacheCurrentData();
const params = await this._activatedRoute.queryParams.pipe(first()).toPromise();
this._remissionListStore.cacheCurrentData(params);
await this.updateBreadcrumb(params);
}
}

View File

@@ -2,6 +2,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { CacheService } from '@core/cache';
import { Config } from '@core/config';
import { Subject } from 'rxjs';
import { filter, first, takeUntil } from 'rxjs/operators';
@@ -23,11 +24,13 @@ export class RemissionComponent implements OnInit, OnDestroy {
private readonly _config: Config,
private _activatedRoute: ActivatedRoute,
private _applicationService: ApplicationService,
private _router: Router
private _router: Router,
private _cache: CacheService
) {}
ngOnInit(): void {
this.addBreadcrumbIfNotExists();
this.clearCache();
this._router.events
?.pipe(
@@ -59,7 +62,6 @@ export class RemissionComponent implements OnInit, OnDestroy {
async updateProcess() {
const params = this._activatedRoute.snapshot.firstChild.params;
const process = await this._applicationService.getProcessById$(this.processId).pipe(first()).toPromise();
if (!!params?.returnId) {
if (process?.data?.active !== +params.returnId) {
this._applicationService.patchProcess(this.processId, {
@@ -67,8 +69,6 @@ export class RemissionComponent implements OnInit, OnDestroy {
data: { active: +params.returnId },
});
}
} else if (!!process?.data?.active) {
this._router.navigate(['./', process?.data?.active, 'list'], { relativeTo: this._activatedRoute });
} else {
this._applicationService.patchProcess(this.processId, {
closeable: true,
@@ -76,4 +76,8 @@ export class RemissionComponent implements OnInit, OnDestroy {
});
}
}
clearCache() {
this._cache.delete({ processId: String(this.processId) });
}
}

View File

@@ -70,3 +70,5 @@
>
</page-shared-shipping-document-details-item>
</ng-template>
<div class="spacer"></div>

View File

@@ -1,3 +1,7 @@
:host {
@apply grid grid-flow-row gap-px-2;
}
.spacer {
height: 7.5rem;
}

View File

@@ -36,6 +36,7 @@
</a>
<button
[routerLink]="['..', 'finish-shipping-document', firstReceiptId$ | async]"
[queryParams]="queryParams$ | async"
[disabled]="finishShippingDocumentDisabled$ | async"
class="bg-brand text-white font-bold text-lg px-6 py-3 rounded-full shadow-cta whitespace-nowrap"
>

View File

@@ -131,14 +131,15 @@ export class ShippingDocumentDetailsComponent extends ComponentStore<ShippingDoc
}
deleted() {
this._cache.delete({ processId: String(this.processId) });
this.navigateBack();
}
reloadReturn = this.effect(($) =>
$.pipe(
tap((_) => {
this.getReturn();
this._cache.delete({ processId: String(this.processId) });
this.getReturn();
})
)
);

View File

@@ -3,7 +3,11 @@
</div>
<div class="actions">
<button class="cancel-btn" (click)="close()">Abbrechen</button>
<button class="repeat-btn" (click)="repeat()">Wiederholen</button>
<button class="send-btn" (click)="send()">Absenden</button>
<button class="cancel-btn" (click)="close()" [disabled]="loading$ | async">Abbrechen</button>
<button class="repeat-btn" (click)="repeat()" [disabled]="loading$ | async">Wiederholen</button>
<button class="send-btn" (click)="send()" [disabled]="loading$ | async">
<ui-spinner [show]="loading$ | async">
Absenden
</ui-spinner>
</button>
</div>

View File

@@ -18,4 +18,10 @@
.repeat-btn {
@apply text-brand border-none outline-none bg-white font-bold text-lg px-4 py-2 rounded-full ml-2;
}
button {
&:disabled {
@apply bg-inactive-branch text-white border-none;
}
}
}

View File

@@ -1,5 +1,7 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core';
import { UiModalRef } from '@ui/modal';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { DomainTaskCalendarService } from '@domain/task-calendar';
import { UiErrorModalComponent, UiModalRef, UiModalService } from '@ui/modal';
import { BehaviorSubject } from 'rxjs';
@Component({
selector: 'camera-capture-modal',
@@ -8,21 +10,38 @@ import { UiModalRef } from '@ui/modal';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CameraCaptureModalComponent {
loading$ = new BehaviorSubject<boolean>(false);
infoId: number;
image: string;
constructor(private modalRef: UiModalRef<string>) {
this.image = this.modalRef.data;
constructor(
private _modalRef: UiModalRef<string, { image: string; infoId: number }>,
private _domainTaskCalendarService: DomainTaskCalendarService,
private _uiModal: UiModalService
) {
this.image = this._modalRef.data.image;
this.infoId = this._modalRef.data.infoId;
}
close() {
this.modalRef.close();
this._modalRef.close();
}
repeat() {
this.modalRef.close('');
this._modalRef.close('');
}
send() {
this.modalRef.close(this.image);
async send() {
this.loading$.next(true);
try {
// TODO: Image Compression compressor.js
await this._domainTaskCalendarService.complete({ infoId: this.infoId, file: this.image }).toPromise();
} catch (err) {
this._uiModal.open({ content: UiErrorModalComponent, data: err, title: 'Fehler beim Hochladen' });
}
this._modalRef.close(this.image);
this.loading$.next(false);
}
}

View File

@@ -1,9 +1,11 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { UiSpinnerModule } from '@ui/spinner';
import { CameraCaptureModalComponent } from './camera-capture-modal.component';
@NgModule({
imports: [],
imports: [CommonModule, UiSpinnerModule],
exports: [CameraCaptureModalComponent],
declarations: [CameraCaptureModalComponent],
})

View File

@@ -150,14 +150,15 @@ export class TaskModalComponent {
cameraCapture(image: string) {
const modalRef = this.uiModal.open({
content: CameraCaptureModalComponent,
data: image,
data: {
image,
infoId: this.info.id,
},
});
modalRef.afterClosed$.subscribe(async (result) => {
if (result.data === '') {
this.captureInput?.nativeElement?.click();
} else if (result.data?.length > 0) {
// TODO: Image Compression compressor.js
await this.domainTaskCalendarService.complete({ infoId: this.info.id, file: result.data }).toPromise();
this.close();
}
});
@@ -167,7 +168,6 @@ export class TaskModalComponent {
if (!this.isIpad) {
event.preventDefault();
event.stopImmediatePropagation();
this.uiModal.open({
content: UiMessageModalComponent,
title: 'Fotonachweis - bitte wechseln Sie auf ein mobiles Gerät',

View File

@@ -43,9 +43,15 @@ jobs:
displayName: Unit Tests
pool:
name: 'Default'
demands:
- Agent.OS -equals Linux
- docker
${{ if eq(variables['Build.SourceBranchName'], 'develop') }}:
demands:
- Agent.Name -equals parfsebuild02_linux_3
- Agent.OS -equals Linux
- docker
${{ else }}:
demands:
- Agent.OS -equals Linux
- docker
steps:
- task: npmAuthenticate@0
displayName: 'npm auth'
@@ -100,9 +106,15 @@ jobs:
displayName: ISAClient CI Debug
pool:
name: 'Default'
demands:
- Agent.OS -equals Linux
- docker
${{ if eq(variables['Build.SourceBranchName'], 'develop') }}:
demands:
- Agent.Name -equals parfsebuild02_linux_3
- Agent.OS -equals Linux
- docker
${{ else }}:
demands:
- Agent.OS -equals Linux
- docker
# condition: eq(variables['Build.SourceBranch'], 'refs/heads/develop')
condition: and(ne(variables['Build.SourceBranch'], 'refs/heads/integration'), ne(variables['Build.SourceBranch'], 'refs/heads/master'), not(startsWith(variables['Build.SourceBranch'], 'refs/heads/hotfix/')), not(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/')))
steps:

34
package-lock.json generated
View File

@@ -5549,7 +5549,7 @@
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/balanced-match/-/balanced-match-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base": {
@@ -6636,7 +6636,7 @@
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/core-util-is/-/core-util-is-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
@@ -7278,7 +7278,7 @@
},
"decamelize-keys": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
"integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
"dev": true,
"requires": {
@@ -7316,7 +7316,7 @@
},
"deep-freeze-strict": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/deep-freeze-strict/-/deep-freeze-strict-1.1.1.tgz",
"integrity": "sha1-d9BYPKJKab5LvZrC+uQV1VUj5bA=",
"dev": true
},
@@ -8447,7 +8447,7 @@
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
},
@@ -8991,7 +8991,7 @@
},
"globjoin": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/globjoin/-/globjoin-0.1.4.tgz",
"integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=",
"dev": true
},
@@ -9084,7 +9084,7 @@
"dependencies": {
"isarray": {
"version": "2.0.1",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/isarray/-/isarray-2.0.1.tgz",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
"integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
}
}
@@ -10151,7 +10151,7 @@
},
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
"dev": true
},
@@ -11276,7 +11276,7 @@
},
"lines-and-columns": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
"dev": true
},
@@ -11681,7 +11681,7 @@
},
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true
},
@@ -12545,7 +12545,7 @@
},
"normalize-selector": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/normalize-selector/-/normalize-selector-0.2.0.tgz",
"integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
"dev": true
},
@@ -14492,7 +14492,7 @@
},
"postcss-media-query-parser": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz",
"integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=",
"dev": true
},
@@ -15111,7 +15111,7 @@
},
"postcss-resolve-nested-selector": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
"integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=",
"dev": true
},
@@ -16628,7 +16628,7 @@
},
"retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/retry/-/retry-0.12.0.tgz",
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
"dev": true
},
@@ -17897,7 +17897,7 @@
},
"style-search": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/style-search/-/style-search-0.1.0.tgz",
"integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=",
"dev": true
},
@@ -18300,7 +18300,7 @@
},
"svg-tags": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/svg-tags/-/svg-tags-1.0.0.tgz",
"integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
"dev": true
},
@@ -18749,7 +18749,7 @@
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"resolved": "https://pkgs.dev.azure.com/hugendubel/_packaging/hugendubel/npm/registry/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
},
"to-object-path": {