Merged PR 2015: fix(crm-data-access, customer-details, reward-shopping-cart): persist selecte...

fix(crm-data-access, customer-details, reward-shopping-cart): persist selected addresses across navigation flows

Implement address selection persistence using CRM tab metadata to ensure
selected shipping addresses and payers are retained throughout the customer
selection flow, particularly when navigating from Kundenkarte to reward cart.

Changes include:
- Create PayerResource and CustomerPayerAddressResource to load selected
  payer from tab metadata with fallback to customer as payer
- Create PayerService to fetch payer data from CRM API with proper error
  handling and abort signal support
- Update BillingAndShippingAddressCardComponent to prefer selected addresses
  from metadata over customer defaults, with computed loading state
- Refactor continue() flow in CustomerDetailsViewMainComponent to load
  selected addresses from metadata before setting in checkout service
- Add adapter logic to convert CRM payer/shipping address types to checkout
  types with proper type casting for incompatible enum types
- Implement fallback chain: metadata selection → component state → customer
  default for both payer and shipping address

This ensures address selections made in the address selection dialogs are
properly preserved and applied when completing the customer selection flow,
fixing the issue where addresses would revert to customer defaults.

Ref: #5411
This commit is contained in:
Nino Righi
2025-11-10 15:10:56 +00:00
committed by Lorenz Hilpert
parent b984a2cac2
commit c3e9a03169
10 changed files with 309 additions and 20 deletions

View File

@@ -36,13 +36,21 @@ import { CrmCustomerService } from '@domain/crm';
import { MessageModalComponent, MessageModalData } from '@modal/message';
import { GenderSettingsService } from '@shared/services/gender';
import { toSignal } from '@angular/core/rxjs-interop';
import { CrmTabMetadataService, Customer } from '@isa/crm/data-access';
import { CustomerAdapter } from '@isa/checkout/data-access';
import {
CrmTabMetadataService,
Customer,
AssignedPayer,
} from '@isa/crm/data-access';
import {
CustomerAdapter,
ShippingAddressAdapter,
} from '@isa/checkout/data-access';
import {
NavigateAfterRewardSelection,
RewardSelectionPopUpService,
} from '@isa/checkout/shared/reward-selection-dialog';
import { NavigationStateService } from '@isa/core/navigation';
import { ShippingAddressDTO as CrmShippingAddressDTO } from '@generated/swagger/crm-api';
export interface CustomerDetailsViewMainState {
isBusy: boolean;
@@ -407,9 +415,9 @@ export class CustomerDetailsViewMainComponent
await this._updateNotifcationChannelsAsync(currentBuyer);
this._setPayer();
await this._setPayer();
this._setShippingAddress();
await this._setShippingAddress();
// #5262 Check for reward selection flow before navigation
if (this.hasReturnUrl()) {
@@ -631,8 +639,46 @@ export class CustomerDetailsViewMainComponent
}
}
@log
_setPayer() {
@logAsync
async _setPayer() {
// Check if there's a selected payer in metadata (from previous address selection)
const selectedPayerId = this.crmTabMetadataService.selectedPayerId(
this.processId,
);
if (selectedPayerId) {
// Load the selected payer from metadata
try {
const payerResponse = await this.customerService
.getPayer(selectedPayerId)
.toPromise();
if (payerResponse?.result) {
// Create AssignedPayer structure expected by adapter
// Type cast needed due to incompatible enum types between CRM and Checkout APIs
const assignedPayer = {
payer: {
id: selectedPayerId,
data: payerResponse.result,
},
} as AssignedPayer;
const payer = CustomerAdapter.toPayerFromAssignedPayer(assignedPayer);
if (payer) {
this._checkoutService.setPayer({
processId: this.processId,
payer,
});
return;
}
}
} catch (error) {
console.error('Failed to load selected payer from metadata', error);
}
}
// Fallback to current payer from component state
if (this.payer) {
this._checkoutService.setPayer({
processId: this.processId,
@@ -641,8 +687,41 @@ export class CustomerDetailsViewMainComponent
}
}
@log
_setShippingAddress() {
@logAsync
async _setShippingAddress() {
// Check if there's a selected shipping address in metadata (from previous address selection)
const selectedShippingAddressId =
this.crmTabMetadataService.selectedShippingAddressId(this.processId);
if (selectedShippingAddressId) {
// Load the selected shipping address from metadata
try {
const addressResponse = await this.customerService
.getShippingAddress(selectedShippingAddressId)
.toPromise();
if (addressResponse?.result) {
const shippingAddress = ShippingAddressAdapter.fromCrmShippingAddress(
addressResponse.result as CrmShippingAddressDTO,
);
if (shippingAddress) {
this._checkoutService.setShippingAddress({
processId: this.processId,
shippingAddress,
});
return;
}
}
} catch (error) {
console.error(
'Failed to load selected shipping address from metadata',
error,
);
}
}
// Fallback to current shipping address from component state
if (this.shippingAddress) {
this._checkoutService.setShippingAddress({
processId: this.processId,