mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
feature(libs-feature-data-access): Using catchResponseArgsErrorPipe across all data-acesss services now and removed old patterns. Adjusted some tests and added Logging for every case wrapped in try catch patterns
Ref: #5340
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { AvailabilityService as GeneratedAvailabilityService } from '@generated/swagger/availability-api';
|
import { AvailabilityService as GeneratedAvailabilityService } from '@generated/swagger/availability-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
|
||||||
import { LogisticianService, Logistician } from '@isa/oms/data-access';
|
import { LogisticianService, Logistician } from '@isa/oms/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
// TODO: [Next Sprint - Architectural] Abstract cross-domain dependency
|
// TODO: [Next Sprint - Architectural] Abstract cross-domain dependency
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { StoreCheckoutBranchService } from '@generated/swagger/checkout-api';
|
import { StoreCheckoutBranchService } from '@generated/swagger/checkout-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { Cache, CacheTimeToLive, InFlight } from '@isa/common/decorators';
|
import { Cache, CacheTimeToLive, InFlight } from '@isa/common/decorators';
|
||||||
@@ -14,20 +17,20 @@ export class BranchService {
|
|||||||
@Cache({ ttl: CacheTimeToLive.fiveMinutes })
|
@Cache({ ttl: CacheTimeToLive.fiveMinutes })
|
||||||
@InFlight()
|
@InFlight()
|
||||||
async fetchBranches(abortSignal?: AbortSignal): Promise<Branch[]> {
|
async fetchBranches(abortSignal?: AbortSignal): Promise<Branch[]> {
|
||||||
let req$ = this.#branchService.StoreCheckoutBranchGetBranches({});
|
let req$ = this.#branchService
|
||||||
|
.StoreCheckoutBranchGetBranches({})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as Branch[];
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to fetch branches', error);
|
this.#logger.error('Failed to fetch branches', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Branch[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
PrintOrderConfirmation,
|
PrintOrderConfirmation,
|
||||||
PrintOrderConfirmationSchema,
|
PrintOrderConfirmationSchema,
|
||||||
} from '../schemas';
|
} from '../schemas';
|
||||||
import { ResponseArgsError } from '@isa/common/data-access';
|
import { catchResponseArgsErrorPipe } from '@isa/common/data-access';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
|
|
||||||
@@ -18,16 +18,19 @@ export class CheckoutPrintService {
|
|||||||
): Promise<ResponseArgs> {
|
): Promise<ResponseArgs> {
|
||||||
const parsed = PrintOrderConfirmationSchema.parse(params);
|
const parsed = PrintOrderConfirmationSchema.parse(params);
|
||||||
|
|
||||||
const req$ = this.#omsPrintService.OMSPrintAbholscheinById(parsed);
|
const req$ = this.#omsPrintService
|
||||||
|
.OMSPrintAbholscheinById(parsed)
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res;
|
||||||
const err = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to print order confirmation', err);
|
this.#logger.error('Failed to print order confirmation', error, () => ({
|
||||||
throw err;
|
printer: parsed.printer,
|
||||||
|
orderIds: parsed.data,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import {
|
|||||||
DestinationDTO,
|
DestinationDTO,
|
||||||
} from '@generated/swagger/checkout-api';
|
} from '@generated/swagger/checkout-api';
|
||||||
|
|
||||||
import { EntityContainer, ResponseArgsError } from '@isa/common/data-access';
|
import {
|
||||||
|
EntityContainer,
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { ShoppingCartService } from './shopping-cart.service';
|
import { ShoppingCartService } from './shopping-cart.service';
|
||||||
@@ -315,19 +318,21 @@ export class CheckoutService {
|
|||||||
shoppingCartId: number,
|
shoppingCartId: number,
|
||||||
customerFeatures: Record<string, string>,
|
customerFeatures: Record<string, string>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const req$ =
|
const req$ = this.#shoppingCartService
|
||||||
this.#shoppingCartService.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer(
|
.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer({
|
||||||
{
|
shoppingCartId,
|
||||||
shoppingCartId,
|
payload: { customerFeatures },
|
||||||
payload: { customerFeatures },
|
})
|
||||||
},
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
|
try {
|
||||||
|
await firstValueFrom(req$);
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error(
|
||||||
|
'Failed to update destinations for customer',
|
||||||
|
error,
|
||||||
|
() => ({ shoppingCartId }),
|
||||||
);
|
);
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
|
||||||
|
|
||||||
if (res.error) {
|
|
||||||
const error = new ResponseArgsError(res);
|
|
||||||
this.#logger.error('Failed to update destinations for customer', error);
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -345,20 +350,24 @@ export class CheckoutService {
|
|||||||
items.map(async (item) => {
|
items.map(async (item) => {
|
||||||
if (!item.id) return;
|
if (!item.id) return;
|
||||||
|
|
||||||
const req$ =
|
const req$ = this.#shoppingCartService
|
||||||
this.#shoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem(
|
.StoreCheckoutShoppingCartUpdateShoppingCartItem({
|
||||||
{
|
shoppingCartId,
|
||||||
|
shoppingCartItemId: item.id,
|
||||||
|
values: { specialComment: comment },
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
|
try {
|
||||||
|
await firstValueFrom(req$);
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error(
|
||||||
|
'Failed to set special comment on item',
|
||||||
|
error,
|
||||||
|
() => ({
|
||||||
shoppingCartId,
|
shoppingCartId,
|
||||||
shoppingCartItemId: item.id,
|
}),
|
||||||
values: { specialComment: comment },
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
|
||||||
|
|
||||||
if (res.error) {
|
|
||||||
const error = new ResponseArgsError(res);
|
|
||||||
this.#logger.error('Failed to set special comment on item');
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -369,20 +378,21 @@ export class CheckoutService {
|
|||||||
* Refreshes checkout to get latest state.
|
* Refreshes checkout to get latest state.
|
||||||
*/
|
*/
|
||||||
private async refreshCheckout(shoppingCartId: number): Promise<Checkout> {
|
private async refreshCheckout(shoppingCartId: number): Promise<Checkout> {
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutService
|
||||||
this.#storeCheckoutService.StoreCheckoutCreateOrRefreshCheckout({
|
.StoreCheckoutCreateOrRefreshCheckout({
|
||||||
shoppingCartId,
|
shoppingCartId,
|
||||||
});
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as Checkout;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to refresh checkout', error);
|
this.#logger.error('Failed to refresh checkout', error, () => ({
|
||||||
|
shoppingCartId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Checkout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -579,20 +589,22 @@ export class CheckoutService {
|
|||||||
checkoutId: number,
|
checkoutId: number,
|
||||||
buyerDTO: Buyer,
|
buyerDTO: Buyer,
|
||||||
): Promise<Checkout> {
|
): Promise<Checkout> {
|
||||||
const req$ = this.#buyerService.StoreCheckoutBuyerSetBuyerPOST({
|
const req$ = this.#buyerService
|
||||||
checkoutId,
|
.StoreCheckoutBuyerSetBuyerPOST({
|
||||||
buyerDTO,
|
checkoutId,
|
||||||
});
|
buyerDTO,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as Checkout;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to set buyer', error);
|
this.#logger.error('Failed to set buyer on checkout', error, () => ({
|
||||||
|
checkoutId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Checkout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -602,20 +614,22 @@ export class CheckoutService {
|
|||||||
checkoutId: number,
|
checkoutId: number,
|
||||||
payer: Payer,
|
payer: Payer,
|
||||||
): Promise<Checkout> {
|
): Promise<Checkout> {
|
||||||
const req$ = this.#payerService.StoreCheckoutPayerSetPayerPOST({
|
const req$ = this.#payerService
|
||||||
checkoutId,
|
.StoreCheckoutPayerSetPayerPOST({
|
||||||
payerDTO: payer,
|
checkoutId,
|
||||||
});
|
payerDTO: payer,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as Checkout;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to set payer', error);
|
this.#logger.error('Failed to set payer on checkout', error, () => ({
|
||||||
|
checkoutId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Checkout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -625,21 +639,24 @@ export class CheckoutService {
|
|||||||
checkoutId: number,
|
checkoutId: number,
|
||||||
channels: NotificationChannel,
|
channels: NotificationChannel,
|
||||||
): Promise<Checkout> {
|
): Promise<Checkout> {
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutService
|
||||||
this.#storeCheckoutService.StoreCheckoutSetNotificationChannels({
|
.StoreCheckoutSetNotificationChannels({
|
||||||
checkoutId,
|
checkoutId,
|
||||||
notificationChannel: channels,
|
notificationChannel: channels,
|
||||||
});
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as Checkout;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to set notification channels', error);
|
this.#logger.error(
|
||||||
|
'Failed to set notification channels on checkout',
|
||||||
|
error,
|
||||||
|
() => ({ checkoutId }),
|
||||||
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Checkout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -649,20 +666,24 @@ export class CheckoutService {
|
|||||||
checkoutId: number,
|
checkoutId: number,
|
||||||
paymentType: PaymentType,
|
paymentType: PaymentType,
|
||||||
): Promise<Checkout> {
|
): Promise<Checkout> {
|
||||||
const req$ = this.#paymentService.StoreCheckoutPaymentSetPaymentType({
|
const req$ = this.#paymentService
|
||||||
checkoutId,
|
.StoreCheckoutPaymentSetPaymentType({
|
||||||
paymentType: paymentType,
|
checkoutId,
|
||||||
});
|
paymentType: paymentType,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as Checkout;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to set payment type', error);
|
this.#logger.error(
|
||||||
|
'Failed to set payment type on checkout',
|
||||||
|
error,
|
||||||
|
() => ({ checkoutId, paymentType }),
|
||||||
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Checkout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -691,17 +712,21 @@ export class CheckoutService {
|
|||||||
shippingAddress: { ...shippingAddress },
|
shippingAddress: { ...shippingAddress },
|
||||||
};
|
};
|
||||||
|
|
||||||
const req$ = this.#storeCheckoutService.StoreCheckoutUpdateDestination({
|
const req$ = this.#storeCheckoutService
|
||||||
checkoutId,
|
.StoreCheckoutUpdateDestination({
|
||||||
destinationId: dest.id,
|
checkoutId,
|
||||||
destinationDTO: updatedDestination,
|
destinationId: dest.id,
|
||||||
});
|
destinationDTO: updatedDestination,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
await firstValueFrom(req$);
|
||||||
if (res.error) {
|
} catch (error) {
|
||||||
const error = new ResponseArgsError(res);
|
this.#logger.error('Failed to update destination', error, () => ({
|
||||||
this.#logger.error('Failed to update destination');
|
checkoutId,
|
||||||
|
destinationId: dest.id,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
} from '../schemas';
|
} from '../schemas';
|
||||||
import { RewardSelectionItem, ShoppingCart, ShoppingCartItem } from '../models';
|
import { RewardSelectionItem, ShoppingCart, ShoppingCartItem } from '../models';
|
||||||
import {
|
import {
|
||||||
ResponseArgsError,
|
catchResponseArgsErrorPipe,
|
||||||
takeUntilAborted,
|
takeUntilAborted,
|
||||||
ensureCurrencyDefaults,
|
ensureCurrencyDefaults,
|
||||||
} from '@isa/common/data-access';
|
} from '@isa/common/data-access';
|
||||||
@@ -36,107 +36,105 @@ export class ShoppingCartService {
|
|||||||
#checkoutMetadataService = inject(CheckoutMetadataService);
|
#checkoutMetadataService = inject(CheckoutMetadataService);
|
||||||
|
|
||||||
async createShoppingCart(): Promise<ShoppingCart> {
|
async createShoppingCart(): Promise<ShoppingCart> {
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutShoppingCartService
|
||||||
this.#storeCheckoutShoppingCartService.StoreCheckoutShoppingCartCreateShoppingCart();
|
.StoreCheckoutShoppingCartCreateShoppingCart()
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error) {
|
this.#shoppingCartStream.pub(
|
||||||
const err = new ResponseArgsError(res);
|
ShoppingCartEvent.Created,
|
||||||
this.#logger.error('Failed to create shopping cart', err);
|
res.result as ShoppingCart,
|
||||||
throw err;
|
'ShoppingCartService',
|
||||||
|
);
|
||||||
|
return res.result as ShoppingCart;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to create shopping cart', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#shoppingCartStream.pub(
|
|
||||||
ShoppingCartEvent.Created,
|
|
||||||
res.result as ShoppingCart,
|
|
||||||
'ShoppingCartService',
|
|
||||||
);
|
|
||||||
return res.result as ShoppingCart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getShoppingCart(
|
async getShoppingCart(
|
||||||
shoppingCartId: number,
|
shoppingCartId: number,
|
||||||
abortSignal?: AbortSignal,
|
abortSignal?: AbortSignal,
|
||||||
): Promise<ShoppingCart | undefined> {
|
): Promise<ShoppingCart | undefined> {
|
||||||
let req$ =
|
let req$ = this.#storeCheckoutShoppingCartService
|
||||||
this.#storeCheckoutShoppingCartService.StoreCheckoutShoppingCartGetShoppingCart(
|
.StoreCheckoutShoppingCartGetShoppingCart({
|
||||||
{
|
shoppingCartId,
|
||||||
shoppingCartId,
|
})
|
||||||
},
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
);
|
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error) {
|
this.#shoppingCartStream.pub(
|
||||||
const err = new ResponseArgsError(res);
|
ShoppingCartEvent.ItemUpdated,
|
||||||
this.#logger.error('Failed to fetch shopping cart', err);
|
res.result as ShoppingCart,
|
||||||
throw err;
|
'ShoppingCartService',
|
||||||
|
);
|
||||||
|
return res.result as ShoppingCart;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to get shopping cart', error, () => ({
|
||||||
|
shoppingCartId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#shoppingCartStream.pub(
|
|
||||||
ShoppingCartEvent.ItemUpdated,
|
|
||||||
res.result as ShoppingCart,
|
|
||||||
'ShoppingCartService',
|
|
||||||
);
|
|
||||||
return res.result as ShoppingCart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async canAddItems(
|
async canAddItems(
|
||||||
params: CanAddItemsToShoppingCartParams,
|
params: CanAddItemsToShoppingCartParams,
|
||||||
): Promise<ItemsResult[]> {
|
): Promise<ItemsResult[]> {
|
||||||
const parsed = CanAddItemsToShoppingCartParamsSchema.parse(params);
|
const parsed = CanAddItemsToShoppingCartParamsSchema.parse(params);
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutShoppingCartService
|
||||||
this.#storeCheckoutShoppingCartService.StoreCheckoutShoppingCartCanAddItems(
|
.StoreCheckoutShoppingCartCanAddItems({
|
||||||
{
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
shoppingCartId: parsed.shoppingCartId,
|
payload: parsed.payload as ItemPayload[],
|
||||||
payload: parsed.payload as ItemPayload[],
|
})
|
||||||
},
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
);
|
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as unknown as ItemsResult[];
|
||||||
const err = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error(
|
this.#logger.error(
|
||||||
'Failed to check if items can be added to shopping cart',
|
'Failed to check if items can be added',
|
||||||
err,
|
error,
|
||||||
|
() => ({ shoppingCartId: parsed.shoppingCartId }),
|
||||||
);
|
);
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as unknown as ItemsResult[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async addItem(params: AddItemToShoppingCartParams): Promise<ShoppingCart> {
|
async addItem(params: AddItemToShoppingCartParams): Promise<ShoppingCart> {
|
||||||
const parsed = AddItemToShoppingCartParamsSchema.parse(params);
|
const parsed = AddItemToShoppingCartParamsSchema.parse(params);
|
||||||
|
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutShoppingCartService
|
||||||
this.#storeCheckoutShoppingCartService.StoreCheckoutShoppingCartAddItemToShoppingCart(
|
.StoreCheckoutShoppingCartAddItemToShoppingCart({
|
||||||
{
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
shoppingCartId: parsed.shoppingCartId,
|
items: parsed.items as AddToShoppingCartDTO[],
|
||||||
items: parsed.items as AddToShoppingCartDTO[],
|
})
|
||||||
},
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
|
this.#shoppingCartStream.pub(
|
||||||
|
ShoppingCartEvent.ItemAdded,
|
||||||
|
res.result as ShoppingCart,
|
||||||
|
'ShoppingCartService',
|
||||||
);
|
);
|
||||||
|
return res.result as ShoppingCart;
|
||||||
const res = await firstValueFrom(req$);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to add item to shopping cart', error, () => ({
|
||||||
if (res.error) {
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
const err = new ResponseArgsError(res);
|
}));
|
||||||
this.#logger.error('Failed to add item to shopping cart', err);
|
throw error;
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#shoppingCartStream.pub(
|
|
||||||
ShoppingCartEvent.ItemAdded,
|
|
||||||
res.result as ShoppingCart,
|
|
||||||
'ShoppingCartService',
|
|
||||||
);
|
|
||||||
return res.result as ShoppingCart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateItem(
|
async updateItem(
|
||||||
@@ -144,60 +142,62 @@ export class ShoppingCartService {
|
|||||||
): Promise<ShoppingCart> {
|
): Promise<ShoppingCart> {
|
||||||
const parsed = UpdateShoppingCartItemParamsSchema.parse(params);
|
const parsed = UpdateShoppingCartItemParamsSchema.parse(params);
|
||||||
|
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutShoppingCartService
|
||||||
this.#storeCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem(
|
.StoreCheckoutShoppingCartUpdateShoppingCartItem({
|
||||||
{
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
shoppingCartId: parsed.shoppingCartId,
|
shoppingCartItemId: parsed.shoppingCartItemId,
|
||||||
shoppingCartItemId: parsed.shoppingCartItemId,
|
values: parsed.values as UpdateShoppingCartItemDTO,
|
||||||
values: parsed.values as UpdateShoppingCartItemDTO,
|
})
|
||||||
},
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
|
this.#shoppingCartStream.pub(
|
||||||
|
ShoppingCartEvent.ItemUpdated,
|
||||||
|
res.result as ShoppingCart,
|
||||||
|
'ShoppingCartService',
|
||||||
);
|
);
|
||||||
|
return res.result as ShoppingCart;
|
||||||
const res = await firstValueFrom(req$);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to update shopping cart item', error, () => ({
|
||||||
if (res.error) {
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
const err = new ResponseArgsError(res);
|
shoppingCartItemId: parsed.shoppingCartItemId,
|
||||||
this.#logger.error('Failed to update shopping cart item', err);
|
}));
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#shoppingCartStream.pub(
|
|
||||||
ShoppingCartEvent.ItemUpdated,
|
|
||||||
res.result as ShoppingCart,
|
|
||||||
'ShoppingCartService',
|
|
||||||
);
|
|
||||||
return res.result as ShoppingCart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeItem(
|
async removeItem(
|
||||||
params: RemoveShoppingCartItemParams,
|
params: RemoveShoppingCartItemParams,
|
||||||
): Promise<ShoppingCart> {
|
): Promise<ShoppingCart> {
|
||||||
const parsed = RemoveShoppingCartItemParamsSchema.parse(params);
|
const parsed = RemoveShoppingCartItemParamsSchema.parse(params);
|
||||||
const req$ =
|
const req$ = this.#storeCheckoutShoppingCartService
|
||||||
this.#storeCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem(
|
.StoreCheckoutShoppingCartUpdateShoppingCartItem({
|
||||||
{
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
shoppingCartId: parsed.shoppingCartId,
|
shoppingCartItemId: parsed.shoppingCartItemId,
|
||||||
shoppingCartItemId: parsed.shoppingCartItemId,
|
values: {
|
||||||
values: {
|
quantity: 0,
|
||||||
quantity: 0,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
|
this.#shoppingCartStream.pub(
|
||||||
|
ShoppingCartEvent.ItemRemoved,
|
||||||
|
res.result as ShoppingCart,
|
||||||
|
'ShoppingCartService',
|
||||||
);
|
);
|
||||||
|
return res.result as ShoppingCart;
|
||||||
const res = await firstValueFrom(req$);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to remove shopping cart item', error, () => ({
|
||||||
if (res.error) {
|
shoppingCartId: parsed.shoppingCartId,
|
||||||
const err = new ResponseArgsError(res);
|
shoppingCartItemId: parsed.shoppingCartItemId,
|
||||||
this.#logger.error('Failed to remove item from shopping cart', err);
|
}));
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#shoppingCartStream.pub(
|
|
||||||
ShoppingCartEvent.ItemRemoved,
|
|
||||||
res.result as ShoppingCart,
|
|
||||||
'ShoppingCartService',
|
|
||||||
);
|
|
||||||
return res.result as ShoppingCart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Code Kommentieren + Beschreiben
|
// TODO: Code Kommentieren + Beschreiben
|
||||||
|
|||||||
@@ -87,7 +87,8 @@ describe('SupplierService', () => {
|
|||||||
// Arrange
|
// Arrange
|
||||||
const errorResponse = {
|
const errorResponse = {
|
||||||
result: null,
|
result: null,
|
||||||
error: { message: 'API Error', code: 500 },
|
error: true,
|
||||||
|
message: 'API Error',
|
||||||
};
|
};
|
||||||
|
|
||||||
mockSupplierService.StoreCheckoutSupplierGetSuppliers.mockReturnValue(
|
mockSupplierService.StoreCheckoutSupplierGetSuppliers.mockReturnValue(
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { StoreCheckoutSupplierService } from '@generated/swagger/checkout-api';
|
import { StoreCheckoutSupplierService } from '@generated/swagger/checkout-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { Cache, CacheTimeToLive, InFlight } from '@isa/common/decorators';
|
import { Cache, CacheTimeToLive, InFlight } from '@isa/common/decorators';
|
||||||
@@ -32,37 +35,42 @@ export class SupplierService {
|
|||||||
async getTakeAwaySupplier(abortSignal?: AbortSignal): Promise<Supplier> {
|
async getTakeAwaySupplier(abortSignal?: AbortSignal): Promise<Supplier> {
|
||||||
this.#logger.debug('Fetching take away supplier');
|
this.#logger.debug('Fetching take away supplier');
|
||||||
|
|
||||||
let req$ = this.#supplierService.StoreCheckoutSupplierGetSuppliers({});
|
let req$ = this.#supplierService
|
||||||
|
.StoreCheckoutSupplierGetSuppliers({})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error) {
|
const takeAwaySupplier = res.result?.find(
|
||||||
const error = new ResponseArgsError(res);
|
(supplier) => supplier.supplierNumber === 'F',
|
||||||
this.#logger.error('Failed to fetch suppliers', error);
|
);
|
||||||
|
|
||||||
|
if (!takeAwaySupplier) {
|
||||||
|
const notFoundError = new Error('Take away supplier (F) not found');
|
||||||
|
this.#logger.error(
|
||||||
|
'Take away supplier not found',
|
||||||
|
notFoundError,
|
||||||
|
() => ({
|
||||||
|
availableSuppliers: res.result?.map((s) => s.supplierNumber),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
throw notFoundError;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#logger.debug('Take away supplier fetched', () => ({
|
||||||
|
supplierId: takeAwaySupplier.id,
|
||||||
|
supplierNumber: takeAwaySupplier.supplierNumber,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return takeAwaySupplier;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch take away supplier', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const takeAwaySupplier = res.result?.find(
|
|
||||||
(supplier) => supplier.supplierNumber === 'F',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!takeAwaySupplier) {
|
|
||||||
const notFoundError = new Error('Take away supplier (F) not found');
|
|
||||||
this.#logger.error('Take away supplier not found', notFoundError, () => ({
|
|
||||||
availableSuppliers: res.result?.map((s) => s.supplierNumber),
|
|
||||||
}));
|
|
||||||
throw notFoundError;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#logger.debug('Take away supplier fetched', () => ({
|
|
||||||
supplierId: takeAwaySupplier.id,
|
|
||||||
supplierNumber: takeAwaySupplier.supplierNumber,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return takeAwaySupplier;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { CountryService as ApiCountryService } from '@generated/swagger/crm-api';
|
import { CountryService as ApiCountryService } from '@generated/swagger/crm-api';
|
||||||
import { Cache, CacheTimeToLive } from '@isa/common/decorators';
|
import { Cache } from '@isa/common/decorators';
|
||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { Country } from '../models';
|
import { Country } from '../models';
|
||||||
import {
|
import {
|
||||||
catchResponseArgsErrorPipe,
|
catchResponseArgsErrorPipe,
|
||||||
ResponseArgs,
|
|
||||||
takeUntilAborted,
|
takeUntilAborted,
|
||||||
} from '@isa/common/data-access';
|
} from '@isa/common/data-access';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
import { logger } from '@isa/core/logging';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class CountryService {
|
export class CountryService {
|
||||||
#apiCountryService = inject(ApiCountryService);
|
#apiCountryService = inject(ApiCountryService);
|
||||||
|
#logger = logger(() => ({ service: 'CountryService' }));
|
||||||
|
|
||||||
@Cache()
|
@Cache()
|
||||||
async getCountries(abortSignal?: AbortSignal): Promise<Country[]> {
|
async getCountries(abortSignal?: AbortSignal): Promise<Country[]> {
|
||||||
@@ -23,8 +24,12 @@ export class CountryService {
|
|||||||
|
|
||||||
req$ = req$.pipe(catchResponseArgsErrorPipe());
|
req$ = req$.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
return res.result as Country[];
|
return res.result as Country[];
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to get countries', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
catchResponseArgsErrorPipe,
|
catchResponseArgsErrorPipe,
|
||||||
ResponseArgs,
|
ResponseArgs,
|
||||||
ResponseArgsError,
|
|
||||||
takeUntilAborted,
|
takeUntilAborted,
|
||||||
} from '@isa/common/data-access';
|
} from '@isa/common/data-access';
|
||||||
import { Cache, CacheTimeToLive } from '@isa/common/decorators';
|
import { Cache, CacheTimeToLive } from '@isa/common/decorators';
|
||||||
@@ -161,8 +160,15 @@ export class CrmSearchService {
|
|||||||
})
|
})
|
||||||
.pipe(catchResponseArgsErrorPipe());
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
return res?.result;
|
const res = await firstValueFrom(req$);
|
||||||
|
return res?.result;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Error adding customer card', error, () => ({
|
||||||
|
customerId: parsed.customerId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async lockCard(params: LockCardInput): Promise<boolean | undefined> {
|
async lockCard(params: LockCardInput): Promise<boolean | undefined> {
|
||||||
@@ -176,15 +182,15 @@ export class CrmSearchService {
|
|||||||
})
|
})
|
||||||
.pipe(catchResponseArgsErrorPipe());
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res?.result;
|
||||||
const err = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Lock card Failed', err);
|
this.#logger.error('Error locking customer card', error, () => ({
|
||||||
throw err;
|
cardCode: parsed.cardCode,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res?.result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async unlockCard(params: UnlockCardInput): Promise<boolean | undefined> {
|
async unlockCard(params: UnlockCardInput): Promise<boolean | undefined> {
|
||||||
@@ -199,15 +205,16 @@ export class CrmSearchService {
|
|||||||
})
|
})
|
||||||
.pipe(catchResponseArgsErrorPipe());
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res?.result;
|
||||||
const err = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Unlock card Failed', err);
|
this.#logger.error('Error unlocking customer card', error, () => ({
|
||||||
throw err;
|
customerId: parsed.customerId,
|
||||||
|
cardCode: parsed.cardCode,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res?.result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cache({ ttl: CacheTimeToLive.oneHour })
|
@Cache({ ttl: CacheTimeToLive.oneHour })
|
||||||
@@ -224,10 +231,14 @@ export class CrmSearchService {
|
|||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
this.#logger.debug('Successfully fetched current booking partner store');
|
const res = await firstValueFrom(req$);
|
||||||
|
this.#logger.debug('Successfully fetched current booking partner store');
|
||||||
return res?.result;
|
return res?.result;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Error fetching current booking partner store', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async addBooking(
|
async addBooking(
|
||||||
@@ -245,8 +256,16 @@ export class CrmSearchService {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.pipe(catchResponseArgsErrorPipe());
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
const res = await firstValueFrom(req$);
|
|
||||||
return res?.result;
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
return res?.result;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Error adding booking', error, () => ({
|
||||||
|
cardCode: parsed.cardCode,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -273,16 +292,12 @@ export class CrmSearchService {
|
|||||||
try {
|
try {
|
||||||
const res = await firstValueFrom(req$);
|
const res = await firstValueFrom(req$);
|
||||||
this.#logger.debug('Successfully checked Bon');
|
this.#logger.debug('Successfully checked Bon');
|
||||||
|
|
||||||
if (res.error) {
|
|
||||||
const err = new ResponseArgsError(res);
|
|
||||||
this.#logger.error('Bon check failed', err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res as ResponseArgs<LoyaltyBonResponse>;
|
return res as ResponseArgs<LoyaltyBonResponse>;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.#logger.error('Error checking Bon', error);
|
this.#logger.error('Error checking Bon', error, () => ({
|
||||||
|
cardCode,
|
||||||
|
bonNr,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,8 +316,16 @@ export class CrmSearchService {
|
|||||||
})
|
})
|
||||||
.pipe(catchResponseArgsErrorPipe());
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
this.#logger.debug('Successfully redeemed Bon');
|
const res = await firstValueFrom(req$);
|
||||||
return res?.result ?? false;
|
this.#logger.debug('Successfully redeemed Bon');
|
||||||
|
return res?.result ?? false;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Error redeeming Bon', error, () => ({
|
||||||
|
cardCode,
|
||||||
|
bonNr,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import {
|
|||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { ReceiptService } from '@generated/swagger/oms-api';
|
import { ReceiptService } from '@generated/swagger/oms-api';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { Receipt } from '../models';
|
import { Receipt } from '../models';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -74,29 +77,31 @@ export class HandleCommandService {
|
|||||||
parsed,
|
parsed,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let req$ = this.#receiptService.ReceiptGetReceiptsByOrderItemSubset({
|
let req$ = this.#receiptService
|
||||||
payload: parsed, // Payload Default from old Implementation, eagerLoading: 1 and receiptType: (1 + 64 + 128) set as Schema default
|
.ReceiptGetReceiptsByOrderItemSubset({
|
||||||
});
|
payload: parsed, // Payload Default from old Implementation, eagerLoading: 1 and receiptType: (1 + 64 + 128) set as Schema default
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error) {
|
// Mapping Logic from old implementation
|
||||||
const err = new ResponseArgsError(res);
|
const mappedReceipts =
|
||||||
|
res?.result?.map((r) => r.item3?.data).filter((f) => !!f) ?? [];
|
||||||
|
|
||||||
|
return mappedReceipts as Receipt[];
|
||||||
|
} catch (error) {
|
||||||
this.#logger.error(
|
this.#logger.error(
|
||||||
'Failed to fetch receipts by order item subset IDs',
|
'Failed to fetch receipts by order item subset IDs',
|
||||||
err,
|
error,
|
||||||
|
() => ({ ids: parsed.ids }),
|
||||||
);
|
);
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mapping Logic from old implementation
|
|
||||||
const mappedReceipts =
|
|
||||||
res?.result?.map((r) => r.item3?.data).filter((f) => !!f) ?? [];
|
|
||||||
|
|
||||||
return mappedReceipts as Receipt[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { LogisticianService as GeneratedLogisticianService } from '@generated/swagger/oms-api';
|
import { LogisticianService as GeneratedLogisticianService } from '@generated/swagger/oms-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { Cache, CacheTimeToLive, InFlight } from '@isa/common/decorators';
|
import { Cache, CacheTimeToLive, InFlight } from '@isa/common/decorators';
|
||||||
@@ -32,37 +35,38 @@ export class LogisticianService {
|
|||||||
async getLogistician2470(abortSignal?: AbortSignal): Promise<Logistician> {
|
async getLogistician2470(abortSignal?: AbortSignal): Promise<Logistician> {
|
||||||
this.#logger.debug('Fetching logistician 2470');
|
this.#logger.debug('Fetching logistician 2470');
|
||||||
|
|
||||||
let req$ = this.#logisticianService.LogisticianGetLogisticians({});
|
let req$ = this.#logisticianService
|
||||||
|
.LogisticianGetLogisticians({})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error || !res.result) {
|
const logistician = res.result?.find(
|
||||||
const error = new ResponseArgsError(res);
|
(l) => l.logisticianNumber === '2470',
|
||||||
this.#logger.error('Failed to fetch logisticians', error);
|
);
|
||||||
|
|
||||||
|
if (!logistician) {
|
||||||
|
const notFoundError = new Error('Logistician 2470 not found');
|
||||||
|
this.#logger.error('Logistician 2470 not found', notFoundError, () => ({
|
||||||
|
availableLogisticians: res.result?.map((l) => l.logisticianNumber),
|
||||||
|
}));
|
||||||
|
throw notFoundError;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#logger.debug('Logistician 2470 fetched', () => ({
|
||||||
|
logisticianId: logistician.id,
|
||||||
|
logisticianNumber: logistician.logisticianNumber,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return logistician;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch logistician 2470', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const logistician = res.result.find(
|
|
||||||
(l) => l.logisticianNumber === '2470',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!logistician) {
|
|
||||||
const notFoundError = new Error('Logistician 2470 not found');
|
|
||||||
this.#logger.error('Logistician 2470 not found', notFoundError, () => ({
|
|
||||||
availableLogisticians: res.result?.map((l) => l.logisticianNumber),
|
|
||||||
}));
|
|
||||||
throw notFoundError;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#logger.debug('Logistician 2470 fetched', () => ({
|
|
||||||
logisticianId: logistician.id,
|
|
||||||
logisticianNumber: logistician.logisticianNumber,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return logistician;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import {
|
|||||||
DBHOrderItemListItemDTO,
|
DBHOrderItemListItemDTO,
|
||||||
QueryTokenDTO,
|
QueryTokenDTO,
|
||||||
} from '@generated/swagger/oms-api';
|
} from '@generated/swagger/oms-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
@@ -49,26 +52,26 @@ export class OpenRewardTasksService {
|
|||||||
orderBy: [],
|
orderBy: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
let req$ = this.#abholfachService.AbholfachWarenausgabe(payload);
|
let req$ = this.#abholfachService
|
||||||
|
.AbholfachWarenausgabe(payload)
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
const tasks = res.result ?? [];
|
||||||
|
|
||||||
if (res.error) {
|
this.#logger.debug('Open reward tasks fetched', () => ({
|
||||||
const error = new ResponseArgsError(res);
|
taskCount: tasks.length,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return tasks;
|
||||||
|
} catch (error) {
|
||||||
this.#logger.error('Failed to fetch open reward tasks', error);
|
this.#logger.error('Failed to fetch open reward tasks', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks = res.result ?? [];
|
|
||||||
|
|
||||||
this.#logger.debug('Open reward tasks fetched', () => ({
|
|
||||||
taskCount: tasks.length,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return tasks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import {
|
|||||||
LogisticianService,
|
LogisticianService,
|
||||||
LogisticianDTO,
|
LogisticianDTO,
|
||||||
} from '@generated/swagger/oms-api';
|
} from '@generated/swagger/oms-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { DisplayOrder } from '../models';
|
import { DisplayOrder } from '../models';
|
||||||
@@ -36,19 +39,23 @@ export class OrderCreationService {
|
|||||||
throw new Error(`Invalid checkoutId: ${checkoutId}`);
|
throw new Error(`Invalid checkoutId: ${checkoutId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const req$ = this.#orderCheckoutService.OrderCheckoutCreateOrderPOST({
|
const req$ = this.#orderCheckoutService
|
||||||
checkoutId,
|
.OrderCheckoutCreateOrderPOST({
|
||||||
});
|
checkoutId,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as DisplayOrder[];
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to create orders', error);
|
this.#logger.error(
|
||||||
|
'Failed to create orders from checkout',
|
||||||
|
error,
|
||||||
|
() => ({ checkoutId }),
|
||||||
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as DisplayOrder[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,25 +70,29 @@ export class OrderCreationService {
|
|||||||
logisticianNumber = '2470',
|
logisticianNumber = '2470',
|
||||||
abortSignal?: AbortSignal,
|
abortSignal?: AbortSignal,
|
||||||
): Promise<LogisticianDTO> {
|
): Promise<LogisticianDTO> {
|
||||||
let req$ = this.#logisticianService.LogisticianGetLogisticians({});
|
let req$ = this.#logisticianService
|
||||||
|
.LogisticianGetLogisticians({})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) req$ = req$.pipe(takeUntilAborted(abortSignal));
|
if (abortSignal) req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error) {
|
const logistician = res.result?.find(
|
||||||
const error = new ResponseArgsError(res);
|
(l) => l.logisticianNumber === logisticianNumber,
|
||||||
this.#logger.error('Failed to get logistician', error);
|
);
|
||||||
|
|
||||||
|
if (!logistician) {
|
||||||
|
throw new Error(`Logistician ${logisticianNumber} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return logistician;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to get logistician', error, () => ({
|
||||||
|
logisticianNumber,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const logistician = res.result?.find(
|
|
||||||
(l) => l.logisticianNumber === logisticianNumber,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!logistician) {
|
|
||||||
throw new Error(`Logistician ${logisticianNumber} not found`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return logistician;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { OrderService } from '@generated/swagger/oms-api';
|
import { OrderService } from '@generated/swagger/oms-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
@@ -25,25 +28,28 @@ export class OrderRewardCollectService {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const req$ = this.#orderService.OrderLoyaltyCollect({
|
const req$ = this.#orderService
|
||||||
orderId: params.orderId,
|
.OrderLoyaltyCollect({
|
||||||
orderItemId: params.orderItemId,
|
orderId: params.orderId,
|
||||||
orderItemSubsetId: params.orderItemSubsetId,
|
orderItemId: params.orderItemId,
|
||||||
data: {
|
orderItemSubsetId: params.orderItemSubsetId,
|
||||||
collectType: params.collectType,
|
data: {
|
||||||
quantity: params.quantity,
|
collectType: params.collectType,
|
||||||
},
|
quantity: params.quantity,
|
||||||
});
|
},
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as DBHOrderItemListItem[];
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to collect reward item', error);
|
this.#logger.error('Failed to collect order reward', error, () => ({
|
||||||
|
orderId: params.orderId,
|
||||||
|
orderItemSubsetId: params.orderItemSubsetId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as DBHOrderItemListItem[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchOrderItemSubset(
|
async fetchOrderItemSubset(
|
||||||
@@ -57,22 +63,22 @@ export class OrderRewardCollectService {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
let req$ = this.#orderService.OrderGetOrderItemSubset(
|
let req$ = this.#orderService
|
||||||
params.orderItemSubsetId,
|
.OrderGetOrderItemSubset(params.orderItemSubsetId)
|
||||||
);
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result as DisplayOrderItemSubset;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to fetch order item subset', error);
|
this.#logger.error('Failed to fetch order item subset', error, () => ({
|
||||||
|
orderItemSubsetId: params.orderItemSubsetId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as DisplayOrderItemSubset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import {
|
|||||||
OrderDTO,
|
OrderDTO,
|
||||||
DisplayOrderDTO,
|
DisplayOrderDTO,
|
||||||
} from '@generated/swagger/oms-api';
|
} from '@generated/swagger/oms-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
@@ -20,21 +23,23 @@ export class OrdersService {
|
|||||||
orderId: number,
|
orderId: number,
|
||||||
abortSignal?: AbortSignal,
|
abortSignal?: AbortSignal,
|
||||||
): Promise<OrderDTO | null> {
|
): Promise<OrderDTO | null> {
|
||||||
let req$ = this.#orderService.OrderGetOrder(orderId);
|
let req$ = this.#orderService
|
||||||
|
.OrderGetOrder(orderId)
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result ?? null;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to fetch order', { orderId, error });
|
this.#logger.error('Failed to get order', error, () => ({
|
||||||
|
orderId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result ?? null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,21 +71,23 @@ export class OrdersService {
|
|||||||
orderId: number,
|
orderId: number,
|
||||||
abortSignal?: AbortSignal,
|
abortSignal?: AbortSignal,
|
||||||
): Promise<DisplayOrderDTO | null> {
|
): Promise<DisplayOrderDTO | null> {
|
||||||
let req$ = this.#orderService.OrderGetDisplayOrder(orderId);
|
let req$ = this.#orderService
|
||||||
|
.OrderGetDisplayOrder(orderId)
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
if (res.error) {
|
return res.result ?? null;
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to fetch display order', { orderId, error });
|
this.#logger.error('Failed to get display order', error, () => ({
|
||||||
|
orderId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result ?? null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { StockService, BranchDTO } from '@generated/swagger/inventory-api';
|
import { StockService, BranchDTO } from '@generated/swagger/inventory-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
@@ -27,41 +30,42 @@ export class BranchService {
|
|||||||
* @throws {Error} If branch retrieval fails
|
* @throws {Error} If branch retrieval fails
|
||||||
*/
|
*/
|
||||||
async getDefaultBranch(abortSignal?: AbortSignal): Promise<BranchDTO> {
|
async getDefaultBranch(abortSignal?: AbortSignal): Promise<BranchDTO> {
|
||||||
let req$ = this.#stockService.StockCurrentBranch();
|
let req$ = this.#stockService
|
||||||
|
.StockCurrentBranch()
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) req$ = req$.pipe(takeUntilAborted(abortSignal));
|
if (abortSignal) req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
const branch = res.result;
|
||||||
|
|
||||||
if (res.error) {
|
if (!branch) {
|
||||||
const error = new ResponseArgsError(res);
|
const error = new Error('No branch data returned');
|
||||||
|
this.#logger.error('Failed to get default branch', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: branch.id,
|
||||||
|
name: branch.name,
|
||||||
|
address: branch.address,
|
||||||
|
branchType: branch.branchType,
|
||||||
|
branchNumber: branch.branchNumber,
|
||||||
|
changed: branch.changed,
|
||||||
|
created: branch.created,
|
||||||
|
isDefault: branch.isDefault,
|
||||||
|
isOnline: branch.isOnline,
|
||||||
|
key: branch.key,
|
||||||
|
label: branch.label,
|
||||||
|
pId: branch.pId,
|
||||||
|
shortName: branch.shortName,
|
||||||
|
status: branch.status,
|
||||||
|
version: branch.version,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
this.#logger.error('Failed to get default branch', error);
|
this.#logger.error('Failed to get default branch', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const branch = res.result;
|
|
||||||
|
|
||||||
if (!branch) {
|
|
||||||
const error = new Error('No branch data returned');
|
|
||||||
this.#logger.error('Failed to get default branch', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: branch.id,
|
|
||||||
name: branch.name,
|
|
||||||
address: branch.address,
|
|
||||||
branchType: branch.branchType,
|
|
||||||
branchNumber: branch.branchNumber,
|
|
||||||
changed: branch.changed,
|
|
||||||
created: branch.created,
|
|
||||||
isDefault: branch.isDefault,
|
|
||||||
isOnline: branch.isOnline,
|
|
||||||
key: branch.key,
|
|
||||||
label: branch.label,
|
|
||||||
pId: branch.pId,
|
|
||||||
shortName: branch.shortName,
|
|
||||||
status: branch.status,
|
|
||||||
version: branch.version,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import { KeyValueStringAndString } from '../models';
|
|||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { RemissionStockService } from './remission-stock.service';
|
import { RemissionStockService } from './remission-stock.service';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { InFlight, Cache, CacheTimeToLive } from '@isa/common/decorators';
|
import { InFlight, Cache, CacheTimeToLive } from '@isa/common/decorators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,26 +68,29 @@ export class RemissionProductGroupService {
|
|||||||
stockId: assignedStock.id,
|
stockId: assignedStock.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let req$ = this.#remiService.RemiProductgroups({
|
let req$ = this.#remiService
|
||||||
stockId: assignedStock.id,
|
.RemiProductgroups({
|
||||||
});
|
stockId: assignedStock.id,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error || !res.result) {
|
this.#logger.debug('Successfully fetched product groups', () => ({
|
||||||
const error = new ResponseArgsError(res);
|
groupCount: res.result?.length || 0,
|
||||||
this.#logger.error('Failed to fetch product groups', error);
|
}));
|
||||||
|
|
||||||
|
return res.result as KeyValueStringAndString[];
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch product groups', error, () => ({
|
||||||
|
stockId: assignedStock.id,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.debug('Successfully fetched product groups', () => ({
|
|
||||||
groupCount: res.result?.length || 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.result as KeyValueStringAndString[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { ReturnService } from '@generated/swagger/inventory-api';
|
import { ReturnService } from '@generated/swagger/inventory-api';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { KeyValueStringAndString } from '../models';
|
import { KeyValueStringAndString } from '../models';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
@@ -74,29 +77,30 @@ export class RemissionReasonService {
|
|||||||
stockId: assignedStock?.id,
|
stockId: assignedStock?.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let req$ = this.#returnService.ReturnGetReturnReasons({
|
let req$ = this.#returnService
|
||||||
stockId: assignedStock?.id,
|
.ReturnGetReturnReasons({
|
||||||
});
|
stockId: assignedStock?.id,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
this.#logger.debug('Request configured with abort signal');
|
this.#logger.debug('Request configured with abort signal');
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error) {
|
this.#logger.debug('Successfully fetched return reasons', () => ({
|
||||||
this.#logger.error(
|
reasonCount: res.result?.length || 0,
|
||||||
'Failed to fetch return reasons',
|
}));
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
return res.result as KeyValueStringAndString[];
|
||||||
throw new ResponseArgsError(res);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch return reasons', error, () => ({
|
||||||
|
stockId: assignedStock?.id,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.debug('Successfully fetched return reasons', () => ({
|
|
||||||
reasonCount: res.result?.length || 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.result as KeyValueStringAndString[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -540,15 +540,15 @@ describe('RemissionReturnReceiptService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle abort signal', async () => {
|
it('should call API with correct parameters', async () => {
|
||||||
mockReturnService.ReturnCreateAndAssignPackage.mockReturnValue(
|
mockReturnService.ReturnCreateAndAssignPackage.mockReturnValue(
|
||||||
of({ result: mockReceipt, error: null }),
|
of({ result: mockReceipt, error: null }),
|
||||||
);
|
);
|
||||||
const abortController = new AbortController();
|
await service.assignPackage({
|
||||||
await service.assignPackage(
|
returnId: 123,
|
||||||
{ returnId: 123, receiptId: 456, packageNumber: 'PKG-789' },
|
receiptId: 456,
|
||||||
abortController.signal,
|
packageNumber: 'PKG-789',
|
||||||
);
|
});
|
||||||
expect(mockReturnService.ReturnCreateAndAssignPackage).toHaveBeenCalled();
|
expect(mockReturnService.ReturnCreateAndAssignPackage).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1052,24 +1052,20 @@ describe('RemissionReturnReceiptService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle abort signal', async () => {
|
it('should call API with correct parameters', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
mockReturnService.ReturnAddReturnItem.mockReturnValue(
|
mockReturnService.ReturnAddReturnItem.mockReturnValue(
|
||||||
of({ result: mockTuple, error: null }),
|
of({ result: mockTuple, error: null }),
|
||||||
);
|
);
|
||||||
const abortController = new AbortController();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await service.addReturnItem(
|
await service.addReturnItem({
|
||||||
{
|
returnId: 1,
|
||||||
returnId: 1,
|
receiptId: 2,
|
||||||
receiptId: 2,
|
returnItemId: 3,
|
||||||
returnItemId: 3,
|
quantity: 4,
|
||||||
quantity: 4,
|
inStock: 5,
|
||||||
inStock: 5,
|
});
|
||||||
},
|
|
||||||
abortController.signal,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(mockReturnService.ReturnAddReturnItem).toHaveBeenCalled();
|
expect(mockReturnService.ReturnAddReturnItem).toHaveBeenCalled();
|
||||||
@@ -1163,24 +1159,20 @@ describe('RemissionReturnReceiptService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle abort signal', async () => {
|
it('should call API with correct parameters', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
mockReturnService.ReturnAddReturnSuggestion.mockReturnValue(
|
mockReturnService.ReturnAddReturnSuggestion.mockReturnValue(
|
||||||
of({ result: mockTuple, error: null }),
|
of({ result: mockTuple, error: null }),
|
||||||
);
|
);
|
||||||
const abortController = new AbortController();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await service.addReturnSuggestionItem(
|
await service.addReturnSuggestionItem({
|
||||||
{
|
returnId: 1,
|
||||||
returnId: 1,
|
receiptId: 2,
|
||||||
receiptId: 2,
|
returnSuggestionId: 3,
|
||||||
returnSuggestionId: 3,
|
quantity: 4,
|
||||||
quantity: 4,
|
inStock: 5,
|
||||||
inStock: 5,
|
});
|
||||||
},
|
|
||||||
abortController.signal,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(mockReturnService.ReturnAddReturnSuggestion).toHaveBeenCalled();
|
expect(mockReturnService.ReturnAddReturnSuggestion).toHaveBeenCalled();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { inject, Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { ReturnService } from '@generated/swagger/inventory-api';
|
import { ReturnService } from '@generated/swagger/inventory-api';
|
||||||
import {
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
ResponseArgs,
|
ResponseArgs,
|
||||||
ResponseArgsError,
|
|
||||||
takeUntilAborted,
|
takeUntilAborted,
|
||||||
} from '@isa/common/data-access';
|
} from '@isa/common/data-access';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
@@ -102,86 +102,21 @@ export class RemissionReturnReceiptService {
|
|||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const returns = (res?.result as Return[]) || [];
|
||||||
this.#logger.error(
|
this.#logger.debug('Successfully fetched completed returns', () => ({
|
||||||
'Failed to fetch completed returns',
|
returnCount: returns.length,
|
||||||
new Error(res.message || 'Unknown error'),
|
}));
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
return returns;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch completed returns', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const returns = (res?.result as Return[]) || [];
|
|
||||||
this.#logger.debug('Successfully fetched completed returns', () => ({
|
|
||||||
returnCount: returns.length,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return returns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Fetches a specific remission return receipt by receipt and return IDs.
|
|
||||||
// * Validates parameters using FetchRemissionReturnReceiptSchema before making the request.
|
|
||||||
// *
|
|
||||||
// * @async
|
|
||||||
// * @param {FetchRemissionReturnParams} params - The receipt and return identifiers
|
|
||||||
// * @param {FetchRemissionReturnParams} params.receiptId - ID of the receipt to fetch
|
|
||||||
// * @param {FetchRemissionReturnParams} params.returnId - ID of the return containing the receipt
|
|
||||||
// * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
|
|
||||||
// * @returns {Promise<Receipt | undefined>} The receipt object if found, undefined otherwise
|
|
||||||
// * @throws {ResponseArgsError} When the API request fails
|
|
||||||
// * @throws {z.ZodError} When parameter validation fails
|
|
||||||
// *
|
|
||||||
// * @example
|
|
||||||
// * const receipt = await service.fetchRemissionReturnReceipt({
|
|
||||||
// * receiptId: '123',
|
|
||||||
// * returnId: '456'
|
|
||||||
// * });
|
|
||||||
// */
|
|
||||||
// async fetchRemissionReturnReceipt(
|
|
||||||
// params: FetchRemissionReturnParams,
|
|
||||||
// abortSignal?: AbortSignal,
|
|
||||||
// ): Promise<Receipt | undefined> {
|
|
||||||
// this.#logger.debug('Fetching remission return receipt', () => ({ params }));
|
|
||||||
|
|
||||||
// const { receiptId, returnId } =
|
|
||||||
// FetchRemissionReturnReceiptSchema.parse(params);
|
|
||||||
|
|
||||||
// this.#logger.info('Fetching return receipt from API', () => ({
|
|
||||||
// receiptId,
|
|
||||||
// returnId,
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// let req$ = this.#returnService.ReturnGetReturnReceipt({
|
|
||||||
// receiptId,
|
|
||||||
// returnId,
|
|
||||||
// eagerLoading: 2,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (abortSignal) {
|
|
||||||
// this.#logger.debug('Request configured with abort signal');
|
|
||||||
// req$ = req$.pipe(takeUntilAborted(abortSignal));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const res = await firstValueFrom(req$);
|
|
||||||
|
|
||||||
// if (res?.error) {
|
|
||||||
// this.#logger.error(
|
|
||||||
// 'Failed to fetch return receipt',
|
|
||||||
// new Error(res.message || 'Unknown error'),
|
|
||||||
// );
|
|
||||||
// throw new ResponseArgsError(res);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const receipt = res?.result as Receipt | undefined;
|
|
||||||
// this.#logger.debug('Successfully fetched return receipt', () => ({
|
|
||||||
// found: !!receipt,
|
|
||||||
// }));
|
|
||||||
|
|
||||||
// return receipt;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches a remission return by its ID.
|
* Fetches a remission return by its ID.
|
||||||
* Validates parameters using FetchReturnSchema before making the request.
|
* Validates parameters using FetchReturnSchema before making the request.
|
||||||
@@ -218,22 +153,19 @@ export class RemissionReturnReceiptService {
|
|||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const returnData = res?.result as Return | undefined;
|
||||||
this.#logger.error(
|
this.#logger.debug('Successfully fetched return', () => ({
|
||||||
'Failed to fetch return',
|
found: !!returnData,
|
||||||
new Error(res.message || 'Unknown error'),
|
}));
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
return returnData;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch return', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnData = res?.result as Return | undefined;
|
|
||||||
this.#logger.debug('Successfully fetched return', () => ({
|
|
||||||
found: !!returnData,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return returnData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -286,22 +218,19 @@ export class RemissionReturnReceiptService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const returnResponse = res as ResponseArgs<Return> | undefined;
|
||||||
this.#logger.error(
|
this.#logger.debug('Successfully created return', () => ({
|
||||||
'Failed to create return',
|
found: !!returnResponse,
|
||||||
new Error(res.message || 'Unknown error'),
|
}));
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
return returnResponse;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to create return', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnResponse = res as ResponseArgs<Return> | undefined;
|
|
||||||
this.#logger.debug('Successfully created return', () => ({
|
|
||||||
found: !!returnResponse,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return returnResponse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -354,22 +283,19 @@ export class RemissionReturnReceiptService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const receiptResponse = res as ResponseArgs<Receipt> | undefined;
|
||||||
this.#logger.error(
|
this.#logger.debug('Successfully created return receipt', () => ({
|
||||||
'Failed to create return receipt',
|
found: !!receiptResponse,
|
||||||
new Error(res.message || 'Unknown error'),
|
}));
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
return receiptResponse;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to create return receipt', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const receiptResponse = res as ResponseArgs<Receipt> | undefined;
|
|
||||||
this.#logger.debug('Successfully created return receipt', () => ({
|
|
||||||
found: !!receiptResponse,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return receiptResponse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -411,24 +337,21 @@ export class RemissionReturnReceiptService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const receiptWithAssignedPackageResponse = res as
|
||||||
this.#logger.error(
|
| ResponseArgs<Receipt>
|
||||||
'Failed to assign package',
|
| undefined;
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
this.#logger.debug('Successfully assigned package', () => ({
|
||||||
throw new ResponseArgsError(res);
|
found: !!receiptWithAssignedPackageResponse,
|
||||||
|
}));
|
||||||
|
return receiptWithAssignedPackageResponse;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to assign package', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const receiptWithAssignedPackageResponse = res as
|
|
||||||
| ResponseArgs<Receipt>
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
this.#logger.debug('Successfully assigned package', () => ({
|
|
||||||
found: !!receiptWithAssignedPackageResponse,
|
|
||||||
}));
|
|
||||||
return receiptWithAssignedPackageResponse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async removeReturnItemFromReturnReceipt(params: {
|
async removeReturnItemFromReturnReceipt(params: {
|
||||||
@@ -436,16 +359,15 @@ export class RemissionReturnReceiptService {
|
|||||||
receiptId: number;
|
receiptId: number;
|
||||||
receiptItemId: number;
|
receiptItemId: number;
|
||||||
}) {
|
}) {
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnRemoveReturnItem(params),
|
await firstValueFrom(
|
||||||
);
|
this.#returnService
|
||||||
|
.ReturnRemoveReturnItem(params)
|
||||||
if (res?.error) {
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
this.#logger.error(
|
|
||||||
'Failed to remove item from return receipt',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to remove item from return receipt', error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,16 +386,17 @@ export class RemissionReturnReceiptService {
|
|||||||
returnId: number;
|
returnId: number;
|
||||||
receiptId: number;
|
receiptId: number;
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnCancelReturnReceipt(params),
|
await firstValueFrom(
|
||||||
);
|
this.#returnService
|
||||||
|
.ReturnCancelReturnReceipt(params)
|
||||||
if (res?.error) {
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
this.#logger.error(
|
|
||||||
'Failed to cancel return receipt',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to cancel return receipt', error, () => ({
|
||||||
|
params,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,34 +409,36 @@ export class RemissionReturnReceiptService {
|
|||||||
* @throws {ResponseArgsError} When the API request fails
|
* @throws {ResponseArgsError} When the API request fails
|
||||||
*/
|
*/
|
||||||
async cancelReturn(params: { returnId: number }): Promise<void> {
|
async cancelReturn(params: { returnId: number }): Promise<void> {
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnCancelReturn(params),
|
await firstValueFrom(
|
||||||
);
|
this.#returnService
|
||||||
|
.ReturnCancelReturn(params)
|
||||||
if (res?.error) {
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
this.#logger.error(
|
|
||||||
'Failed to cancel return',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to cancel return', error, () => ({
|
||||||
|
params,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteReturnItem(params: { itemId: number }) {
|
async deleteReturnItem(params: { itemId: number }) {
|
||||||
this.#logger.debug('Deleting return item', () => ({ params }));
|
this.#logger.debug('Deleting return item', () => ({ params }));
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnDeleteReturnItem(params),
|
const res = await firstValueFrom(
|
||||||
);
|
this.#returnService
|
||||||
|
.ReturnDeleteReturnItem(params)
|
||||||
if (res?.error) {
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
this.#logger.error(
|
|
||||||
'Failed to delete return item',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res?.result as ReturnItem;
|
return res?.result as ReturnItem;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to delete return item', error, () => ({
|
||||||
|
params,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateReturnItemImpediment(params: UpdateItemImpediment) {
|
async updateReturnItemImpediment(params: UpdateItemImpediment) {
|
||||||
@@ -521,24 +446,27 @@ export class RemissionReturnReceiptService {
|
|||||||
|
|
||||||
const { itemId, comment } = UpdateItemImpedimentSchema.parse(params);
|
const { itemId, comment } = UpdateItemImpedimentSchema.parse(params);
|
||||||
|
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnReturnItemImpediment({
|
const res = await firstValueFrom(
|
||||||
itemId,
|
this.#returnService
|
||||||
data: {
|
.ReturnReturnItemImpediment({
|
||||||
comment,
|
itemId,
|
||||||
},
|
data: {
|
||||||
}),
|
comment,
|
||||||
);
|
},
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
|
);
|
||||||
|
|
||||||
if (res?.error) {
|
return res?.result as ReturnItem;
|
||||||
|
} catch (error) {
|
||||||
this.#logger.error(
|
this.#logger.error(
|
||||||
'Failed to update return item impediment',
|
'Failed to update return item impediment',
|
||||||
new Error(res.message || 'Unknown error'),
|
error,
|
||||||
|
() => ({ itemId, comment }),
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res?.result as ReturnItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateReturnSuggestionImpediment(params: UpdateItemImpediment) {
|
async updateReturnSuggestionImpediment(params: UpdateItemImpediment) {
|
||||||
@@ -546,22 +474,26 @@ export class RemissionReturnReceiptService {
|
|||||||
params,
|
params,
|
||||||
}));
|
}));
|
||||||
const { itemId, comment } = UpdateItemImpedimentSchema.parse(params);
|
const { itemId, comment } = UpdateItemImpedimentSchema.parse(params);
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnReturnSuggestionImpediment({
|
const res = await firstValueFrom(
|
||||||
itemId,
|
this.#returnService
|
||||||
data: {
|
.ReturnReturnSuggestionImpediment({
|
||||||
comment,
|
itemId,
|
||||||
},
|
data: {
|
||||||
}),
|
comment,
|
||||||
);
|
},
|
||||||
if (res?.error) {
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
|
);
|
||||||
|
return res?.result as ReturnSuggestion;
|
||||||
|
} catch (error) {
|
||||||
this.#logger.error(
|
this.#logger.error(
|
||||||
'Failed to update return suggestion impediment',
|
'Failed to update return suggestion impediment',
|
||||||
new Error(res.message || 'Unknown error'),
|
error,
|
||||||
|
() => ({ itemId, comment }),
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
throw error;
|
||||||
}
|
}
|
||||||
return res?.result as ReturnSuggestion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async completeReturnReceipt({
|
async completeReturnReceipt({
|
||||||
@@ -572,23 +504,25 @@ export class RemissionReturnReceiptService {
|
|||||||
receiptId: number;
|
receiptId: number;
|
||||||
}): Promise<Receipt> {
|
}): Promise<Receipt> {
|
||||||
this.#logger.debug('Completing return receipt', () => ({ returnId }));
|
this.#logger.debug('Completing return receipt', () => ({ returnId }));
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnFinalizeReceipt({
|
const res = await firstValueFrom(
|
||||||
|
this.#returnService
|
||||||
|
.ReturnFinalizeReceipt({
|
||||||
|
returnId,
|
||||||
|
receiptId,
|
||||||
|
data: {},
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return res?.result as Receipt;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to complete return receipt', error, () => ({
|
||||||
returnId,
|
returnId,
|
||||||
receiptId,
|
receiptId,
|
||||||
data: {},
|
}));
|
||||||
}),
|
throw error;
|
||||||
);
|
|
||||||
|
|
||||||
if (res?.error) {
|
|
||||||
this.#logger.error(
|
|
||||||
'Failed to complete return receipt',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res?.result as Receipt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async completeReturn(params: { returnId: number }): Promise<Return> {
|
async completeReturn(params: { returnId: number }): Promise<Return> {
|
||||||
@@ -596,23 +530,24 @@ export class RemissionReturnReceiptService {
|
|||||||
returnId: params.returnId,
|
returnId: params.returnId,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnFinalizeReturn(params),
|
const res = await firstValueFrom(
|
||||||
);
|
this.#returnService
|
||||||
|
.ReturnFinalizeReturn(params)
|
||||||
if (res?.error) {
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
this.#logger.error(
|
|
||||||
'Failed to complete return',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
|
||||||
|
this.#logger.info('Successfully completed return', () => ({
|
||||||
|
returnId: params.returnId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res?.result as Return;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to complete return', error, () => ({
|
||||||
|
returnId: params.returnId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.info('Successfully completed return', () => ({
|
|
||||||
returnId: params.returnId,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res?.result as Return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async completeReturnGroup(params: { returnGroup: string }) {
|
async completeReturnGroup(params: { returnGroup: string }) {
|
||||||
@@ -620,23 +555,24 @@ export class RemissionReturnReceiptService {
|
|||||||
returnId: params.returnGroup,
|
returnId: params.returnGroup,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const res = await firstValueFrom(
|
try {
|
||||||
this.#returnService.ReturnFinalizeReturnGroup(params),
|
const res = await firstValueFrom(
|
||||||
);
|
this.#returnService
|
||||||
|
.ReturnFinalizeReturnGroup(params)
|
||||||
if (res?.error) {
|
.pipe(catchResponseArgsErrorPipe()),
|
||||||
this.#logger.error(
|
|
||||||
'Failed to complete return group',
|
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
);
|
||||||
throw new ResponseArgsError(res);
|
|
||||||
|
this.#logger.info('Successfully completed return group', () => ({
|
||||||
|
returnId: params.returnGroup,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res?.result as Return[];
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to complete return group', error, () => ({
|
||||||
|
returnGroup: params.returnGroup,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.info('Successfully completed return group', () => ({
|
|
||||||
returnId: params.returnGroup,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res?.result as Return[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async completeReturnReceiptAndReturn(params: {
|
async completeReturnReceiptAndReturn(params: {
|
||||||
@@ -711,22 +647,23 @@ export class RemissionReturnReceiptService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const updatedReturn = res?.result as ReceiptReturnTuple | undefined;
|
||||||
this.#logger.error(
|
this.#logger.debug('Successfully added return item', () => ({
|
||||||
'Failed to add return item',
|
found: !!updatedReturn,
|
||||||
new Error(res.message || 'Unknown error'),
|
}));
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
return updatedReturn;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to add return item', error, () => ({
|
||||||
|
returnId,
|
||||||
|
receiptId,
|
||||||
|
returnItemId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedReturn = res?.result as ReceiptReturnTuple | undefined;
|
|
||||||
this.#logger.debug('Successfully added return item', () => ({
|
|
||||||
found: !!updatedReturn,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return updatedReturn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -788,24 +725,25 @@ export class RemissionReturnReceiptService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res?.error) {
|
const updatedReturnSuggestion = res?.result as
|
||||||
this.#logger.error(
|
| ReceiptReturnSuggestionTuple
|
||||||
'Failed to add return suggestion item',
|
| undefined;
|
||||||
new Error(res.message || 'Unknown error'),
|
this.#logger.debug('Successfully added return suggestion item', () => ({
|
||||||
);
|
found: !!updatedReturnSuggestion,
|
||||||
throw new ResponseArgsError(res);
|
}));
|
||||||
|
|
||||||
|
return updatedReturnSuggestion;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to add return suggestion item', error, () => ({
|
||||||
|
returnId,
|
||||||
|
receiptId,
|
||||||
|
returnSuggestionId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedReturnSuggestion = res?.result as
|
|
||||||
| ReceiptReturnSuggestionTuple
|
|
||||||
| undefined;
|
|
||||||
this.#logger.debug('Successfully added return suggestion item', () => ({
|
|
||||||
found: !!updatedReturnSuggestion,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return updatedReturnSuggestion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import {
|
|||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
BatchResponseArgs,
|
BatchResponseArgs,
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
ListResponseArgs,
|
ListResponseArgs,
|
||||||
ResponseArgsError,
|
|
||||||
takeUntilAborted,
|
takeUntilAborted,
|
||||||
} from '@isa/common/data-access';
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
@@ -122,16 +122,18 @@ export class RemissionSearchService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res.error) {
|
this.#logger.debug('Successfully fetched required capacity');
|
||||||
const error = new ResponseArgsError(res);
|
return (res?.result ?? []) as ValueTupleOfStringAndInteger[];
|
||||||
this.#logger.error('Failed to fetch required capacity', error);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch required capacity', error, () => ({
|
||||||
|
stockId: parsed.stockId,
|
||||||
|
supplierId: parsed.supplierId,
|
||||||
|
}));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.debug('Successfully fetched required capacity');
|
|
||||||
return (res?.result ?? []) as ValueTupleOfStringAndInteger[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -401,14 +403,18 @@ export class RemissionSearchService {
|
|||||||
req = req.pipe(takeUntilAborted(abortSignal));
|
req = req.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req);
|
try {
|
||||||
if (res.error) {
|
const res = await firstValueFrom(req.pipe(catchResponseArgsErrorPipe()));
|
||||||
const error = new ResponseArgsError(res);
|
|
||||||
this.#logger.error('Failed to check item addition', error);
|
return res as BatchResponseArgs<ReturnItem>;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error(
|
||||||
|
'Failed to check if items can be added to remission list',
|
||||||
|
error,
|
||||||
|
() => ({ stockId: stock.id, itemCount: items.length }),
|
||||||
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res as BatchResponseArgs<ReturnItem>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async addToList(
|
async addToList(
|
||||||
@@ -437,14 +443,17 @@ export class RemissionSearchService {
|
|||||||
})),
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$.pipe(catchResponseArgsErrorPipe()));
|
||||||
|
|
||||||
if (res.error) {
|
return res.successful?.map((r) => r.value) as ReturnItem[];
|
||||||
const error = new ResponseArgsError(res);
|
} catch (error) {
|
||||||
this.#logger.error('Failed to add item to remission list', error);
|
this.#logger.error(
|
||||||
|
'Failed to add items to remission list',
|
||||||
|
error,
|
||||||
|
() => ({ stockId: stock.id, itemCount: items.length }),
|
||||||
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.successful?.map((r) => r.value) as ReturnItem[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,13 +87,13 @@ describe('RemissionStockService', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw ResponseArgsError when API returns no result', async () => {
|
it('should throw Error when API returns no result', async () => {
|
||||||
mockStockService.StockCurrentStock.mockReturnValue(
|
mockStockService.StockCurrentStock.mockReturnValue(
|
||||||
of({ error: false, result: undefined }),
|
of({ error: false, result: undefined }),
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(service.fetchAssignedStock()).rejects.toThrow(
|
await expect(service.fetchAssignedStock()).rejects.toThrow(
|
||||||
ResponseArgsError,
|
'Assigned stock has no ID',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -196,16 +196,17 @@ describe('RemissionStockService', () => {
|
|||||||
expect(mockStockService.StockInStock).toHaveBeenCalled();
|
expect(mockStockService.StockInStock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw ResponseArgsError when API returns no result', async () => {
|
it('should return empty array when API returns no result', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
mockStockService.StockInStock.mockReturnValue(
|
mockStockService.StockInStock.mockReturnValue(
|
||||||
of({ error: false, result: undefined }),
|
of({ error: false, result: undefined }),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Act & Assert
|
// Act
|
||||||
await expect(service.fetchStockInfos(validParams)).rejects.toThrow(
|
const result = await service.fetchStockInfos(validParams);
|
||||||
ResponseArgsError,
|
|
||||||
);
|
// Assert
|
||||||
|
expect(result).toBe(undefined);
|
||||||
expect(mockStockService.StockInStock).toHaveBeenCalled();
|
expect(mockStockService.StockInStock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ import { StockService } from '@generated/swagger/inventory-api';
|
|||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { Stock, StockInfo } from '../models';
|
import { Stock, StockInfo } from '../models';
|
||||||
import { FetchStockInStock, FetchStockInStockSchema } from '../schemas';
|
import { FetchStockInStock, FetchStockInStockSchema } from '../schemas';
|
||||||
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
import {
|
||||||
|
catchResponseArgsErrorPipe,
|
||||||
|
takeUntilAborted,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
import { logger } from '@isa/core/logging';
|
import { logger } from '@isa/core/logging';
|
||||||
import { InFlight, Cache, CacheTimeToLive } from '@isa/common/decorators';
|
import { InFlight, Cache, CacheTimeToLive } from '@isa/common/decorators';
|
||||||
|
|
||||||
@@ -56,73 +59,74 @@ export class RemissionStockService {
|
|||||||
@InFlight()
|
@InFlight()
|
||||||
async fetchAssignedStock(abortSignal?: AbortSignal): Promise<Stock> {
|
async fetchAssignedStock(abortSignal?: AbortSignal): Promise<Stock> {
|
||||||
this.#logger.info('Fetching assigned stock from API');
|
this.#logger.info('Fetching assigned stock from API');
|
||||||
let req$ = this.#stockService.StockCurrentStock();
|
let req$ = this.#stockService
|
||||||
|
.StockCurrentStock()
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
this.#logger.debug('Request configured with abort signal');
|
this.#logger.debug('Request configured with abort signal');
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
const result = res.result;
|
||||||
|
if (result?.id === undefined) {
|
||||||
|
const error = new Error('Assigned stock has no ID');
|
||||||
|
this.#logger.error('Invalid stock response', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
if (res.error || !res.result) {
|
this.#logger.debug('Successfully fetched assigned stock', () => ({
|
||||||
this.#logger.error(
|
stockId: result.id,
|
||||||
'Failed to fetch assigned stock',
|
}));
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = res.result;
|
// TypeScript cannot narrow StockDTO to Stock based on the id check above,
|
||||||
if (result.id === undefined) {
|
// so we use a minimal type assertion after runtime validation
|
||||||
const error = new Error('Assigned stock has no ID');
|
return result as Stock;
|
||||||
this.#logger.error('Invalid stock response', error);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch assigned stock', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.debug('Successfully fetched assigned stock', () => ({
|
|
||||||
stockId: result.id,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// TypeScript cannot narrow StockDTO to Stock based on the id check above,
|
|
||||||
// so we use a minimal type assertion after runtime validation
|
|
||||||
return result as Stock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchStock(
|
async fetchStock(
|
||||||
branchId: number,
|
branchId: number,
|
||||||
abortSignal?: AbortSignal,
|
abortSignal?: AbortSignal,
|
||||||
): Promise<Stock | undefined> {
|
): Promise<Stock | undefined> {
|
||||||
let req$ = this.#stockService.StockGetStocks();
|
let req$ = this.#stockService
|
||||||
|
.StockGetStocks()
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
this.#logger.debug('Request configured with abort signal');
|
this.#logger.debug('Request configured with abort signal');
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error || !res.result) {
|
const stock = res.result?.find((s) => s.branch?.id === branchId);
|
||||||
this.#logger.error(
|
if (!stock) {
|
||||||
'Failed to fetch stocks',
|
return undefined;
|
||||||
new Error(res.message || 'Unknown error'),
|
}
|
||||||
);
|
|
||||||
throw new ResponseArgsError(res);
|
if (stock.id === undefined) {
|
||||||
|
this.#logger.warn('Found stock without ID for branch', () => ({
|
||||||
|
branchId,
|
||||||
|
}));
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeScript cannot narrow StockDTO to Stock based on the id check above,
|
||||||
|
// so we use a minimal type assertion after runtime validation
|
||||||
|
return stock as Stock;
|
||||||
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch stock', error, () => ({
|
||||||
|
branchId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stock = res.result.find((s) => s.branch?.id === branchId);
|
|
||||||
if (!stock) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stock.id === undefined) {
|
|
||||||
this.#logger.warn('Found stock without ID for branch', () => ({ branchId }));
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeScript cannot narrow StockDTO to Stock based on the id check above,
|
|
||||||
// so we use a minimal type assertion after runtime validation
|
|
||||||
return stock as Stock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -179,30 +183,31 @@ export class RemissionStockService {
|
|||||||
itemCount: parsed.itemIds.length,
|
itemCount: parsed.itemIds.length,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let req$ = this.#stockService.StockInStock({
|
let req$ = this.#stockService
|
||||||
stockId: assignedStockId,
|
.StockInStock({
|
||||||
articleIds: parsed.itemIds,
|
stockId: assignedStockId,
|
||||||
});
|
articleIds: parsed.itemIds,
|
||||||
|
})
|
||||||
|
.pipe(catchResponseArgsErrorPipe());
|
||||||
|
|
||||||
if (abortSignal) {
|
if (abortSignal) {
|
||||||
this.#logger.debug('Request configured with abort signal');
|
this.#logger.debug('Request configured with abort signal');
|
||||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
try {
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error || !res.result) {
|
this.#logger.debug('Successfully fetched stock info', () => ({
|
||||||
this.#logger.error(
|
itemCount: res.result?.length || 0,
|
||||||
'Failed to fetch stock info',
|
}));
|
||||||
new Error(res.message || 'Unknown error'),
|
|
||||||
);
|
return res.result as StockInfo[];
|
||||||
throw new ResponseArgsError(res);
|
} catch (error) {
|
||||||
|
this.#logger.error('Failed to fetch stock info', error, () => ({
|
||||||
|
stockId: assignedStockId,
|
||||||
|
}));
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#logger.debug('Successfully fetched stock info', () => ({
|
|
||||||
itemCount: res.result?.length || 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return res.result as StockInfo[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user