Merge branch 'develop' into release/3.0

This commit is contained in:
Nino
2023-10-19 13:26:35 +02:00
287 changed files with 6083 additions and 626 deletions

View File

@@ -1,5 +1,5 @@
import { Injectable, inject } from '@angular/core';
import { AbholfachService, ListResponseArgsOfDBHOrderItemListItemDTO, OrderItemProcessingStatusValue, QueryTokenDTO } from '@swagger/oms';
import { AbholfachService, AutocompleteTokenDTO, ListResponseArgsOfDBHOrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
import { PickupShelfIOService } from './pickup-shelf-io.service';
import { Observable, throwError } from 'rxjs';
@@ -15,6 +15,10 @@ export class PickupShelfInService extends PickupShelfIOService {
return this._abholfachService.AbholfachWareneingang(queryToken);
}
complete(autocompleteToken: AutocompleteTokenDTO) {
return this._abholfachService.AbholfachWareneingangAutocomplete(autocompleteToken);
}
getOrderItemsByOrderNumberOrCompartmentCode(args: {
orderNumber?: string;
compartmentCode?: string;

View File

@@ -1,8 +1,9 @@
import { Injectable } from '@angular/core';
import {
AutocompleteTokenDTO,
ListResponseArgsOfDBHOrderItemListItemDTO,
OrderItemProcessingStatusValue,
QueryTokenDTO,
ResponseArgsOfIEnumerableOfAutocompleteDTO,
ResponseArgsOfQuerySettingsDTO,
} from '@swagger/oms';
import { Observable } from 'rxjs';
@@ -13,6 +14,8 @@ export abstract class PickupShelfIOService {
abstract search(queryToken: QueryTokenDTO): Observable<ListResponseArgsOfDBHOrderItemListItemDTO>;
abstract complete(autocompleteToken: AutocompleteTokenDTO): Observable<ResponseArgsOfIEnumerableOfAutocompleteDTO>;
abstract getOrderItemsByOrderNumberOrCompartmentCode(args: {
orderNumber?: string;
compartmentCode?: string;

View File

@@ -1,5 +1,5 @@
import { Injectable, inject } from '@angular/core';
import { AbholfachService, ListResponseArgsOfDBHOrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
import { AbholfachService, AutocompleteTokenDTO, ListResponseArgsOfDBHOrderItemListItemDTO, QueryTokenDTO } from '@swagger/oms';
import { PickupShelfIOService } from './pickup-shelf-io.service';
import { Observable, throwError } from 'rxjs';
@@ -15,6 +15,10 @@ export class PickupShelfOutService extends PickupShelfIOService {
return this._abholfachService.AbholfachWarenausgabe(queryToken);
}
complete(autocompleteToken: AutocompleteTokenDTO) {
return this._abholfachService.AbholfachWarenausgabeAutocomplete(autocompleteToken);
}
getOrderItemsByOrderNumberOrCompartmentCode(args: {
orderNumber?: string;
compartmentCode?: string;

View File

@@ -1,5 +1,5 @@
import { Injectable, inject } from '@angular/core';
import { DBHOrderItemListItemDTO, OrderItemSubsetDTO, OrderService } from '@swagger/oms';
import { DBHOrderItemListItemDTO, OrderItemDTO, OrderItemSubsetDTO, OrderService } from '@swagger/oms';
@Injectable({ providedIn: 'root' })
export class PickupShelfService {
@@ -8,7 +8,6 @@ export class PickupShelfService {
getOrderByOrderId(orderId: number) {
return this._orderService.OrderGetOrder(orderId);
}
patchOrderItemSubset(item: DBHOrderItemListItemDTO, changes: Partial<OrderItemSubsetDTO>) {
return this._orderService.OrderPatchOrderItemSubset({
orderId: item.orderId,

View File

@@ -73,7 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
},
"@shared/icon": "/assets/icons.json"

View File

@@ -72,7 +72,7 @@
},
"checkForUpdates": 900000,
"licence": {
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -74,7 +74,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -73,7 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"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="
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -73,7 +73,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"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="
"scandit": "AVljxT/dG+TAIDDL2jTxm843juR2OtZ6lHLxRpYR7x9uYiSvY2IAHdRx8tjsf9KU7wK0F5cAeb/nLMHF6Vor9ps79wvuBQw6G3N0IW978b78ZUgPOFzxHUAMuD8dbkDZlX8r9y1cOd9sT3UNEwGrQ4siUt2oCkigyTxJAgYs1ijnjQid7q42hHk3tMXywrAYeu5MhF0TV1H77DRDMxPHD/xiR0zhFQRB2Dtnm1+e3LHKCyQjZ/zknEpQB6HS7UbCBoEDj4tohb83E6oqmQFWwt85/Jk9f49gxXakIcNODnQI5H63kSqpEmV9Al1a5L+WGZ6Bq1gwBbnD8FBXlVqxoooiFXW7jzzBa9LNmQiQ5J8yEkIsPeyOHec7F4ERvVONSMYwWyH39ZweSiRsZRM1UsFPhN96bCT5MEwkjPFn4gji6TPGEceJZvV3HwsiCT5Bgjla4bvDsZ2jYvAr9tSij8kIii9dHvsWlrimt+szHJLSz+8uNI6jAvXyr2f3oRxZD/F9osZHVWkgtAc+vVWqkxVJCqmpmoHOXI6TFSqSjYHddhZyU5r2lgQt0+NI6k/bV3iN7Le1RJCP/wuSDCTZjzsU1igB7UnIN2Y70CqCjIeVH9qlxaI1YAC9lwFv1FZvsiueYeJP1n39mmXCSELVtzxgIBEX5yaIHNbbGXd+e8JUgcO8vJ2JA2kJudaU+xfYR5SY//+J1kPsNSbnBnM25LL+LjeRB3QTfqV5sFq8ORWcIMITvkEaRfP3PVcOzb+hO4Ren4ezhJuyADulmvG8a9Kxxk6ymzBbE7a93SGVbxp7OQNEmvTn5+B9wJ7/l1mtvZL2TilrDZBQVMYWrGuUGpA="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -74,7 +74,7 @@
},
"checkForUpdates": 3600000,
"licence": {
"scandit": "AZ7zLw2eLmFWHbYP4RDq8VAEgAxmNGYcPU8YpOc3DryEXj4zMzYQFrQuUm0YewGQYEESXjpRwGX1NYmKY3pXHnAn2DeqIzh2an+FUu9socQlbQnJiHJHoWBAqcqWSua+P12tc95P3s9aaEEYvSjUy7Md88f7N+sk6zZbUmqbMXeXqmZwdkmRoUY/2w0CiiiA4gBFHgu4sMeNQ9dWyfxKTUPf5AnsxnuYpCt5KLxJWSYDv8HHj0mx8DCJTe1m2ony97Lge3JbJ5Dd+Zz6SCwqik7fv53Qole9s/3m66lYFWKAzWRKkHN1zts78CmPxPb+AAHVoqlBM3duvYmnCxxGOmlXabKUNuDR2ExaMu/nlo532jqqy25Cet/FP1UAs96ZGRgzEcHxGPp6kA53lJ15zd+cxz6G93E83AmYJkhddXBQElWEaGtQRfrEzRGmvcksR+V8MMYjGmhkVbQxGGqpnfP4IxbuEFcef6bxxTiulzo75gXoqZTt+7C1qpDcrMM3Yp0Z8RBw3JlV2tLk4FYFZpxY8QrXIcjvRYKExtQ9e5sSbST4Vx95YhEUd6iX0SBPDzcmgR4/Ef6gvJfoWgz68+rqhBGckphdHi2Mf/pYuAlh2jbwtrkErE2xWARBejR/UcU/A3F7k9RkFd5/QZC7qhsE6bZH7uhpkptIbi5XkXagwYy1oJD7yJs4VLOJteYWferRm8h1auxXew5tL8VLHciF+lLj6h8PTUDt2blLgUjHtualqlCwdSTzJyYwk4oswGGDk6E48X7LXpzuhtR8TYTOi2REN0uuTbO/slFBRw+CaYUnD0LjB9p2lb8ndcdV9adzBKmwPxiOtlOELQ=="
"scandit": "Ae7z0WDdRDFqG6oYuAXzesYGJpDLDqt+xWtQHOESiOjaSkB7IEIDJAk534U+cg1zGnk++4hOEK9hXEGR01NLTjh76w1fDL0U63OUjo50EHBXIUvzAVSur3pRY+1ER7SvSEWaT0hDOLYvYrTpdECtt1graN9yMvJzXD38VJKUfssT92p+YENV2Hul3eXIvaVjHqXE/yvupF+MlOMMUMhX0/Km/yTU9H9SjBdsXYihZmYWbt2JotO3Zs1ojXb0+3La10xb01S1q0XdDN6El3XMVilEtdmrP3WoGois8vpQBvOCEvduxCfILFAqjeWXTZvXSut9u+kQKpK8uHW4rVV6iVClpZfPYqKJqTh78AI9gpnfb/zO9GfQEDS3g7wI5WbQKqaNRzhTVowFRri4Ep9R5TRC1bnd00RC4zVaMkbu5kBOA7YoRjgUiYWHKJpi/VokZWyN6u1lsi5mTUbQkm1ZWfX5I/iUVYBgyHZYl+8kfFkwLPXGZNrF4xqubjKiCZRQj0oyNjHOBeHqvAekzhk7scX2g/NN+liRQv4ur413b+uXacSiiYIrLhtGgzrz1KRrtu19uB5odk3LoerDoiYXat7wEg9zUYT/+uBfO2X+uS7L5LW0PMI3hV+joQVpDk5SlA2868Nx0KWtPWmMf7xCuFIhDskfBsXZNRTblqxkk0RzzSqtjx9ihGr+/Tuzm8Pm0s4OQqV7b+++/Zn+Vo4rCqMTwutjOO7dqhah5hbOT1MqY/6VcjCXyDad3BXXr+WYU4GtYTe8Ytjkm/ZTG3fImoDbMchEcqnCw3oxG5e/gkdurE8g/mZlFOtzAN7KkqIsg6qLaC5COjfLPXsi/A=="
},
"@shared/icon": "/assets/icons.json"
}

View File

@@ -1,194 +1,193 @@
<div class="flex flex-col bg-white rounded pt-10">
<div class="rounded-[50%] bg-[#26830C] w-8 h-8 flex items-center justify-center self-center">
<shared-icon class="text-white" icon="done" [size]="24"></shared-icon>
</div>
<div class="summary-wrapper">
<div class="flex flex-col bg-white rounded pt-10 mb-24">
<div class="rounded-[50%] bg-[#26830C] w-8 h-8 flex items-center justify-center self-center">
<shared-icon class="text-white" icon="done" [size]="24"></shared-icon>
</div>
<h1 class="text-center text-h2 my-1 font-bold">Bestellbestätigung</h1>
<p class="text-center text-p1 mb-10">
Nachfolgend erhalten Sie die Übersicht Ihrer Bestellung.
</p>
<h1 class="text-center text-h2 my-1 font-bold">Bestellbestätigung</h1>
<p class="text-center text-p1 mb-10">
Nachfolgend erhalten Sie die Übersicht Ihrer Bestellung.
</p>
<ng-container *ngFor="let displayOrder of displayOrders$ | async; let i = index; let orderLast = last">
<ng-container *ngIf="i === 0">
<div class="flex flex-row items-center bg-white shadow-card min-h-[3.3125rem]">
<div class="text-h3 font-bold px-5 py-[0.875rem]">
{{ displayOrder?.buyer | buyerName }}
<ng-container *ngFor="let displayOrder of displayOrders$ | async; let i = index; let orderLast = last">
<ng-container *ngIf="i === 0">
<div class="flex flex-row items-center bg-white shadow-card min-h-[3.3125rem]">
<div class="text-h3 font-bold px-5 py-[0.875rem]">
{{ displayOrder?.buyer | buyerName }}
</div>
</div>
<hr />
</ng-container>
<div class="flex flex-row items-center bg-[#F5F7FA] min-h-[3.3125rem]">
<div class="flex flex-row items-center justify-center px-5 py-[0.875rem]">
<shared-icon
*ngIf="(displayOrder?.items)[0]?.features?.orderType !== 'Dummy'"
class="mr-2"
[size]="(displayOrder?.items)[0]?.features?.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="(displayOrder?.items)[0]?.features?.orderType"
></shared-icon>
<p class="text-p1 font-bold mr-3">{{ (displayOrder?.items)[0]?.features?.orderType }}</p>
<div
*ngIf="
(displayOrder?.items)[0]?.features?.orderType === 'Abholung' || (displayOrder?.items)[0]?.features?.orderType === 'Rücklage';
else shippingAddress
"
>
{{ displayOrder.targetBranch?.name }}, {{ displayOrder.targetBranch | branchAddress }}
</div>
<ng-template #shippingAddress>
{{ displayOrder.shippingAddress | branchAddress }}
</ng-template>
<div *ngIf="(displayOrder?.items)[0]?.features?.orderType === 'Download'">
| {{ displayOrder.buyer?.communicationDetails?.email }}
</div>
</div>
</div>
<hr />
</ng-container>
<div class="flex flex-row items-center bg-[#F5F7FA] min-h-[3.3125rem]">
<div class="flex flex-row items-center justify-center px-5 py-[0.875rem]">
<shared-icon
*ngIf="(displayOrder?.items)[0]?.features?.orderType !== 'Dummy'"
class="mr-2"
[size]="(displayOrder?.items)[0]?.features?.orderType === 'B2B-Versand' ? 36 : 24"
[icon]="(displayOrder?.items)[0]?.features?.orderType"
></shared-icon>
<p class="text-p1 font-bold mr-3">{{ (displayOrder?.items)[0]?.features?.orderType }}</p>
<div
*ngIf="
(displayOrder?.items)[0]?.features?.orderType === 'Abholung' || (displayOrder?.items)[0]?.features?.orderType === 'Rücklage';
else shippingAddress
"
>
{{ displayOrder.targetBranch?.name }}, {{ displayOrder.targetBranch | branchAddress }}
</div>
<ng-template #shippingAddress>
{{ displayOrder.shippingAddress | branchAddress }}
</ng-template>
<div *ngIf="(displayOrder?.items)[0]?.features?.orderType === 'Download'">
| {{ displayOrder.buyer?.communicationDetails?.email }}
</div>
</div>
</div>
<hr />
<div class="flex flex-col px-5 pt-7 pb-[1.875rem] bg-white" [attr.data-order-type]="(displayOrder?.items)[0]?.features?.orderType">
<div class="flex flex-row justify-between items-center mb-[0.375rem]">
<div class="flex flex-row">
<span class="w-32">Vorgangs-ID</span>
<ng-container *ngIf="customer$ | async; let customer">
<a
*ngIf="customer$ | async; let customer"
class="font-bold text-[#0556B4] no-underline"
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
[queryParams]="{ main_qs: customer?.customerNumber, filter_customertype: '' }"
>{{ displayOrder.orderNumber }}</a
>
</ng-container>
<ui-spinner class="text-[#0556B4] h-4 w-4" [show]="!(customer$ | async)"> </ui-spinner>
</div>
<button
*ifRole="'Store'"
type="button"
class="cta-print bg-transparent text-brand font-bold text-p1 outline-none border-none pr-0"
(click)="openPrintModal(displayOrder.id)"
>
Drucken
</button>
</div>
<div class="flex flex-row justify-between items-center">
<div class="flex flex-row">
<span class="w-32">Bestelldatum</span>
<strong>{{ displayOrder.orderDate | date }}</strong>
<div class="flex flex-col px-5 py-4 bg-white" [attr.data-order-type]="(displayOrder?.items)[0]?.features?.orderType">
<div class="flex flex-row justify-between items-center mb-[0.375rem]">
<div class="flex flex-row">
<span class="w-32">Vorgangs-ID</span>
<ng-container *ngIf="customer$ | async; let customer">
<a
*ngIf="customer$ | async; let customer"
class="font-bold text-[#0556B4] no-underline"
[routerLink]="['/kunde', processId, 'customer', 'search', customer?.id, 'orders', displayOrder.id]"
[queryParams]="{ main_qs: customer?.customerNumber, filter_customertype: '' }"
>{{ displayOrder.orderNumber }}</a
>
</ng-container>
<ui-spinner class="text-[#0556B4] h-4 w-4" [show]="!(customer$ | async)"> </ui-spinner>
</div>
</div>
<div class="flex flex-row justify-between items-center">
<div class="flex flex-row">
<span class="w-32">Bestelldatum</span>
<strong>{{ displayOrder.orderDate | date }}</strong>
</div>
</div>
</div>
<div class="mr-4">
<button
(click)="expanded[i] = !expanded[i]"
type="button"
class="text-[#0556B4] font-bold flex flex-row items-center justify-center"
[class.flex-row-reverse]="!expanded[i]"
>
<shared-icon
class="mr-1"
icon="arrow-back"
[size]="20"
[class.ml-1]="!expanded[i]"
[class.rotate-180]="!expanded[i]"
></shared-icon>
{{ expanded[i] ? 'Weniger' : 'Mehr' }}
</button>
</div>
<button
(click)="expanded[i] = !expanded[i]"
type="button"
class="text-[#0556B4] font-bold flex flex-row items-center justify-center"
[class.flex-row-reverse]="!expanded[i]"
>
<shared-icon
class="mr-1"
icon="arrow-back"
[size]="20"
[class.ml-1]="!expanded[i]"
[class.rotate-180]="!expanded[i]"
></shared-icon>
{{ expanded[i] ? 'Weniger' : 'Mehr' }}
</button>
</div>
</div>
<ng-container *ngFor="let order of displayOrder.items; let last = last">
<ng-container *ngIf="expanded[i]">
<div
class="page-checkout-summary__items-tablet px-5 pb-[1.875rem] bg-white"
[class.page-checkout-summary__items]="isDesktop$ | async"
[class.last]="last"
>
<div class="page-checkout-summary__items-thumbnail flex flex-row">
<a [routerLink]="getProductSearchDetailsPath(order?.product?.ean)" [queryParams]="getProductSearchDetailsQueryParams(order)">
<img class="w-[3.125rem] h-20 mr-2" [src]="order.product?.ean | productImage: 195:315:true" />
</a>
</div>
<ng-container *ngFor="let order of displayOrder.items; let last = last">
<ng-container *ngIf="expanded[i]">
<div
class="page-checkout-summary__items-tablet px-5 pb-[1.875rem] bg-white"
[class.page-checkout-summary__items]="isDesktop$ | async"
[class.last]="last"
>
<div class="page-checkout-summary__items-thumbnail flex flex-row">
<a [routerLink]="getProductSearchDetailsPath(order?.product?.ean)" [queryParams]="getProductSearchDetailsQueryParams(order)">
<img class="w-[3.125rem] h-20 mr-2" [src]="order.product?.ean | productImage: 195:315:true" />
</a>
</div>
<div class="page-checkout-summary__items-title whitespace-nowrap overflow-ellipsis overflow-hidden">
<a
class="font-bold no-underline text-[#0556B4]"
[routerLink]="getProductSearchDetailsPath(order?.product?.ean)"
[queryParams]="getProductSearchDetailsQueryParams(order)"
>{{ order?.product?.name }}</a
>
</div>
<div class="page-checkout-summary__items-title whitespace-nowrap overflow-ellipsis overflow-hidden">
<a
class="font-bold no-underline text-[#0556B4]"
[routerLink]="getProductSearchDetailsPath(order?.product?.ean)"
[queryParams]="getProductSearchDetailsQueryParams(order)"
>{{ order?.product?.name }}</a
>
</div>
<div class="page-checkout-summary__items-ssc" *ngIf="(order?.subsetItems)[0]; let subsetItem">
<span class="mr-2">{{ subsetItem.supplierName }}</span>
<span *ngIf="subsetItem?.ssc && subsetItem?.sscText" class="font-bold border-l border-black pl-2"
>{{ subsetItem.ssc }} - {{ subsetItem.sscText }}</span
>
</div>
<div class="page-checkout-summary__items-ssc" *ngIf="(order?.subsetItems)[0]; let subsetItem">
<span class="mr-2">{{ subsetItem.supplierName }}</span>
<span *ngIf="subsetItem?.ssc && subsetItem?.sscText" class="font-bold border-l border-black pl-2"
>{{ subsetItem.ssc }} - {{ subsetItem.sscText }}</span
>
</div>
<div class="page-checkout-summary__items-quantity font-bold justify-self-end">
<span> {{ order.quantity }}x </span>
</div>
<div class="page-checkout-summary__items-quantity font-bold justify-self-end">
<span> {{ order.quantity }}x </span>
</div>
<div class="page-checkout-summary__items-price font-bold justify-self-end">
<span> {{ order.price?.value?.value | currency: ' ' }} {{ order.price?.value?.currency }} </span>
</div>
<div class="page-checkout-summary__items-price font-bold justify-self-end">
<span> {{ order.price?.value?.value | currency: ' ' }} {{ order.price?.value?.currency }} </span>
</div>
<div class="page-checkout-summary__items-delivery product-details">
<div class="delivery-row" [ngSwitch]="order?.features?.orderType">
<ng-container *ngSwitchCase="'Abholung'">
<span class="order-type"
>Abholung ab {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
</span>
</ng-container>
<ng-container *ngSwitchCase="'Rücklage'">
<span class="order-type"
>{{ order?.features?.orderType }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
</span>
</ng-container>
<ng-container *ngSwitchCase="['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(order?.features?.orderType) > -1">
<ng-container *ngIf="(order?.subsetItems)[0]?.estimatedDelivery; else estimatedShippingDate">
<div class="page-checkout-summary__items-delivery product-details">
<div class="delivery-row" [ngSwitch]="order?.features?.orderType">
<ng-container *ngSwitchCase="'Abholung'">
<span class="order-type"
>Zustellung zwischen
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}</span
>
>Abholung ab {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
</span>
</ng-container>
<ng-template #estimatedShippingDate>
<span class="order-type">Versanddatum {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}</span>
</ng-template>
</ng-container>
<ng-container *ngSwitchDefault>
<span class="order-type">{{ order?.features?.orderType }}</span>
</ng-container>
<ng-container *ngSwitchCase="'Rücklage'">
<span class="order-type"
>{{ order?.features?.orderType }}
<ng-container [ngTemplateOutlet]="abholfrist" [ngTemplateOutletContext]="{ order: order }"> </ng-container>
</span>
</ng-container>
<ng-container *ngSwitchCase="['Versand', 'B2B-Versand', 'DIG-Versand'].indexOf(order?.features?.orderType) > -1">
<ng-container *ngIf="(order?.subsetItems)[0]?.estimatedDelivery; else estimatedShippingDate">
<span class="order-type"
>Zustellung zwischen
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.start | date: 'EEE, dd.MM.')?.replace('.', '') }} und
{{ ((order?.subsetItems)[0]?.estimatedDelivery?.stop | date: 'EEE, dd.MM.')?.replace('.', '') }}</span
>
</ng-container>
<ng-template #estimatedShippingDate>
<span class="order-type">Versanddatum {{ (order?.subsetItems)[0]?.estimatedShippingDate | date }}</span>
</ng-template>
</ng-container>
<ng-container *ngSwitchDefault>
<span class="order-type">{{ order?.features?.orderType }}</span>
</ng-container>
</div>
</div>
</div>
</ng-container>
<hr *ngIf="last" />
</ng-container>
<ng-container *ngIf="orderLast">
<div class="flex flex-row justify-between items-center min-h-[3.3125rem] bg-white px-5 py-4 rounded-b">
<span *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="text-p2 font-bold"
>{{ totalItemCount$ | async }} Artikel | {{ totalReadingPoints }} Lesepunkte</span
>
<div class="flex flex-row items-center justify-center">
<div class="text-p1 font-bold flex flex-row items-center">
<div class="mr-1">Gesamtsumme {{ totalPrice$ | async | currency: ' ' }} {{ totalPriceCurrency$ | async }}</div>
</div>
<div
class="bg-brand text-white font-bold text-p1 outline-none border-none rounded-full px-6 py-3 ml-2"
*ngIf="(takeNowOrders$ | async)?.length === 1 && (isB2BCustomer$ | async)"
>
<button class="cta-goods-out" (click)="navigateToShelfOut()">Zur Warenausgabe</button>
</div>
</div>
</div>
</ng-container>
<hr *ngIf="last" />
</ng-container>
<ng-container *ngIf="orderLast">
<div class="flex flex-row justify-between items-center min-h-[3.3125rem] bg-white px-5 py-4 rounded-b">
<span *ngIf="totalReadingPoints$ | async; let totalReadingPoints" class="text-p2 font-bold"
>{{ totalItemCount$ | async }} Artikel | {{ totalReadingPoints }} Lesepunkte</span
>
<div class="flex flex-row items-center justify-center">
<div class="text-p1 font-bold flex flex-row items-center">
<div class="mr-1">Gesamtsumme {{ totalPrice$ | async | currency: ' ' }} {{ totalPriceCurrency$ | async }}</div>
</div>
<div
class="bg-brand text-white font-bold text-p1 outline-none border-none rounded-full px-6 py-3 ml-2"
*ngIf="(takeNowOrders$ | async)?.length === 1 && (isB2BCustomer$ | async)"
>
<button class="cta-goods-out" (click)="navigateToShelfOut()">Zur Warenausgabe</button>
</div>
</div>
</div>
</ng-container>
</ng-container>
</div>
</div>
<ng-template #abholfrist let-order="order">
@@ -222,3 +221,23 @@
</div>
<div class="fetching" *ngIf="!!(updatingPreferredPickUpDate$ | async)[(order?.subsetItems)[0].id]"></div>
</ng-template>
<div class="absolute left-1/2 bottom-10 transform -translate-x-1/2 inline-grid grid-flow-col gap-4">
<button
*ifRole="'Store'"
type="button"
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14"
(click)="printOrderConfirmation()"
>
Bestellbestätigung drucken
</button>
<button
*ngIf="hasAbholung$ | async"
type="button"
class="px-6 py-2 rounded-full border-2 border-solid border-brand text-brand bg-white font-bold text-lg whitespace-nowrap h-14"
(click)="sendOrderConfirmation()"
>
Bestellbestätigung senden
</button>
</div>

View File

@@ -1,5 +1,9 @@
:host {
@apply box-border bg-transparent rounded overflow-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop flex flex-col justify-between;
@apply box-border bg-transparent relative;
}
.summary-wrapper {
@apply rounded overflow-scroll h-split-screen-tablet desktop-small:h-split-screen-desktop flex flex-col justify-between;
}
.fetching {

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injector, OnDestroy, OnInit, inject } from '@angular/core';
import { DomainCheckoutService } from '@domain/checkout';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { PrintModalComponent, PrintModalData } from '@modal/printer';
@@ -15,6 +15,9 @@ import { BehaviorSubject, combineLatest, NEVER, Subject } from 'rxjs';
import { DateAdapter } from '@ui/common';
import { CheckoutNavigationService, PickUpShelfOutNavigationService, ProductCatalogNavigationService } from '@shared/services';
import { EnvironmentService } from '@core/environment';
import { SendOrderConfirmationModalService } from '@shared/modals/send-order-confirmation-modal';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ToasterService } from '@shared/shell';
@Component({
selector: 'page-checkout-summary',
@@ -23,6 +26,14 @@ import { EnvironmentService } from '@core/environment';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CheckoutSummaryComponent implements OnInit, OnDestroy {
private _injector = inject(Injector);
get sendOrderConfirmationModalService() {
return this._injector.get(SendOrderConfirmationModalService);
}
private _toaster = inject(ToasterService);
private _onDestroy$ = new Subject();
processId = Date.now();
selectedDate = this.dateAdapter.today();
@@ -78,6 +89,10 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
shareReplay()
);
hasAbholung$ = this.displayOrders$.pipe(
map((displayOrders) => displayOrders.filter((order) => order.features?.orderType === 'Abholung')?.length > 0)
);
totalItemCount$ = this.displayOrders$.pipe(
map((displayOrders) =>
displayOrders.reduce(
@@ -222,20 +237,6 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
return { main_qs: item?.product?.ean, filter_format: item?.features?.orderType === 'Download' ? 'eb;dl' : undefined };
}
openPrintModal(id: number) {
this.uiModal.open({
content: PrintModalComponent,
data: {
printerType: 'Label',
print: (printer) => this.domainPrinterService.printOrder({ orderIds: [id], printer }).toPromise(),
} as PrintModalData,
config: {
panelClass: [],
showScrollbarY: false,
},
});
}
async updatePreferredPickUpDate(item: DisplayOrderItemDTO, date: Date) {
const data: Record<string, string> = {};
@@ -310,4 +311,35 @@ export class CheckoutSummaryComponent implements OnInit, OnDestroy {
console.error(e);
}
}
async sendOrderConfirmation() {
const orders = await this.displayOrders$.pipe(first()).toPromise();
await this.sendOrderConfirmationModalService.open(orders);
}
async printOrderConfirmation() {
const orders = await this.displayOrders$.pipe(first()).toPromise();
await this.uiModal
.open({
content: PrintModalComponent,
data: {
printerType: 'Label',
print: async (printer) => {
try {
const result = await this.domainPrinterService.printOrder({ orderIds: orders.map((o) => o.id), printer }).toPromise();
this._toaster.open({ type: 'success', message: 'Bestellbestätigung wurde gedruckt' });
return result;
} catch (error) {
this._toaster.open({ type: 'danger', message: 'Fehler beim Drucken der Bestellbestätigung' });
}
},
} as PrintModalData,
config: {
panelClass: [],
showScrollbarY: false,
},
})
.afterClosed$.toPromise();
}
}

View File

@@ -4,7 +4,7 @@ import { BreadcrumbService } from '@core/breadcrumb';
import { EnvironmentService } from '@core/environment';
import { DomainCustomerOrderService, DomainGoodsService, DomainOmsService } from '@domain/oms';
import { CustomerOrdersNavigationService } from '@shared/services';
import { OrderItemListItemDTO } from '@swagger/oms';
import { DBHOrderItemListItemDTO, OrderItemListItemDTO } from '@swagger/oms';
import { UiMessageModalComponent, UiModalService } from '@ui/modal';
import { combineLatest, Observable } from 'rxjs';
import { map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
@@ -87,10 +87,10 @@ export class CustomerOrderEditComponent implements OnInit {
});
}
async navigateToDetailsPage({ options }: { options?: { processingStatus?: number } }) {
async navigateToDetailsPage(changes?: Partial<DBHOrderItemListItemDTO>) {
const orderId = this._activatedRoute.snapshot.params.orderId;
const compartmentCode = this._activatedRoute.snapshot.params.compartmentCode;
const processingStatus = options?.processingStatus ? options.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
const processingStatus = changes?.processingStatus ? changes.processingStatus : this._activatedRoute.snapshot.params.processingStatus;
await this._navigation
.getCustomerOrdersDetailsPath({

View File

@@ -85,7 +85,9 @@
</app-deviating-address-form-block>
<div class="spacer"></div>
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>

View File

@@ -19,7 +19,7 @@ form {
}
button.cta-submit {
@apply sticky left-1/2 bottom-8 text-center bg-brand text-lg text-white font-bold px-7 py-3 rounded-full transform -translate-x-1/2 transition-all duration-200 ease-in-out;
@apply fixed bottom-16 desktop-small:bottom-8 text-center bg-brand text-lg text-white font-bold px-7 py-3 rounded-full transform transition-all duration-200 ease-in-out;
&:disabled {
@apply bg-active-branch cursor-not-allowed;

View File

@@ -98,7 +98,9 @@
</app-deviating-address-form-block>
<div class="spacer"></div>
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" (click)="save()" [disabled]="form.invalid || form.pending">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>

View File

@@ -143,7 +143,9 @@
<div class="spacer"></div>
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>

View File

@@ -84,9 +84,12 @@
</app-deviating-address-form-block>
<div class="spacer"></div>
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">
Speichern
</ui-spinner>
</button>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">
Speichern
</ui-spinner>
</button>
</div>
</form>

View File

@@ -98,7 +98,9 @@
</app-deviating-address-form-block>
<div class="spacer"></div>
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>

View File

@@ -1,10 +1,3 @@
<a
*ngIf="customerSearchNavigation$ | async; let customerSearchNavigation"
[routerLink]="customerSearchNavigation.path"
[queryParams]="customerSearchNavigation.queryParams"
class="text-[1.375rem] font-bold text-[#596470] text-center py-4"
>Kundensuche</a
>
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
<h1 class="text-[1.625rem] font-bold">Kundendaten erfassen</h1>
<p class="text-lg mt-2">

View File

@@ -1,9 +1,6 @@
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { RouterModule } from '@angular/router';
import { ApplicationService } from '@core/application';
import { CustomerSearchNavigation } from '@shared/services';
import { map } from 'rxjs/operators';
@Component({
selector: 'page-customer-create-side-view',
@@ -14,9 +11,5 @@ import { map } from 'rxjs/operators';
imports: [CommonModule, RouterModule],
})
export class CustomerCreateSideViewComponent {
customerSearchNavigation$ = this._applicationService.activatedProcessId$.pipe(
map((processId) => this.searchNavigation.defaultRoute({ processId }))
);
constructor(public readonly searchNavigation: CustomerSearchNavigation, private _applicationService: ApplicationService) {}
constructor() {}
}

View File

@@ -113,7 +113,9 @@
<div class="spacer"></div>
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
<div class="sticky w-full flex items-center justify-center">
<button class="cta-submit" type="button" [disabled]="form.invalid || form.pending" (click)="save()">
<ui-spinner [show]="busy$ | async">Speichern</ui-spinner>
</button>
</div>
</form>

View File

@@ -49,7 +49,14 @@
<span class="mr-4">
{{ shippingAddress | address }}
</span>
<a *ngIf="canEditAddress$ | async" class="text-brand font-bold" type="button">
<a
*ngIf="editShippingAddressRoute$(shippingAddress.id) | async; let route"
class="text-brand font-bold"
type="button"
[routerLink]="route?.path"
[queryParams]="route?.queryParams"
[queryParamsHandling]="'merge'"
>
Bearbeiten
</a>
</div>

View File

@@ -71,6 +71,16 @@ export class DetailsMainViewDeliveryAddressesComponent extends ComponentStore<De
)
);
editShippingAddressRoute$ = (shippingAddressId: number) =>
combineLatest([this.canEditAddress$, this._store.processId$, this._store.customerId$]).pipe(
map(([canEditAddress, processId, customerId]) => {
if (canEditAddress) {
return this._navigation.editShippingAddressRoute({ processId, customerId, shippingAddressId });
}
return undefined;
})
);
canEditAddress$ = combineLatest([this._store.isKundenkarte$, this._store.isBusinessKonto$, this._store.isMitarbeiter$]).pipe(
map(([isKundenkarte, isBusinessKonto, isMitarbeiter]) => isKundenkarte || isBusinessKonto || isMitarbeiter)
);

View File

@@ -70,13 +70,13 @@
</shared-form-control>
<div class="text-center col-span-2">
<shared-checkbox>Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
<shared-checkbox formControlName="isDefault">Diese Rechnungsadresse als Standard Adresse festlegen</shared-checkbox>
</div>
<div class="mt-6 text-center col-span-2">
<button
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
>
Speichern
</button>

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ChangeDetectorRef, inject } from '@angular/core';
import { CheckboxComponent } from '@shared/components/checkbox';
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { SelectModule } from '@shared/components/select';
@@ -36,6 +36,8 @@ export class EditBillingAddressMainViewComponent extends ComponentStore<EditBill
map(([processId, customerId]) => this._navigation.detailsRoute({ processId, customerId }))
);
private _cdr = inject(ChangeDetectorRef);
formGroup = new FormGroup({
gender: new FormControl<Gender>(0, [Validators.required, Validators.min(1)]),
title: new FormControl<string>(undefined),
@@ -103,6 +105,10 @@ export class EditBillingAddressMainViewComponent extends ComponentStore<EditBill
country: payer.address.country,
info: payer.address.info,
});
this.formGroup.markAllAsTouched();
this.formGroup.updateValueAndValidity();
this._cdr.markForCheck();
}
async save() {

View File

@@ -86,13 +86,13 @@
</shared-form-control>
<div class="text-center col-span-2">
<shared-checkbox>Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
<shared-checkbox formControlName="isDefault">Diese Lieferadresse als Standard Adresse festlegen</shared-checkbox>
</div>
<div class="mt-6 text-center col-span-2">
<button
[disabled]="formGroup.invalid || formGroup.disabled"
type="submit"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white"
class="px-5 py-3 font-bold text-lg rounded-full bg-brand text-white disabled:bg-gray-400 disabled:cursor-not-allowed"
tabindex="15"
>
Speichern

View File

@@ -1,18 +1,23 @@
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy } from '@angular/core';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, inject, ChangeDetectorRef } from '@angular/core';
import { CheckboxComponent } from '@shared/components/checkbox';
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { SelectModule } from '@shared/components/select';
import { FormControlComponent } from '@shared/components/form-control';
import { CrmCustomerService } from '@domain/crm';
import { AddressDTO, Gender, ShippingAddressDTO } from '@swagger/crm';
import { map, takeUntil } from 'rxjs/operators';
import { map, switchMap, takeUntil } from 'rxjs/operators';
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { AddressSelectionModalService } from '@shared/modals/address-selection-modal';
import { CustomerSearchStore } from '../store';
import { CustomerSearchNavigation } from '@shared/services';
import { Subject, combineLatest } from 'rxjs';
import { IconComponent } from '@shared/components/icon';
import { RouterLink } from '@angular/router';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { ComponentStore } from '@ngrx/component-store';
export interface EditShippingAddressMainViewState {
shippingAddress?: ShippingAddressDTO;
}
@Component({
selector: 'page-edit-shipping-address-main-view',
@@ -33,9 +38,13 @@ import { RouterLink } from '@angular/router';
CheckboxComponent,
],
})
export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
export class EditShippingAddressMainViewComponent extends ComponentStore<EditShippingAddressMainViewState> implements OnInit, OnDestroy {
private _activatedRoute = inject(ActivatedRoute);
private _onDestroy = new Subject<void>();
private _cdr = inject(ChangeDetectorRef);
detailsRoute$ = combineLatest([this._store.processId$, this._store.customerId$]).pipe(
map(([processId, customerId]) => this._navigation.detailsRoute({ processId, customerId }))
);
@@ -61,14 +70,30 @@ export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
isBusinessKonto$ = this._store.isBusinessKonto$;
shippingAddressId$ = this._activatedRoute.params.pipe(
map((params) => params.shippingAddressId),
switchMap((shippingAddressId) => this._customerService.getShippingAddress(shippingAddressId).pipe(map((res) => res.result)))
);
get shippingAddressId() {
return this.get((s) => s.shippingAddress?.id);
}
constructor(
private _customerService: CrmCustomerService,
private _addressSelection: AddressSelectionModalService,
private _store: CustomerSearchStore,
private _navigation: CustomerSearchNavigation
) {}
) {
super({ shippingAddress: undefined });
}
ngOnInit() {
this.shippingAddressId$.pipe(takeUntil(this._onDestroy)).subscribe((shippingAddress) => {
this.patchState({ shippingAddress });
this.patchFormGroup(shippingAddress);
});
this._store.customer$.pipe(takeUntil(this._onDestroy)).subscribe(() => {
if (this._store.isBusinessKonto) {
this.formGroup.controls.organisation.setValidators([Validators.required]);
@@ -78,6 +103,26 @@ export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
});
}
patchFormGroup(shipping: ShippingAddressDTO) {
this.formGroup.patchValue({
gender: shipping.gender ?? 0,
title: shipping.title,
lastName: shipping.lastName,
firstName: shipping.firstName,
organisation: shipping.organisation?.name,
street: shipping.address.street,
streetNumber: shipping.address.streetNumber,
zipCode: shipping.address.zipCode,
city: shipping.address.city,
country: shipping.address.country,
info: shipping.address.info,
});
this.formGroup.markAllAsTouched();
this.formGroup.updateValueAndValidity();
this._cdr.markForCheck();
}
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
@@ -127,7 +172,12 @@ export class EditShippingAddressMainViewComponent implements OnInit, OnDestroy {
address: addressValidationResult,
};
const result = await this._customerService.createShippingAddress(this._store.customerId, shippingAddress, formData.isDefault);
const result = await this._customerService.updateShippingAddress(
this._store.customerId,
this.shippingAddressId,
shippingAddress,
formData.isDefault
);
this._navigation.navigateToDetails({ processId: this._store.processId, customerId: this._store.customerId });
} catch (error) {

View File

@@ -14,7 +14,13 @@
</div>
</div>
<div class="px-3 bg-surface text-surface-content">
<shared-filter [filter]="filter" [loading]="fetching$ | async" (search)="search(filter)" [hint]="message$ | async"></shared-filter>
<shared-filter
[filter]="filter"
[loading]="fetching$ | async"
(search)="search(filter)"
[hint]="message$ | async"
[scanner]="true"
></shared-filter>
</div>
<div class="grid grid-flow-col gap-6 items-center justify-center mt-6">

View File

@@ -1,10 +1,3 @@
<a
*ngIf="customerCreateNavigation$ | async; let customerCreateNavigation"
[routerLink]="customerCreateNavigation.path"
[queryParams]="customerCreateNavigation.queryParams"
class="text-[1.375rem] font-bold text-[#596470] text-center py-4"
>Kundendaten erfassen</a
>
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
<p class="text-lg mt-2 mb-6">

View File

@@ -1,10 +1,8 @@
import { AsyncPipe, CommonModule, NgIf } from '@angular/common';
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { RouterModule } from '@angular/router';
import { CustomerCreateNavigation } from '@shared/services';
import { Filter, FilterModule } from '@shared/components/filter';
import { CustomerSearchStore } from '../store';
import { map } from 'rxjs/operators';
@Component({
selector: 'page-customer-main-side-view',
@@ -15,15 +13,13 @@ import { map } from 'rxjs/operators';
imports: [CommonModule, RouterModule, FilterModule, AsyncPipe, NgIf],
})
export class MainSideViewComponent {
customerCreateNavigation$ = this._store.processId$.pipe(map((processId) => this._navigation.defaultRoute({ processId })));
message$ = this._store.message$;
filter$ = this._store.filter$;
fetching$ = this._store.fetchingCustomerList$;
constructor(private _navigation: CustomerCreateNavigation, private _store: CustomerSearchStore) {}
constructor(private _store: CustomerSearchStore) {}
search(filter: Filter) {
this._store.setFilter(filter);

View File

@@ -1,11 +1,4 @@
<div class="desktop-large:hidden">
<a
*ngIf="customerCreateNavigation$ | async; let customerCreateNavigation"
[routerLink]="customerCreateNavigation.path"
[queryParams]="customerCreateNavigation.queryParams"
class="block text-[1.375rem] font-bold text-[#596470] text-center py-4"
>Kundendaten erfassen</a
>
<div class="text-center pt-10 px-8 rounded-card side-view-shadow grow">
<h1 class="text-[1.625rem] font-bold">Kundensuche</h1>
<p class="text-lg mt-2 mb-6">
@@ -19,6 +12,7 @@
(search)="search(filter)"
[loading]="fetching$ | async"
[hint]="message$ | async"
[scanner]="true"
></shared-filter-input-group-main>
<a
*ngIf="filterRoute$ | async; let filterRoute"

View File

@@ -6,7 +6,7 @@ import { AsyncPipe, NgIf } from '@angular/common';
import { Router, RouterLink } from '@angular/router';
import { IconComponent } from '@shared/components/icon';
import { combineLatest } from 'rxjs';
import { CustomerCreateNavigation, CustomerSearchNavigation } from '@shared/services';
import { CustomerSearchNavigation } from '@shared/services';
import { CustomerFilterMainViewModule } from '../filter-main-view/filter-main-view.module';
import { isEmpty } from 'lodash';
@@ -20,8 +20,6 @@ import { isEmpty } from 'lodash';
imports: [AsyncPipe, RouterLink, FilterModule, NgIf, IconComponent, CustomerFilterMainViewModule],
})
export class CustomerMainViewComponent {
customerCreateNavigation$ = this._store.processId$.pipe(map((processId) => this._createNavigation.defaultRoute({ processId })));
filterRoute$ = combineLatest([this._store.processId$, this._store.filter$]).pipe(
map(([processId, filter]) => {
const route = this._searchNavigation.filterRoute({ processId, comingFrom: this._router.url?.split('?')[0] });
@@ -45,12 +43,7 @@ export class CustomerMainViewComponent {
message$ = this._store.message$;
constructor(
private _createNavigation: CustomerCreateNavigation,
private _searchNavigation: CustomerSearchNavigation,
private _store: CustomerSearchStore,
private _router: Router
) {}
constructor(private _searchNavigation: CustomerSearchNavigation, private _store: CustomerSearchStore, private _router: Router) {}
search(filter: Filter) {
this._store.setFilter(filter);

View File

@@ -7,6 +7,7 @@
(search)="search(filter)"
[hint]="message$ | async"
[loading]="fetching$ | async"
[scanner]="true"
></shared-filter-input-group-main>
<a
class="btn btn-light h-14 font-bold"

View File

@@ -7,6 +7,7 @@
(search)="search(filter)"
[hint]="message$ | async"
[loading]="fetching$ | async"
[scanner]="true"
></shared-filter-input-group-main>
<a
class="btn btn-light h-14 font-bold"

View File

@@ -3,10 +3,8 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router } from '@angular/router';
import { PickupShelfDetailsStore, PickupShelfStore } from './store';
import { ActionHandlerService } from './services/action-handler.service';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString, OrderItemProcessingStatusValue } from '@swagger/oms';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@swagger/oms';
import { OrderItemsContext } from '@domain/oms';
import { mergeMap, take } from 'rxjs/operators';
import { of } from 'rxjs';
export abstract class PickupShelfDetailsBaseComponent {
protected destroyRef = inject(DestroyRef);
@@ -36,7 +34,13 @@ export abstract class PickupShelfDetailsBaseComponent {
* Führt die Actions aus
* @param action Actions
*/
async execAction(action: KeyValueDTOOfStringAndString): Promise<OrderItemsContext> {
async execAction({
action,
latestCompartmentCode,
}: {
action: KeyValueDTOOfStringAndString;
latestCompartmentCode?: string;
}): Promise<OrderItemsContext> {
if (action.command.includes('FETCHED_PARTIAL')) {
this.store.setFetchPartial(true);
return;
@@ -45,7 +49,7 @@ export abstract class PickupShelfDetailsBaseComponent {
const ctx = await this.actionHandlerService.handle({
action,
items: this.store.selectedOrderItems,
compartmentCode: this.store.latestCompartmentCodeForOrder,
compartmentCode: latestCompartmentCode ?? undefined, // Ticket #4391 - if undefined, assign new compartmentCode to item (bei eingetroffen und drucken)
compartmentInfo: this.store.selectedCompartmentInfo || this.store.compartmentInfo,
order: this.store.order,
itemQuantity: this.store.selectedOrderItemQuantity,
@@ -73,8 +77,6 @@ export abstract class PickupShelfDetailsBaseComponent {
if (!updatedItem) return;
console.log('updatedItem', updatedItem);
this.listStore.patchOrderItem({
orderItemSubsetId: item.orderItemSubsetId,
changes: {

View File

@@ -1,7 +1,6 @@
<div class="mb-4">
<page-pickup-shelf-details-header
[order]="order$ | async"
(handleAction)="handleAction($event)"
(handleAction)="handleAction({ action: $event })"
(updateDate)="updateDate($event)"
(editClick)="navigateToEditPage($event)"
></page-pickup-shelf-details-header>
@@ -25,18 +24,20 @@
</div>
<div class="page-pickup-shelf-in-details__action-wrapper">
<button
[disabled]="addToPreviousCompartmentActionDisabled$ | async"
*ngIf="addToPreviousCompartmentAction$ | async; let action"
class="cta-action shadow-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction(action)"
>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command"
>{{ latestCompartmentCode$ | async | addToPreviousCompartmentCodeLabelPipe }} zubuchen</ui-spinner
<ng-container *ngIf="latestCompartmentCode$ | async; let latestCompartmentCode">
<button
[disabled]="addToPreviousCompartmentActionDisabled$ | async"
*ngIf="addToPreviousCompartmentAction$ | async; let action"
class="cta-action shadow-action"
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
(click)="handleAction({action, latestCompartmentCode })"
>
</button>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command"
>{{ latestCompartmentCode | addToPreviousCompartmentCodeLabelPipe }} zubuchen</ui-spinner
>
</button>
</ng-container>
<button
[disabled]="actionsDisabled$ | async"
@@ -44,7 +45,7 @@
[class.cta-action-primary]="action.selected"
[class.cta-action-secondary]="!action.selected"
*ngFor="let action of mainActions$ | async"
(click)="handleAction(action)"
(click)="handleAction({action})"
>
<ui-spinner [show]="(changeActionLoader$ | async) === action.command">{{ action.label }}</ui-spinner>
</button>

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, ContentChild, inject, OnInit, AfterViewInit } from '@angular/core';
import { Component, ChangeDetectionStrategy, inject, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { PickupShelfDetailsBaseComponent } from '../../pickup-shelf-details-base.component';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { PickUpShelfDetailsHeaderComponent } from '../../shared/pickup-shelf-details-header/pickup-shelf-details-header.component';
@@ -37,7 +37,7 @@ import { ActivatedRoute } from '@angular/router';
],
})
export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseComponent implements OnInit, AfterViewInit {
@ContentChild(PickUpShelfDetailsTagsComponent, { static: false })
@ViewChild(PickUpShelfDetailsTagsComponent, { static: false })
pickUpShelfDetailsTags: PickUpShelfDetailsTagsComponent;
private _pickupShelfInNavigationService = inject(PickupShelfInNavigationService);
@@ -106,11 +106,11 @@ export class PickupShelfInDetailsComponent extends PickupShelfDetailsBaseCompone
});
}
async handleAction(action: KeyValueDTOOfStringAndString) {
async handleAction({ action, latestCompartmentCode }: { action: KeyValueDTOOfStringAndString; latestCompartmentCode?: string }) {
try {
this.changeActionLoader$.next(action.command);
this.store.setDisableHeaderStatusDropdown(true);
const context = await this.execAction(action);
const context = await this.execAction({ action, latestCompartmentCode });
if (!!context) {
if (action.command.includes('ARRIVED') || action.command.includes('PRINT_PRICEDIFFQRCODELABEL')) {
await this.router.navigate(this._pickupShelfInNavigationService.defaultRoute().path);

View File

@@ -4,6 +4,7 @@ import { SharedGoodsInOutOrderEditModule } from '@shared/components/goods-in-out
import { first } from 'rxjs/operators';
import { AsyncPipe, NgIf } from '@angular/common';
import { PickupShelfInNavigationService } from '@shared/services';
import { DBHOrderItemListItemDTO } from '@swagger/oms';
@Component({
selector: 'page-pickup-shelf-in-edit',
@@ -22,15 +23,12 @@ export class PickupShelfInEditComponent extends PickupShelfDetailsBaseComponent
this.listStore;
}
async navigateToShelfInDetailsPage({ options }: { options?: { processingStatus?: number } }) {
async navigateToShelfInDetailsPage(changes?: Partial<DBHOrderItemListItemDTO>) {
const orderId = (await this.store.orderItems$.pipe(first()).toPromise())?.find((_) => true)?.orderId;
const compartmentCode = this.activatedRoute?.snapshot?.params?.compartmentCode;
const orderNumber = this.activatedRoute?.snapshot?.params?.orderNumber;
const processingStatus = options?.processingStatus
? options.processingStatus
: this.activatedRoute.snapshot.params.orderItemProcessingStatus;
const compartmentInfo = this.activatedRoute.snapshot.params.compartmentInfo;
const compartmentCode = changes?.compartmentCode ?? this.activatedRoute?.snapshot?.params?.compartmentCode;
const processingStatus = changes?.processingStatus ?? this.activatedRoute.snapshot.params.orderItemProcessingStatus;
const compartmentInfo = changes?.compartmentInfo ?? this.activatedRoute.snapshot.params.compartmentInfo;
await this.router.navigate(
this.shelfInNavigation.detailRoute({

View File

@@ -51,7 +51,10 @@
[showScrollArrow]="false"
[showSpacer]="(primaryOutletActive$ | async) || (isTablet$ | async) || (isDesktopSmall$ | async)"
>
<div class="page-pickup-shelf-in-list__items-list w-full" *ngFor="let bueryNumberGroup of list$ | async | groupBy: byBuyerNumberFn">
<div
class="page-pickup-shelf-in-list__items-list w-full"
*ngFor="let bueryNumberGroup of list$ | async | groupBy: byBuyerNumberFn; trackBy: trackByGroupFn"
>
<ng-container *ngIf="bueryNumberGroup.items[0]; let firstItem">
<div
class="page-pickup-shelf-in-list__item-header-group w-full grid grid-flow-col gap-x-4 items-center justify-between bg-white text-xl rounded-t p-4 font-bold mb-px-2"
@@ -65,9 +68,11 @@
</div>
</ng-container>
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn">
<ng-container *ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn">
<ng-container *ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn">
<ng-container *ngFor="let orderNumberGroup of bueryNumberGroup.items | groupBy: byOrderNumberFn; trackBy: trackByGroupFn">
<ng-container *ngFor="let processingStatusGroup of orderNumberGroup.items | groupBy: byProcessingStatusFn; trackBy: trackByGroupFn">
<ng-container
*ngFor="let compartmentCodeGroup of processingStatusGroup.items | groupBy: byCompartmentCodeFn; trackBy: trackByGroupFn"
>
<page-pickup-shelf-list-item
*ngFor="let item of compartmentCodeGroup.items; let firstItem = first; trackBy: trackByFn"
class="page-pickup-shelf-in-list__result-item mb-[0.125rem]"
@@ -79,6 +84,7 @@
</ng-container>
</ng-container>
</div>
<page-pickup-shelf-list-item-loader *ngIf="fetching$ | async"></page-pickup-shelf-list-item-loader>
</ui-scroll-container>
</div>

View File

@@ -16,7 +16,7 @@ import { Filter, FilterModule } from '@shared/components/filter';
import { IconModule } from '@shared/components/icon';
import { PickUpShelfListItemComponent } from '../../shared/pickup-shelf-list-item/pickup-shelf-list-item.component';
import { UiScrollContainerComponent, UiScrollContainerModule } from '@ui/scroll-container';
import { GroupByPipe } from '@ui/common';
import { Group, GroupByPipe } from '@ui/common';
import { UiSpinnerModule } from '@ui/spinner';
import { PickupShelfInNavigationService } from '@shared/services';
import { debounceTime, map } from 'rxjs/operators';
@@ -27,6 +27,7 @@ import { isEqual } from 'lodash';
import { EnvironmentService } from '@core/environment';
import { CacheService } from '@core/cache';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { PickupShelfListItemLoaderComponent } from '../../shared/pickup-shelf-list-item/pickup-shelf-list-item-loader.component';
@Component({
selector: 'page-pickup-shelf-in-list',
@@ -46,6 +47,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
UiScrollContainerModule,
GroupByPipe,
UiSpinnerModule,
PickupShelfListItemLoaderComponent,
],
})
export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
@@ -106,6 +108,8 @@ export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
trackByFn: TrackByFunction<DBHOrderItemListItemDTO> = (index, item) => `${item.orderId}${item.orderItemId}${item.orderItemSubsetId}`;
trackByGroupFn: TrackByFunction<Group<string, DBHOrderItemListItemDTO>> = (index, group) => group.group;
private readonly SCROLL_POSITION_TOKEN = 'SHELF_IN_LIST_SCROLL_POSITION';
constructor(

View File

@@ -14,6 +14,8 @@ import { DBHOrderItemListItemDTO } from '@swagger/oms';
import { Observable, of } from 'rxjs';
import { take } from 'rxjs/operators';
import { ApplicationService } from '@core/application';
import { FilterAutocompleteProvider } from '@shared/components/filter';
import { PickUpShelfInAutocompleteProvider } from './providers/pickup-shelf-in-autocomplete.provider';
@Component({
selector: 'page-pickup-shelf-in',
@@ -24,6 +26,11 @@ import { ApplicationService } from '@core/application';
standalone: true,
imports: [BreadcrumbModule, SharedSplitscreenComponent],
providers: [
{
provide: FilterAutocompleteProvider,
useClass: PickUpShelfInAutocompleteProvider,
multi: true,
},
provideComponentStore(PickupShelfStore),
provideComponentStore(PickupShelfDetailsStore),
{ provide: PickupShelfIOService, useClass: PickupShelfInService },

View File

@@ -0,0 +1,38 @@
import { Injectable, inject } from '@angular/core';
import { PickupShelfIOService } from '@domain/pickup-shelf';
import { FilterAutocomplete, FilterAutocompleteProvider, FilterInput } from '@shared/components/filter';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@Injectable()
export class PickUpShelfInAutocompleteProvider extends FilterAutocompleteProvider {
private _pickupShelfIOService = inject(PickupShelfIOService);
for = 'pickup-shelf-in';
constructor() {
super();
}
complete(input: FilterInput): Observable<FilterAutocomplete[]> {
const token = input?.parent?.parent?.getQueryToken();
const filter = token?.filter;
const type = Object.keys(token?.input).join(';');
if (input.value.length >= 3) {
return this._pickupShelfIOService
.complete({
filter,
input: input.value,
take: 5,
type,
})
.pipe(
catchError(() => of({ result: [] })),
map((res) => res.result)
);
} else {
return of([]);
}
}
}

View File

@@ -1,7 +1,6 @@
<div class="mb-4">
<page-pickup-shelf-details-header
[processId]="processId"
[order]="order$ | async"
(handleAction)="handleAction($event)"
(updateDate)="updateDate($event)"
(editClick)="navigateToEditPage($event)"

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, inject, ContentChild } from '@angular/core';
import { Component, ChangeDetectionStrategy, inject, ViewChild } from '@angular/core';
import { PickupShelfDetailsBaseComponent } from '../../pickup-shelf-details-base.component';
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { PickUpShelfDetailsHeaderComponent } from '../../shared/pickup-shelf-details-header/pickup-shelf-details-header.component';
@@ -34,7 +34,7 @@ import { FormsModule } from '@angular/forms';
providers: [],
})
export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseComponent {
@ContentChild(PickUpShelfDetailsTagsComponent, { static: false })
@ViewChild(PickUpShelfDetailsTagsComponent, { static: false })
pickUpShelfDetailsTags: PickUpShelfDetailsTagsComponent;
private _pickupShelfOutNavigationService = inject(PickUpShelfOutNavigationService);
@@ -74,7 +74,7 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
try {
this.changeActionLoader$.next(action.command);
this.store.setDisableHeaderStatusDropdown(true);
const context = await this.execAction(action);
const context = await this.execAction({ action });
if (!!context) {
if (action.command.includes('ARRIVED') || action.command.includes('PRINT_PRICEDIFFQRCODELABEL')) {
@@ -113,17 +113,17 @@ export class PickupShelfOutDetailsComponent extends PickupShelfDetailsBaseCompon
updateDate({ date, type }: { date: Date; type?: 'delivery' | 'pickup' | 'preferred' }) {
switch (type) {
case 'delivery':
case 'delivery': // vsl. Lieferdatum
this.store.orderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { estimatedShippingDate: date.toISOString() } })
);
break;
case 'pickup':
case 'pickup': // Abholfrist
this.store.orderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { compartmentStop: date.toISOString() } })
);
break;
case 'preferred':
case 'preferred': // Zurücklegen bis
this.store.orderItems.forEach((item) =>
this.store.patchOrderItemSubset({ item, changes: { preferredPickUpDate: date.toISOString() } })
);

View File

@@ -4,6 +4,7 @@ import { SharedGoodsInOutOrderEditModule } from '@shared/components/goods-in-out
import { first } from 'rxjs/operators';
import { PickUpShelfOutNavigationService } from '@shared/services';
import { AsyncPipe, NgIf } from '@angular/common';
import { DBHOrderItemListItemDTO } from '@swagger/oms';
@Component({
selector: 'page-pickup-shelf-out-edit',
@@ -23,14 +24,12 @@ export class PickupShelfOutEditComponent extends PickupShelfDetailsBaseComponent
this.listStore;
}
async navigateToShelfOutDetailsPage({ options }: { options?: { processingStatus?: number } }) {
async navigateToShelfOutDetailsPage(changes: Partial<DBHOrderItemListItemDTO>) {
const orderId = (await this.store.orderItems$.pipe(first()).toPromise())?.find((_) => true)?.orderId;
const compartmentCode = this.activatedRoute?.snapshot?.params?.compartmentCode;
const orderNumber = this.activatedRoute?.snapshot?.params?.orderNumber;
const processingStatus = options?.processingStatus
? options.processingStatus
: this.activatedRoute.snapshot.params.orderItemProcessingStatus;
const compartmentInfo = this.activatedRoute.snapshot.params.compartmentInfo;
const compartmentCode = changes?.compartmentCode ?? this.activatedRoute?.snapshot?.params?.compartmentCode;
const processingStatus = changes?.processingStatus ?? this.activatedRoute.snapshot.params.orderItemProcessingStatus;
const compartmentInfo = changes?.compartmentInfo ?? this.activatedRoute.snapshot.params.compartmentInfo;
await this.router.navigate(
this.shelfOutNavigation.detailRoute({

View File

@@ -13,6 +13,8 @@ import { take } from 'rxjs/operators';
import { provideActionHandlers } from '@core/command';
import { ActionHandlerServices } from '@domain/oms';
import { ActionHandlerService } from '../services/action-handler.service';
import { FilterAutocompleteProvider } from '@shared/components/filter';
import { PickUpShelfOutAutocompleteProvider } from './providers/pickup-shelf-out-autocomplete.provider';
@Component({
selector: 'page-pickup-shelf-out',
@@ -23,6 +25,11 @@ import { ActionHandlerService } from '../services/action-handler.service';
standalone: true,
imports: [BreadcrumbModule, SharedSplitscreenComponent, AsyncPipe],
providers: [
{
provide: FilterAutocompleteProvider,
useClass: PickUpShelfOutAutocompleteProvider,
multi: true,
},
provideComponentStore(PickupShelfStore),
provideComponentStore(PickupShelfDetailsStore),
{ provide: PickupShelfIOService, useClass: PickupShelfOutService },

View File

@@ -0,0 +1,38 @@
import { Injectable, inject } from '@angular/core';
import { PickupShelfIOService } from '@domain/pickup-shelf';
import { FilterAutocomplete, FilterAutocompleteProvider, FilterInput } from '@shared/components/filter';
import { Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@Injectable()
export class PickUpShelfOutAutocompleteProvider extends FilterAutocompleteProvider {
private _pickupShelfIOService = inject(PickupShelfIOService);
for = 'pickup-shelf-out';
constructor() {
super();
}
complete(input: FilterInput): Observable<FilterAutocomplete[]> {
const token = input?.parent?.parent?.getQueryToken();
const filter = token?.filter;
const type = Object.keys(token?.input).join(';');
if (input.value.length >= 3) {
return this._pickupShelfIOService
.complete({
filter,
input: input.value,
take: 5,
type,
})
.pipe(
catchError(() => of({ result: [] })),
map((res) => res.result)
);
} else {
return of([]);
}
}
}

View File

@@ -140,7 +140,7 @@
data-detail-id="Benachrichtigung"
>
<div class="min-w-[9rem]">Benachrichtigung</div>
<div class="flex flex-row font-bold">{{ (notificationsChannel | notificationsChannel) || '-' }}</div>
<div class="flex flex-row font-bold">{{ (notificationsChannel$ | async | notificationsChannel) || '-' }}</div>
</div>
</div>
</div>
@@ -283,7 +283,7 @@
[disabled]="(!isKulturpass && !!orderItem?.features?.paid) || (changeDateDisabled$ | async)"
class="cta-pickup-preferred"
>
<strong class="border-r border-[#AEB7C1] pr-4" *ngIf="preferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
<strong class="border-r border-[#AEB7C1] pr-4" *ngIf="findLatestPreferredPickUpDate$ | async; let pickUpDate; else: selectTemplate">
{{ pickUpDate | date: 'dd.MM.yy' }}
</strong>
<ng-template #selectTemplate>
@@ -298,7 +298,7 @@
[xOffset]="8"
[min]="minDateDatepicker"
[disabledDaysOfWeek]="[0]"
[selected]="(preferredPickUpDate$ | async) || today"
[selected]="(findLatestPreferredPickUpDate$ | async) || today"
(save)="updatePreferredPickUpDate($event)"
>
</ui-datepicker>

View File

@@ -1,9 +1,9 @@
import { AsyncPipe, DatePipe, NgFor, NgIf, NgSwitch, NgSwitchCase, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, SimpleChanges, inject } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString, NotificationChannel, OrderDTO } from '@swagger/oms';
import { PickupShelfDetailsStore } from '../../store';
import { map, shareReplay } from 'rxjs/operators';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { map, shareReplay, withLatestFrom } from 'rxjs/operators';
import { BehaviorSubject, Observable, combineLatest } from 'rxjs';
import { DateAdapter, UiCommonModule } from '@ui/common';
import { IconModule } from '@shared/components/icon';
import { UiDropdownModule } from '@ui/dropdown';
@@ -50,8 +50,37 @@ export class PickUpShelfDetailsHeaderComponent {
@Output()
updateDate = new EventEmitter<{ date: Date; type?: 'delivery' | 'pickup' | 'preferred' }>();
@Input()
order: OrderDTO;
get order$(): Observable<OrderDTO> {
return this._store.order$;
}
get order(): OrderDTO {
return this._store.order;
}
findLatestPreferredPickUpDate$: Observable<Date> = this.order$.pipe(
withLatestFrom(this._store.selectedOrderItemIds$),
map(([order, selectedOrderItemIds]) => {
let latestDate;
const subsetItems = order?.items
?.reduce((acc, item) => {
return [...acc, ...item.data.subsetItems];
}, [])
?.filter((a) => !!a.data.preferredPickUpDate && selectedOrderItemIds.find((id) => id === a.data.id));
if (subsetItems?.length > 0) {
latestDate = new Date(
subsetItems?.reduce((a, b) => {
return new Date(a.data.preferredPickUpDate) > new Date(b.data.preferredPickUpDate) ? a : b;
})?.data?.preferredPickUpDate
);
}
return latestDate;
})
);
notificationsChannel$: Observable<NotificationChannel> = this.order$.pipe(map((order) => order?.notificationChannels ?? 0));
@Input()
processId?: number;
@@ -69,10 +98,6 @@ export class PickUpShelfDetailsHeaderComponent {
orderItem$ = this._store.orderItems$.pipe(map((orderItems) => orderItems?.find((_) => true)));
preferredPickUpDate$ = new BehaviorSubject<Date>(undefined);
notificationsChannel: NotificationChannel = 0;
changeDateLoader$ = new BehaviorSubject<boolean>(false);
changePreferredDateLoader$ = new BehaviorSubject<boolean>(false);
changeStatusLoader$ = new BehaviorSubject<boolean>(false);
@@ -124,19 +149,6 @@ export class PickUpShelfDetailsHeaderComponent {
constructor(private dateAdapter: DateAdapter, private cdr: ChangeDetectorRef) {}
ngOnChanges(changes: SimpleChanges): void {
if (changes.order) {
this.findLatestPreferredPickUpDate();
this.computeNotificationChannel();
}
}
computeNotificationChannel() {
const order = this.order;
this.notificationsChannel = order?.notificationChannels ?? 0;
this.cdr.markForCheck();
}
async handleActionClick(action?: KeyValueDTOOfStringAndString) {
this.changeStatusLoader$.next(true);
this.handleAction.emit(action);
@@ -159,21 +171,4 @@ export class PickUpShelfDetailsHeaderComponent {
updatePreferredPickUpDate(date: Date) {
this.updateDate.emit({ date, type: 'preferred' });
}
findLatestPreferredPickUpDate() {
let latestDate;
const subsetItems = this.order?.items
?.reduce((acc, item) => {
return [...acc, ...item.data.subsetItems];
}, [])
?.filter((a) => !!a.data.preferredPickUpDate);
if (subsetItems?.length > 0) {
latestDate = new Date(
subsetItems?.reduce((a, b) => {
return new Date(a.data.preferredPickUpDate) > new Date(b.data.preferredPickUpDate) ? a : b;
})?.data?.preferredPickUpDate
);
}
this.preferredPickUpDate$.next(latestDate);
}
}

View File

@@ -46,13 +46,13 @@ export class PickUpShelfHistoryComponent {
customerName$ = this.historyItem$.pipe(
map((historyItem) =>
[historyItem?.organisation ?? historyItem.organisation, historyItem.lastName, historyItem.firstName].filter((i) => !!i).join(', ')
[historyItem?.organisation ?? historyItem?.organisation, historyItem?.lastName, historyItem?.firstName].filter((i) => !!i).join(', ')
)
);
customerNumber$ = this.historyItem$.pipe(map((historyItem) => historyItem.buyerNumber));
customerNumber$ = this.historyItem$.pipe(map((historyItem) => historyItem?.buyerNumber));
history$ = this.historyItem$.pipe(switchMap((historyItem) => this._omsService.getHistory(historyItem.orderItemSubsetId).pipe(take(1))));
history$ = this.historyItem$.pipe(switchMap((historyItem) => this._omsService.getHistory(historyItem?.orderItemSubsetId).pipe(take(1))));
constructor(
private _activatedRoute: ActivatedRoute,

View File

@@ -2,7 +2,6 @@
class="page-pickup-shelf-list-item__item-card hover p-4 bg-white border border-solid border-transparent rounded"
[routerLink]="itemDetailsLink"
[routerLinkActive]="!isTablet && !primaryOutletActive ? 'active' : ''"
[queryParams]="queryParams"
queryParamsHandling="preserve"
(click)="isDesktopLarge ? scrollIntoView() : ''"
>
@@ -63,13 +62,10 @@
<div class="page-pickup-shelf-list-item__item-order-number-processing-status-paid flex flex-col">
<div
*ngIf="showCompartmentOrOrderNumber"
*ngIf="showCompartmentCode"
class="page-pickup-shelf-list-item__item-order-number text-h3 mb-[0.375rem] self-end font-bold break-all text-right"
>
<ng-container *ngIf="item?.compartmentCode; else orderNumber"
>{{ item?.compartmentCode }}{{ item?.compartmentInfo && '_' + item?.compartmentInfo }}</ng-container
>
<ng-template #orderNumber>{{ item?.orderNumber }}</ng-template>
{{ item?.compartmentCode }}{{ item?.compartmentInfo && '_' + item?.compartmentInfo }}
</div>
<div class="page-pickup-shelf-list-item__item-processing-paid-status flex flex-col font-bold self-end text-p2 mb-[0.375rem]">

View File

@@ -62,31 +62,13 @@ export class PickUpShelfListItemComponent {
return this.item?.product?.contributors?.split(';').map((val) => val.trim());
}
get queryParams() {
const queryParams = this.store.filter?.getQueryParams();
if (this.item?.compartmentCode) {
return {
...queryParams,
buyerNumber: this.item?.buyerNumber,
};
} else {
return {
...queryParams,
};
}
}
get showChangeDate() {
return [256, 512, 1024, 2048, 4069].includes(this.item?.processingStatus);
}
// Zeige weder CompartmentCode noch OrderNumber an bei Status "bestellt" (16) und "nachbestellt" (8192)
get showCompartmentOrOrderNumber() {
return (
this.item.processingStatus !== 16 &&
this.item.processingStatus !== 8192 &&
(this.isTablet || this.isDesktopSmall || this.primaryOutletActive)
);
// Zeige nur CompartmentCode an wenn verfügbar
get showCompartmentCode() {
return !!this.item?.compartmentCode && (this.isTablet || this.isDesktopSmall || this.primaryOutletActive);
}
get processingStatusColor() {

View File

@@ -19,6 +19,14 @@ export const selectDisplayedCompartmentInfo = (s: PickupShelfDetailsState) => s.
export const selectOrderItems = (s: PickupShelfDetailsState): DBHOrderItemListItemDTO[] => {
let items = selectOrderItemsRaw(s);
const orderId = selectOrder(s)?.id;
if (!orderId) {
return [];
}
// Ticket #4348 - Möglicherweise sollte hier stattdessen auf die Buyernumber gefiltert werden, falls nicht alle OrderItems angezeigt werden die angezeigt werden sollten
items = items?.filter((oi) => oi.orderId === orderId);
const processingStatus = selectDisplayedOrderItemProcessingStatus(s);
if (processingStatus) {
items = items?.filter((oi) => oi.processingStatus === processingStatus);

View File

@@ -3,6 +3,7 @@ import { PickupShelfDetailsState } from './pickup-shelf-details.state';
import { Observable } from 'rxjs';
import {
DBHOrderItemListItemDTO,
EntityDTOContainerOfOrderItemSubsetDTO,
ListResponseArgsOfDBHOrderItemListItemDTO,
ListResponseArgsOfOrderItemSubsetTaskListItemDTO,
OrderDTO,
@@ -22,7 +23,6 @@ import { UiModalService } from '@ui/modal';
import { CrmCustomerService } from '@domain/crm';
import * as Selectors from './pickup-shelf-details.selectors';
import { CustomerInfoDTO, ListResponseArgsOfCustomerInfoDTO } from '@swagger/crm';
import { uniq } from 'lodash';
import { CacheService } from '@core/cache';
import { RunCheckTrigger } from '../trigger';
import { DomainReceiptService } from '@domain/oms';
@@ -137,7 +137,6 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
return this.get(Selectors.selectSelectedCompartmentInfo);
}
set selectedCompartmentInfo(selectedCompartmentInfo: string) {
console.log('set selectedCompartmentInfo', selectedCompartmentInfo);
if (this.selectedCompartmentInfo !== selectedCompartmentInfo) {
this.patchState({ selectedCompartmentInfo });
}
@@ -413,12 +412,12 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
},
resolve?: (items: DBHOrderItemListItemDTO[]) => void
) => (res: ListResponseArgsOfDBHOrderItemListItemDTO) => {
// // Ticket #4348
// check if order items belong to the same customer
const buyerNumbers = uniq(res.result.map((i) => i.buyerNumber));
if (buyerNumbers.length > 1) {
this._modal.error('Fehler beim Laden der Bestellpositionen', new Error('Die Bestellpositionen gehören zu unterschiedlichen Kunden.'));
return;
}
// if (buyerNumbers.length > 1) {
// this._modal.error('Fehler beim Laden der Bestellpositionen', new Error('Die Bestellpositionen gehören zu unterschiedlichen Kunden.'));
// return;
// }
this._cacheService.set<DBHOrderItemListItemDTO[]>(
{
@@ -470,9 +469,11 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
}
const customer = res.result[0];
const isKulturpass = this.order?.features?.orderSource === 'KulturPass';
// check if the customer is the same as the order's buyer
if (customer.customerNumber !== this.order.buyer.buyerNumber) {
// also check if the order is a KulturPass order, then there may be no customer
if (!isKulturpass && customer?.customerNumber !== this.order.buyer.buyerNumber) {
this._modal.error('Fehler beim Laden des Kunden', new Error('Der Kunde ist nicht der Bestellung zugeordnet.'));
return;
}
@@ -496,18 +497,17 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
this.patchState({ fetchingCustomer: false });
};
patchOrderItemSubset = this.effect(
(specialComment$: Observable<{ item: DBHOrderItemListItemDTO; changes: Partial<OrderItemSubsetDTO> }>) =>
specialComment$.pipe(
switchMap((data) =>
this._pickupShelfService.patchOrderItemSubset(data.item, data.changes).pipe(
tapResponse(
(res) => this.patchOrderItemSubsetDone(data.item)(res),
(err) => this.patchOrderItemSubsetError(err)
)
patchOrderItemSubset = this.effect(($: Observable<{ item: DBHOrderItemListItemDTO; changes: Partial<OrderItemSubsetDTO> }>) =>
$.pipe(
mergeMap((data) =>
this._pickupShelfService.patchOrderItemSubset(data.item, data.changes).pipe(
tapResponse(
(res) => this.patchOrderItemSubsetDone(data.item)(res),
(err) => this.patchOrderItemSubsetError(err)
)
)
)
)
);
private patchOrderItemSubsetDone = (item: DBHOrderItemListItemDTO) => (res: ResponseArgsOfOrderItemSubsetDTO) => {
@@ -515,14 +515,48 @@ export class PickupShelfDetailsStore extends ComponentStore<PickupShelfDetailsSt
orderItemSubsetId: item.orderItemSubsetId,
changes: {
specialComment: res.result.specialComment,
estimatedShippingDate: res.result.estimatedShippingDate,
estimatedDelivery: res.result.estimatedDelivery,
pickUpDeadline: res.result.compartmentStop,
},
});
if (res.result.preferredPickUpDate) {
this.patchPreferredPickUpDateOnOrderSubsetItemInState({ item, newPreferredPickUpDate: res.result.preferredPickUpDate });
}
};
private patchOrderItemSubsetError = (err: any) => {
this._modal.error('Fehler beim Speichern des Kommentars', err);
};
patchPreferredPickUpDateOnOrderSubsetItemInState({
item,
newPreferredPickUpDate,
}: {
item: DBHOrderItemListItemDTO;
newPreferredPickUpDate: string;
}) {
// Filter selected order subset items from order
const items = this.order.items;
const subsetItems: EntityDTOContainerOfOrderItemSubsetDTO[] = items
.reduce((acc, item) => {
return [...acc, ...item.data.subsetItems];
}, [])
.filter((item) => this.selectedOrderItemIds.find((id) => id === item.data.id));
// Update preferredPickUpDate on subsetItem from order and patch the state
const subsetItem = subsetItems.find((subsetItem) => subsetItem.data.id === item.orderItemSubsetId);
subsetItem.data.preferredPickUpDate = newPreferredPickUpDate;
this.patchState({
order: {
...this.order,
items: items,
},
});
}
patchOrderItemSubsetInState = this.updater(
(state, { orderItemSubsetId, changes }: { orderItemSubsetId: number; changes: Partial<DBHOrderItemListItemDTO> }) => {
return {

View File

@@ -14,6 +14,7 @@ import { EmptyControl } from './empty-control';
import { FirstErrorPipe } from './first-error.pipe';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
@Component({
selector: 'shared-form-control',
@@ -39,11 +40,17 @@ export class FormControlComponent implements OnDestroy, AfterContentInit {
required = false;
get displayLabel() {
return (this.label ?? this.control?.['name'] ?? '') + (this.required ? '*' : '');
return (this.label ?? this.control?.['name'] ?? '') + (this.required && this._hasRequiredMark ? '*' : '');
}
private _onDestroy$ = new Subject<void>();
private _hasRequiredMark = true;
@Input()
set hasRequiredMark(value: BooleanInput) {
this._hasRequiredMark = coerceBooleanProperty(value);
}
constructor(private _elementRef: ElementRef, private _cdr: ChangeDetectorRef) {}
ngAfterContentInit() {

View File

@@ -183,7 +183,7 @@
</div>
</div>
<div class="actions">
<button class="cta-close" (click)="navigateBack({})" type="button">Abbrechen</button>
<button class="cta-close" (click)="navigation.emit({})" type="button">Abbrechen</button>
<button class="cta-save" [disabled]="control.invalid || control.disabled" type="submit">Speichern</button>
</div>
</form>

View File

@@ -16,7 +16,15 @@ import {
import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { DomainOmsService } from '@domain/oms';
import { emailNotificationValidator, mobileNotificationValidator } from '@shared/components/notification-channel-control';
import { NotificationChannel, OrderItemListItemDTO, StockStatusCodeDTO, VATDTO } from '@swagger/oms';
import {
DBHOrderItemListItemDTO,
NotificationChannel,
OrderItemListItemDTO,
OrderItemProcessingStatusValue,
OrderItemSubsetDTO,
StockStatusCodeDTO,
VATDTO,
} from '@swagger/oms';
import { DateAdapter } from '@ui/common';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiSelectOptionComponent } from '@ui/select';
@@ -37,7 +45,7 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
@ViewChildren('autosize') autosize: QueryList<CdkTextareaAutosize>;
@Output()
navigation = new EventEmitter<{ options?: { processingStatus?: number } }>();
navigation = new EventEmitter<Partial<DBHOrderItemListItemDTO>>();
@Input()
items: OrderItemListItemDTO[];
@@ -216,10 +224,6 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
item.pickUpDeadline = deadline;
}
navigateBack({ processingStatus }: { processingStatus?: number }) {
processingStatus ? this.navigation.emit({ options: { processingStatus } }) : this.navigation.emit({});
}
async generateNotification(notificationChannels: NotificationChannel[]) {
if (!notificationChannels || notificationChannels.length === 0) {
return;
@@ -270,7 +274,8 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
}
}
let newProcessingStatus: number;
let newProcessingStatus: OrderItemProcessingStatusValue;
let changedOrderItemSubsets: OrderItemSubsetDTO[] = [];
for (let itemCtrl of control.items) {
const orderItemId = itemCtrl.orderItemId;
const orderItemSubsetId = itemCtrl.orderItemSubsetId;
@@ -318,34 +323,53 @@ export class SharedGoodsInOutOrderEditComponent implements OnChanges, OnDestroy
try {
if (this.isOrderItemSubsetDirty(formGroup)) {
await this.omsService
.patchOrderItemSubset({
orderId,
orderItemId,
orderItemSubsetId,
orderItemSubset: {
compartmentCode:
itemCtrl.compartmentInfo && itemCtrl.compartmentCode
? itemCtrl.compartmentCode.replace('_' + itemCtrl.compartmentInfo, '')
: itemCtrl.compartmentCode,
compartmentInfo: itemCtrl.compartmentInfo || '',
estimatedShippingDate: itemCtrl.estimatedShippingDate || null,
compartmentStop: itemCtrl.pickUpDeadline || null,
specialComment: itemCtrl.specialComment || '',
ssc: itemCtrl.ssc,
sscText: itemCtrl.sscText !== '' ? itemCtrl.sscText.substring(3) : '',
isPrebooked: itemCtrl.isPrebooked,
},
})
.pipe(first())
.toPromise();
changedOrderItemSubsets.push(
await this.omsService
.patchOrderItemSubset({
orderId,
orderItemId,
orderItemSubsetId,
orderItemSubset: {
compartmentCode:
itemCtrl.compartmentInfo && itemCtrl.compartmentCode
? itemCtrl.compartmentCode.replace('_' + itemCtrl.compartmentInfo, '')
: itemCtrl.compartmentCode,
compartmentInfo: itemCtrl.compartmentInfo || '',
estimatedShippingDate: itemCtrl.estimatedShippingDate || null,
compartmentStop: itemCtrl.pickUpDeadline || null,
specialComment: itemCtrl.specialComment || '',
ssc: itemCtrl.ssc,
sscText: itemCtrl.sscText !== '' ? itemCtrl.sscText.substring(3) : '',
isPrebooked: itemCtrl.isPrebooked,
},
})
.pipe(first())
.toPromise()
);
}
} catch (error) {
this._modal.open({ content: UiErrorModalComponent, data: error, title: 'Fehler beim Aktualisieren des Bestellpostens' });
throw error;
}
}
this.navigateBack({ processingStatus: newProcessingStatus });
if (changedOrderItemSubsets.length === 0) {
this.navigation.emit({});
return;
}
if (changedOrderItemSubsets.length === 1) {
this.navigation.emit({
processingStatus: newProcessingStatus,
compartmentCode: changedOrderItemSubsets[0].compartmentCode,
compartmentInfo: changedOrderItemSubsets[0].compartmentInfo,
});
return;
}
this.navigation.emit({
processingStatus: newProcessingStatus,
});
} catch (error) {
console.error(error);
this.enableControlFields();

View File

@@ -23,7 +23,7 @@
<span *ngIf="product?.volume && product?.publicationDate">|</span>
{{ product?.publicationDate | date: 'dd. MMMM yyyy' }}
</div>
<div class="shared-purchase-options-list-item__availabilities mt-6 grid grid-flow-col gap-4 justify-start">
<div class="shared-purchase-options-list-item__availabilities mt-3 grid grid-flow-row gap-2 justify-start">
<div class="whitespace-nowrap self-center" *ngIf="(availabilities$ | async)?.length">Verfügbar als</div>
<div *ngFor="let availability of availabilities$ | async" class="grid grid-flow-col gap-4 justify-start">
<div

View File

@@ -0,0 +1,23 @@
<div class="text-center pt-4 pb-1">
<div class="rounded-[50%] bg-[#26830C] w-8 h-8 inline-flex items-center justify-center self-center">
<shared-icon class="text-white" icon="done" [size]="24"></shared-icon>
</div>
</div>
<h1 class="text-center text-[1.625rem] font-bold pb-[.375rem]">Bestellbestätigung</h1>
<p class="text-center pb-4">Wie lautet Ihre Emailadresse?</p>
<shared-form-control label="E-Mail-Adresse" class="max-w-md mx-auto pb-4" hasRequiredMark="false">
<input placeholder="E-Mail" type="mail" class="input-control" [formControl]="emailControl" />
</shared-form-control>
<div class="text-center pb-4">
<button
(click)="sendOrderConfirmation()"
type="button"
[disabled]="emailControl.invalid || emailControl.disabled"
class="bg-brand text-white px-6 py-2 rounded-full border-2 border-solid border-brand font-bold disabled:bg-[#596470] disabled:border-[#596470] disabled:cursor-not-allowed disabled:text-white"
>
Bestellbestätigung senden
</button>
</div>

View File

@@ -0,0 +1,72 @@
import { Component, ChangeDetectionStrategy, inject, OnInit } from '@angular/core';
import { UiModalRef } from '@ui/modal';
import { SendOrderConfirmationModalData, SendOrderConfirmationModalResult } from './types';
import { FormControldModule } from '@shared/components/form-control';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { validateEmail } from 'apps/page/customer/src/lib/validators/email-validator';
import { IconComponent } from '@shared/components/icon';
import { NotificationChannel, OrderService } from '@swagger/oms';
import { ToasterService } from '@shared/shell';
@Component({
selector: 'shared-send-order-confirmation-modal',
templateUrl: 'send-order-confirmation-modal.component.html',
styleUrls: ['send-order-confirmation-modal.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
host: { class: 'shared-send-order-confirmation-modal' },
standalone: true,
imports: [FormControldModule, ReactiveFormsModule, IconComponent],
})
export class SendOrderConfirmationModalComponent implements OnInit {
toaster = inject(ToasterService);
orderService = inject(OrderService);
emailControl = new FormControl('', [Validators.required, Validators.email, validateEmail]);
readonly modalRef: UiModalRef<SendOrderConfirmationModalResult, SendOrderConfirmationModalData> = inject(UiModalRef);
ngOnInit(): void {
const email = this.modalRef.data.map((order) => order.buyer?.communicationDetails?.email).find((email) => !!email);
if (email) {
this.emailControl.setValue(email);
}
}
async sendOrderConfirmation() {
if (this.emailControl.invalid || this.emailControl.disabled) {
this.emailControl.markAllAsTouched();
return;
}
this.emailControl.disable();
const email = this.emailControl.value;
for (let order of this.modalRef.data) {
let notificationChannels = order.notificationChannels ?? 0;
notificationChannels = (1 | notificationChannels) as NotificationChannel;
try {
await this.orderService
.OrderPatchOrder({ orderId: order.id, order: { notificationChannels, buyer: { communicationDetails: { email } } } })
.toPromise();
const response = await this.orderService.OrderOrderConfirmationTask(order.id).toPromise();
this.toaster.open({
type: 'success',
message: `Bestellbestätigung für die Bestellung ${order.orderNumber} wurde erfolgreich versendet`,
});
this.modalRef.close(response.result);
return;
} catch (error) {
this.toaster.open({
type: 'danger',
message: `Fehler beim Versenden der Bestellbestätigung für die Bestellung ${order.orderNumber}`,
});
}
this.emailControl.enable();
}
}
}

View File

@@ -0,0 +1,23 @@
import { Injectable, inject } from '@angular/core';
import { UiModalService } from '@ui/modal';
import { SendOrderConfirmationModalComponent } from './send-order-confirmation-modal.component';
import { SendOrderConfirmationModalData, SendOrderConfirmationModalResult } from './types';
@Injectable({ providedIn: 'root' })
export class SendOrderConfirmationModalService {
private modal = inject(UiModalService);
async open(data: SendOrderConfirmationModalData): Promise<SendOrderConfirmationModalResult | undefined> {
// Darf nur für Abholfachbestellungen geöffnet werden
const orders = data.filter((order) => order.features?.orderType === 'Abholung');
const modalRef = this.modal.open<SendOrderConfirmationModalResult, SendOrderConfirmationModalData>({
content: SendOrderConfirmationModalComponent,
data: orders,
});
const result = await modalRef.afterClosed$.toPromise();
return result.data;
}
}

View File

@@ -0,0 +1,5 @@
import { DisplayOrderDTO, OrderItemSubsetTaskDTO } from '@swagger/oms';
export type SendOrderConfirmationModalData = DisplayOrderDTO[];
export type SendOrderConfirmationModalResult = OrderItemSubsetTaskDTO[];

View File

@@ -0,0 +1,3 @@
export * from './lib/send-order-confirmation-modal.component';
export * from './lib/types';
export * from './lib/send-order-confirmation-modal.service';

View File

@@ -141,6 +141,34 @@ export class CustomerSearchNavigation {
return this._router.navigate(route.path, { queryParams: route.queryParams });
}
editShippingAddressRoute(params: { processId: NumberInput; customerId: NumberInput; shippingAddressId: NumberInput }): NavigationRoute {
const path = [
'/kunde',
coerceNumberProperty(params.processId),
'customer',
{
outlets: {
primary: [
'search',
coerceNumberProperty(params.customerId),
'shippingaddress',
coerceNumberProperty(params.shippingAddressId),
'edit',
],
side: 'results',
},
},
];
const urlTree = this._router.createUrlTree(path, { queryParams: {} });
return {
path,
urlTree,
queryParams: {},
};
}
ordersRoute(params: { processId: NumberInput; customerId: NumberInput }): NavigationRoute {
const path = [
'/kunde',

View File

@@ -19,7 +19,7 @@
<a
*ngIf="customerSearchRoute$ | async; let customerSearchRoute"
class="side-menu-group-item"
(click)="closeSideMenu(); focusSearchBox()"
(click)="expandCustomer(); closeSideMenu(); focusSearchBox()"
[routerLink]="customerSearchRoute.path"
[queryParams]="customerSearchRoute.queryParams"
routerLinkActive="active"
@@ -140,7 +140,7 @@
<div class="side-menu-group-sub-item-wrapper">
<a
class="side-menu-group-item"
(click)="closeSideMenu(); focusSearchBox()"
(click)="expandShelf(); closeSideMenu(); focusSearchBox()"
*ngIf="pickUpShelfInRoutePath$ | async; let pickUpShelfInNavigation"
[routerLink]="pickUpShelfInNavigation.path"
[queryParams]="pickUpShelfInNavigation.queryParams"
@@ -154,14 +154,14 @@
</span>
<button
class="side-menu-group-arrow"
[class.side-menu-item-rotate]="goodsInExpanded"
(click)="$event.stopPropagation(); $event.preventDefault(); goodsInExpanded = !goodsInExpanded"
[class.side-menu-item-rotate]="shelfExpanded"
(click)="$event.stopPropagation(); $event.preventDefault(); shelfExpanded = !shelfExpanded"
>
<shared-icon icon="keyboard-arrow-down"></shared-icon>
</button>
</a>
<div class="side-menu-group-sub-items" [class.hidden]="!goodsInExpanded">
<div class="side-menu-group-sub-items" [class.hidden]="!shelfExpanded">
<a
class="side-menu-group-item"
*ngIf="pickUpShelfInListRoutePath$ | async; let pickUpShelfInListNavigation"

View File

@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, Inject } from '@angular/core';
import { Component, ChangeDetectionStrategy, Inject, ChangeDetectorRef } from '@angular/core';
import { AuthModule, AuthService } from '@core/auth';
import { StockService } from '@swagger/wws';
import { first, map, retry, switchMap, take } from 'rxjs/operators';
@@ -136,8 +136,8 @@ export class ShellSideMenuComponent {
queryParams: {},
});
goodsInExpanded: boolean;
customerExpanded: boolean;
shelfExpanded: boolean = false;
customerExpanded: boolean = false;
constructor(
private _shellService: ShellService,
@@ -155,9 +155,20 @@ export class ShellSideMenuComponent {
private _customerCreateNavigation: CustomerCreateNavigation,
private _pickUpShelfOutNavigation: PickUpShelfOutNavigationService,
private _pickUpShelfInNavigation: PickupShelfInNavigationService,
private _cdr: ChangeDetectorRef,
@Inject(DOCUMENT) private readonly _document: Document
) {}
expandCustomer() {
this.customerExpanded = true;
this._cdr.markForCheck();
}
expandShelf() {
this.shelfExpanded = true;
this._cdr.markForCheck();
}
getLastNavigationByProcessId(id: number, fallback?: { path: string[]; queryParams: any }) {
return this._breadcrumbService.getBreadcrumbByKey$(id)?.pipe(
map((breadcrumbs) => {

View File

@@ -11,7 +11,6 @@ export { DialogOfString } from './models/dialog-of-string';
export { DialogSettings } from './models/dialog-settings';
export { DialogContentType } from './models/dialog-content-type';
export { KeyValueDTOOfStringAndString } from './models/key-value-dtoof-string-and-string';
export { IPublicUserInfo } from './models/ipublic-user-info';
export { ProblemDetails } from './models/problem-details';
export { ResponseArgsOfIEnumerableOfAutocompleteDTO } from './models/response-args-of-ienumerable-of-autocomplete-dto';
export { AutocompleteDTO } from './models/autocomplete-dto';
@@ -200,6 +199,12 @@ export { ResponseArgsOfOrderDTO } from './models/response-args-of-order-dto';
export { ListResponseArgsOfOrderListItemDTO } from './models/list-response-args-of-order-list-item-dto';
export { ResponseArgsOfIEnumerableOfOrderListItemDTO } from './models/response-args-of-ienumerable-of-order-list-item-dto';
export { OrderListItemDTO } from './models/order-list-item-dto';
export { ResponseArgsOfIEnumerableOfOrderItemSubsetTaskDTO } from './models/response-args-of-ienumerable-of-order-item-subset-task-dto';
export { OrderItemSubsetTaskDTO } from './models/order-item-subset-task-dto';
export { EntityDTOContainerOfOrderItemSubsetTransitionDTO } from './models/entity-dtocontainer-of-order-item-subset-transition-dto';
export { OrderItemSubsetTransitionDTO } from './models/order-item-subset-transition-dto';
export { EntityDTOBaseOfOrderItemSubsetTransitionDTOAndIOrderItemStatusTransition } from './models/entity-dtobase-of-order-item-subset-transition-dtoand-iorder-item-status-transition';
export { EntityDTOBaseOfOrderItemSubsetTaskDTOAndIOrderItemStatusTask } from './models/entity-dtobase-of-order-item-subset-task-dtoand-iorder-item-status-task';
export { ResponseArgsOfBoolean } from './models/response-args-of-boolean';
export { ResponseArgsOfOrderItemDTO } from './models/response-args-of-order-item-dto';
export { ResponseArgsOfIEnumerableOfOrderItemDTO } from './models/response-args-of-ienumerable-of-order-item-dto';
@@ -226,9 +231,6 @@ export { ResponseArgsOfIEnumerableOfOrderItemSubsetDTO } from './models/response
export { ListResponseArgsOfOrderItemSubsetTaskListItemDTO } from './models/list-response-args-of-order-item-subset-task-list-item-dto';
export { ResponseArgsOfIEnumerableOfOrderItemSubsetTaskListItemDTO } from './models/response-args-of-ienumerable-of-order-item-subset-task-list-item-dto';
export { OrderItemSubsetTaskListItemDTO } from './models/order-item-subset-task-list-item-dto';
export { EntityDTOContainerOfOrderItemSubsetTransitionDTO } from './models/entity-dtocontainer-of-order-item-subset-transition-dto';
export { OrderItemSubsetTransitionDTO } from './models/order-item-subset-transition-dto';
export { EntityDTOBaseOfOrderItemSubsetTransitionDTOAndIOrderItemStatusTransition } from './models/entity-dtobase-of-order-item-subset-transition-dtoand-iorder-item-status-transition';
export { OrderItemStatusValuesDTO } from './models/order-item-status-values-dto';
export { ResponseArgsOfPayerDTO } from './models/response-args-of-payer-dto';
export { ResponseArgsOfShippingAddressDTO } from './models/response-args-of-shipping-address-dto';

View File

@@ -2,17 +2,69 @@
import { TouchedBase } from './touched-base';
import { GeoLocation } from './geo-location';
export interface AddressDTO extends TouchedBase{
/**
* Apartment
*/
apartment?: string;
/**
* c/o, zu Händen
*/
careOf?: string;
/**
* Ort
*/
city?: string;
/**
* Land (ISO3166 A 3)
*/
country?: string;
/**
* Stadtteil, District
*/
district?: string;
/**
* Orts-Koordinaten
*/
geoLocation?: GeoLocation;
/**
* Adresszusatz
*/
info?: string;
/**
* Postfach
*/
po?: string;
/**
* Region
*/
region?: string;
/**
* Bundesland, Bundesstaat, Kanton, ...
*/
state?: string;
/**
* Straße
*/
street?: string;
/**
* Hausnummer
*/
streetNumber?: string;
/**
* PLZ
*/
zipCode?: string;
}

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Adress Typ
*/
export type AddressType = 0 | 1 | 2 | 4 | 8;

View File

@@ -5,9 +5,29 @@ import { CommunicationDetailsDTO } from './communication-details-dto';
import { OrganisationDTO } from './organisation-dto';
import { PersonNamesDTO } from './person-names-dto';
export interface AddresseeDTO extends TouchedBase{
/**
* Adresse
*/
address?: AddressDTO;
/**
* Kontaktdaten
*/
communicationDetails?: CommunicationDetailsDTO;
/**
* Korrespondenzsprache
*/
locale?: string;
/**
* Organisation / Firma
*/
organisation?: OrganisationDTO;
/**
* Anrede / Namen
*/
person?: PersonNamesDTO;
}

View File

@@ -5,12 +5,49 @@ import { CommunicationDetailsDTO } from './communication-details-dto';
import { Gender } from './gender';
import { OrganisationDTO } from './organisation-dto';
export interface AddresseeWithReferenceDTO extends EntityReferenceDTO{
/**
* Adresse
*/
address?: AddressDTO;
/**
* Kommuninkations-Kontaktdaten
*/
communicationDetails?: CommunicationDetailsDTO;
/**
* Vorname
*/
firstName?: string;
/**
* Anrede
*
* NotSet = 0, Wert nicht gesetzt
* Neutrum = 1, Divers
* Male = 2, Herr
* Female = 4, Frau
*/
gender?: Gender;
/**
* Nachname
*/
lastName?: string;
/**
* Lokalisierung / (Korrespondenz-) Sprache
*/
locale?: string;
/**
* Organisation/Firma
*/
organisation?: OrganisationDTO;
/**
* Akademischer Titel
*/
title?: string;
}

View File

@@ -1,2 +1,7 @@
/* tslint:disable */
/**
* Richtlinie 2003/89/EG (Allergenkennzeichnungsrichtlinie)
* https://de.wikipedia.org/wiki/Richtlinie_2003/89/EG_(Allergenkennzeichnungsrichtlinie)
*/
export type AllergeneType = 0 | 1 | 2 | 4 | 6 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 1536 | 2048 | 6144 | 10240 | 18432 | 34816 | 67584 | 133120 | 264192 | 526336 | 1048576 | 3145728 | 5242880 | 9437184 | 17825792 | 34603008 | 68157440 | 135266304 | 268435456 | 805306368 | 1342177280 | 2415919104 | 4563402752 | 8858370048 | 17448304640 | 34628173824 | 68987912192 | 137438953472;

View File

@@ -1,7 +1,27 @@
/* tslint:disable */
/**
* Auocomplete-Ergebnis
*/
export interface AutocompleteDTO {
/**
* Anzeige / Bezeichner
*/
display?: string;
/**
* Id
*/
id?: string;
/**
* Abfragewert
*/
query?: string;
/**
* Art (z.B. Titel, Autor, Verlag, ...)
*/
type?: string;
}

View File

@@ -1,10 +1,38 @@
/* tslint:disable */
import { OrderByDTO } from './order-by-dto';
/**
* Suchabfrage
*/
export interface AutocompleteTokenDTO {
/**
* Filter
*/
filter?: {[key: string]: string};
/**
* Fuzzy (0 = off, > 0 = on)
*/
fuzzy?: number;
/**
* Eingabe
*/
input?: string;
/**
* Sortierung nach
*/
orderBy?: Array<OrderByDTO>;
/**
* Menge angezigter Treffer
*/
take?: number;
/**
* Typ (z.B. qs, author, title, publisher, customer, order, orderitem, ...)
*/
type?: string;
}

View File

@@ -7,22 +7,94 @@ import { PriceDTO } from './price-dto';
import { EntityDTOContainerOfShopItemDTO2 } from './entity-dtocontainer-of-shop-item-dto2';
import { EntityDTOContainerOfSupplierDTO } from './entity-dtocontainer-of-supplier-dto';
export interface AvailabilityDTO extends TouchedBase{
/**
* Art der Verfügbarkeit
*/
availabilityType?: AvailabilityType;
/**
* Voraussichtlicher Zustellungszeitraum
*/
estimatedDelivery?: DateRangeDTO;
/**
* vsl. Lieferdatum
*/
estimatedShippingDate?: string;
/**
* Auf Lager
*/
inStock?: number;
/**
* Artikel wird vorgemerkt
*/
isPrebooked?: boolean;
/**
* Letzte Verfügbarkeitsanfrage
*/
lastRequest?: string;
/**
* Logistiker / Versender
*/
logistician?: EntityDTOContainerOfLogisticianDTO;
/**
* Verkaufspreis (VK)
*/
price?: PriceDTO;
/**
* Eindeutige Referenz zur Zuordnung
*/
requestReference?: string;
/**
* Artikel / Produkt
*/
shopItem?: EntityDTOContainerOfShopItemDTO2;
/**
* Stock Status Code
*/
ssc?: string;
/**
* Stock Status Code - Beschreibung
*/
sscText?: string;
/**
* Lieferant
*/
supplier?: EntityDTOContainerOfSupplierDTO;
/**
* Zusätzliche Information des Lieferanten
*/
supplierInfo?: string;
/**
* Artikel- /Produktnummer des Lieferanten
*/
supplierProductNumber?: string;
/**
* Verfügbarkeitsstatus des Lieferanten
*/
supplierSSC?: string;
/**
* Beschreibung des Verfügbarkeitsstatus des Lieferanten
*/
supplierSSCText?: string;
/**
* Bezugsweg
*/
supplyChannel?: string;
}

View File

@@ -3,33 +3,149 @@ import { AvailableFor } from './available-for';
import { RangeDTO } from './range-dto';
import { PriceDTO } from './price-dto';
import { AvailabilityType } from './availability-type';
/**
* Verfügbarkeit
*/
export interface AvailabilityDTO2 {
/**
* Alternatives Voraussichtliches Lieferdatum
*/
altAt?: string;
/**
* Voraussichtliches Lieferdatum - von
*/
at?: string;
/**
* Verfügbar als/für
*/
availableFor?: AvailableFor;
/**
* EAN /ISBN13
*/
ean?: string;
/**
* vsl. Zustellung
*/
estimatedDelivery?: RangeDTO;
/**
* Erstverkaufstag (EVT)
*/
firstDayOfSale?: string;
/**
* Vorgemerkt
*/
isPrebooked?: boolean;
/**
* Produkt / Artikel PK
*/
itemId?: number;
/**
* Logistiker
*/
logistician?: string;
/**
* Logistiker PK
*/
logisticianId?: number;
/**
* Spätester Bestellzeitpunkt
*/
orderDeadline?: string;
/**
* Bestell-Referenz
*/
orderReference?: string;
/**
* Rang
*/
preferred?: number;
/**
* Preis (VK)
*/
price?: PriceDTO;
/**
* Preisbindung
*/
priceMaintained?: boolean;
/**
* Verfügbare Menge
*/
qty?: number;
/**
* Beschreibung des StatusCode
*/
requestMessage?: string;
/**
* Eindeutige Refrenz zur Zuordnung
*/
requestReference?: string;
/**
* StatusCode der Verfügbarkeitsanfrage
*/
requestStatusCode?: string;
/**
* Zeitstempel der Anfrage
*/
requested?: string;
/**
* Shop PK
*/
shop?: number;
/**
* Stock Status Code / Meldeschlüssel
*/
ssc?: string;
/**
* Stock Status Code / Beschreibung
*/
sscText?: string;
/**
* Verfügbarkeitsstatus
*/
status: AvailabilityType;
/**
* Lieferant
*/
supplier?: string;
/**
* Lieferant PK
*/
supplierId?: number;
/**
* Produkt / Artikel PK des Lieferanten
*/
supplierProductNumber?: string;
/**
* Voraussichtliches Lieferdatum - bis
*/
to?: string;
}

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Art der Verfügbarkeit
*/
export type AvailabilityType = 0 | 1 | 2 | 32 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 16384;

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Verfügbar als
*/
export type AvailableFor = 0 | 1 | 2 | 4 | 8 | 16 | 32;

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Handelsgewichte / Avoirdupois
*/
export type Avoirdupois = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;

View File

@@ -5,16 +5,70 @@ import { BranchType } from './branch-type';
import { EntityDTOContainerOfLabelDTO } from './entity-dtocontainer-of-label-dto';
import { EntityDTOContainerOfBranchDTO } from './entity-dtocontainer-of-branch-dto';
export interface BranchDTO extends EntityDTOBaseOfBranchDTOAndIBranch{
/**
* Addressdaten
*/
address?: AddressDTO;
/**
* Filial-/Abteilungsnnummer
*/
branchNumber?: string;
/**
* Art der Filiale/Abteilung
*
* NotSet = 0,
* Store = 1,
* WebStore = 2,
* CallCenter = 4,
* Headquarter = 8
*/
branchType?: BranchType;
/**
* Standard
*/
isDefault?: string;
/**
* Ist die Filiale aktiv
*/
isOnline?: boolean;
/**
* Aus dieser Filiale kann bestellt werden
*/
isOrderingEnabled?: boolean;
/**
* In diese Filiale kann bestellt werden
*/
isShippingEnabled?: boolean;
/**
* Eindeutiger Schlüssel/Kürzel (bezogen auf das Label)
*/
key?: string;
/**
* Label, welche die Fialiale/Abteilung angehört
*/
label?: EntityDTOContainerOfLabelDTO;
/**
* Name der Filiale/Abteilung
*/
name?: string;
/**
* Übergeordnete Filiale/Abteilung
*/
parent?: EntityDTOContainerOfBranchDTO;
/**
* Kurzname
*/
shortName?: string;
}

View File

@@ -3,9 +3,35 @@ import { AddresseeWithReferenceDTO } from './addressee-with-reference-dto';
import { BuyerStatus } from './buyer-status';
import { BuyerType } from './buyer-type';
export interface BuyerDTO extends AddresseeWithReferenceDTO{
/**
* Auftraggeber-Nummer
*/
buyerNumber?: string;
/**
* Kundenstatus
*/
buyerStatus?: BuyerStatus;
/**
* Kundentyp
*
* ContactCustomer = 1, Kontakt-Kunde
* BranchCustomer = 2, Filial-Kunde
* Staff = 4, Mitarbeiter
* B2C = 8, B2C Kunde (Anlage: Anrede, Vorname, Nachname und Adresse notwendig)
* B2B = 16, B2B Kunde, ehemals. Qualifizierter Kunde mit Firmenadresse (Anlage: Firmenname und Adresse)
*/
buyerType?: BuyerType;
/**
* Geburtsdatum
*/
dateOfBirth?: string;
/**
* Einmalkunde
*/
isTemporaryAccount?: boolean;
}

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Auftraggeberstatus
*/
export type BuyerStatus = 0 | 1 | 2 | 4 | 8 | 16;

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Auftraggebertyp
*/
export type BuyerType = 0 | 1 | 2 | 4 | 8 | 16;

View File

@@ -3,12 +3,44 @@ import { EntityDTOBase } from './entity-dtobase';
import { EntityDTOContainerOfCategoryDTO } from './entity-dtocontainer-of-category-dto';
import { EntityDTOContainerOfTenantDTO } from './entity-dtocontainer-of-tenant-dto';
export interface CategoryDTO extends EntityDTOBase{
/**
* Schlüssel
*/
key?: string;
/**
* Name/Bezeichnung der Kategorie
*/
name?: string;
/**
* Übergeordnete Kategorie
*/
parent?: EntityDTOContainerOfCategoryDTO;
/**
* Sortierung
*/
sort?: number;
/**
* Start
*/
start?: string;
/**
* Stop
*/
stop?: string;
/**
* Mandant
*/
tenant?: EntityDTOContainerOfTenantDTO;
/**
* Art, z.B. Warengruppe
*/
type?: string;
}

View File

@@ -1,7 +1,23 @@
/* tslint:disable */
export interface ChangeStockStatusCodeValues {
/**
* PK OrderItemSubset
*/
id: number;
/**
* Teilmenge
*/
quantity?: number;
/**
* Bemerkung zum Lieferhindernis
*/
shippingDelayComment?: string;
/**
* SSC (Meldeschlüssel)
*/
ssc?: string;
}

View File

@@ -1,8 +1,24 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
export interface CommunicationDetailsDTO extends TouchedBase{
/**
* E-Mail Adresse
*/
email?: string;
/**
* Faxnummer
*/
fax?: string;
/**
* Mobilnummer
*/
mobile?: string;
/**
* Telefonnummer
*/
phone?: string;
}

View File

@@ -3,16 +3,64 @@ import { EntityDTOBaseOfCompanyDTOAndICompany } from './entity-dtobase-of-compan
import { AddressDTO } from './address-dto';
import { EntityDTOContainerOfCompanyDTO } from './entity-dtocontainer-of-company-dto';
export interface CompanyDTO extends EntityDTOBaseOfCompanyDTOAndICompany{
/**
* Adresse
*/
address?: AddressDTO;
/**
* Firmen-Nr
*/
companyNumber?: string;
/**
* Kostenstelle
*/
costUnit?: string;
/**
* Abteilung/Bereich
*/
department?: string;
/**
* GLN
*/
gln?: string;
/**
* Rechtsform
*/
legalForm?: string;
/**
* Lokalisierung / (Korrespondenz-) Sprache
*/
locale?: string;
/**
* Name der Organisation/Firma
*/
name?: string;
/**
* Namens-Zusatz der Organisation/Firma
*/
nameSuffix?: string;
/**
* Übergeordnete Firma
*/
parent?: EntityDTOContainerOfCompanyDTO;
/**
* Branche
*/
sector?: string;
/**
* Umsatzsteuer Id
*/
vatId?: string;
}

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Attribut zur Darstellung
*/
export type ComponentItemDisplayType = 0 | 1 | 2;

View File

@@ -5,16 +5,64 @@ import { ComponentItemDisplayType } from './component-item-display-type';
import { EntityDTOContainerOfItemDTO2 } from './entity-dtocontainer-of-item-dto2';
import { QuantityUnitType } from './quantity-unit-type';
export interface ComponentItemDTO extends TouchedBase{
/**
* Kategorie des Set-Artikels (nicht Warengruppe)
*/
category?: EntityDTOContainerOfCategoryDTO;
/**
* Beschreibung des Set-Artikels (intern)
*/
description?: string;
/**
* Art der Anzeige
*/
displayType?: ComponentItemDisplayType;
/**
* Artikel
*/
item?: EntityDTOContainerOfItemDTO2;
/**
* Name des Set-Artikels (intern)
*/
name?: string;
/**
* Menge (max.)
*/
quantityMax?: number;
/**
* Menge (min.)
*/
quantityMin?: number;
/**
* Mengenart (z.B. Stück, Länge, Gewicht, Fläche, Volumen, Zeit)
*/
quantityUnitType?: QuantityUnitType;
/**
* Nicht optional / optional
*/
required?: boolean;
/**
* Beginn
*/
start?: string;
/**
* Ende
*/
stop?: string;
/**
* Maßeinheit
*/
unit?: string;
}

View File

@@ -4,11 +4,39 @@ import { ComponentItemDTO } from './component-item-dto';
import { QuantityUnitType } from './quantity-unit-type';
import { SetType } from './set-type';
export interface ComponentsDTO extends EntityDTOBaseOfComponentsDTOAndIComponents{
/**
* Artikel / Produkte
*/
items?: Array<ComponentItemDTO>;
/**
* Gesamtmenge aller Komponenten(max.)
*/
overallQuantityMax?: number;
/**
* Gesamtmenge aller Komponenten (min.)
*/
overallQuantityMin?: number;
/**
* Mengenart (z.B. Stück, Länge, Gewicht, Fläche, Volumen, Zeit)
*/
quantityUnitType?: QuantityUnitType;
/**
* Referenzmenge
*/
referenceQuantity?: number;
/**
* Feste oder auswählbare Komponenten
*/
type?: SetType;
/**
* Maßeinheit
*/
unit?: string;
}

View File

@@ -4,8 +4,24 @@ import { OrganisationNamesDTO } from './organisation-names-dto';
import { PersonNamesDTO } from './person-names-dto';
import { EntityDTOContainerOfTenantDTO } from './entity-dtocontainer-of-tenant-dto';
export interface ContributorDTO extends EntityDTOBaseOfContributorDTOAndIContributor{
/**
* Anzeigename
*/
friendlyName?: string;
/**
* Organisation / Firma
*/
organisation?: OrganisationNamesDTO;
/**
* Person
*/
person?: PersonNamesDTO;
/**
* Mandant
*/
tenant?: EntityDTOContainerOfTenantDTO;
}

View File

@@ -1,8 +1,24 @@
/* tslint:disable */
import { EntityDTOBaseOfCountryDTOAndICountry } from './entity-dtobase-of-country-dtoand-icountry';
export interface CountryDTO extends EntityDTOBaseOfCountryDTOAndICountry{
/**
* Standard
*/
isDefault?: string;
/**
* ISO Code 3166 A 3
*/
isO3166_A_3?: string;
/**
* Name
*/
name?: string;
/**
* Reihenfolge
*/
sort?: number;
}

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* CRUDA (Create, Read, Update, Delete, Archive)
*/
export type CRUDA = 0 | 1 | 2 | 4 | 8 | 16;

View File

@@ -1,6 +1,14 @@
/* tslint:disable */
import { TouchedBase } from './touched-base';
export interface DateRangeDTO extends TouchedBase{
/**
* Begin
*/
start?: string;
/**
* Ende
*/
stop?: string;
}

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Deklarationspflichtige Zusatzstoffe in Lebensmitteln
*/
export type DeclarableFoodAdditives = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 16384 | 32768 | 65536;

View File

@@ -1,2 +1,6 @@
/* tslint:disable */
/**
* Art des Inhalts
*/
export type DialogContentType = 0 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128;

View File

@@ -2,15 +2,59 @@
import { KeyValueDTOOfStringAndString } from './key-value-dtoof-string-and-string';
import { DialogContentType } from './dialog-content-type';
import { DialogSettings } from './dialog-settings';
/**
* Dialog / Meldung
*/
export interface DialogOfString {
/**
* Aktionen
*/
actions?: Array<KeyValueDTOOfStringAndString>;
/**
* null/0 = none, 1 = one, -1 = any, Actions.Count = all
*/
actionsRequired?: number;
/**
* Bereich (z.B. inline, toaster, status/embedded, dialog)
*/
area?: string;
/**
* Inhalt
*/
content?: string;
/**
* Art des Inhalts
*/
contentType: DialogContentType;
/**
* Beschreibung / Info
*/
description?: string;
/**
* Zeit in ms, nachder der Dialog ausgeblendet wird
*/
displayTimeout?: number;
/**
* Dialog-Einstellungen
*/
settings: DialogSettings;
/**
* Untertitel
*/
subtitle?: string;
/**
* Überschrift / Titel
*/
title?: string;
}

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