mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
feat(checkout): add reward order confirmation feature with schema migrations
- Add new reward-order-confirmation feature library with components and store - Implement checkout completion orchestrator service for order finalization - Migrate checkout/oms/crm models to Zod schemas for better type safety - Add order creation facade and display order schemas - Update shopping cart facade with order completion flow - Add comprehensive tests for shopping cart facade - Update routing to include order confirmation page
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,4 +3,5 @@ export * from './lib/constants';
|
||||
export * from './lib/models';
|
||||
export * from './lib/resources';
|
||||
export * from './lib/helpers';
|
||||
export * from './lib/schemas';
|
||||
export * from './lib/services';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { CrmSearchService } from '../services/crm-search.service';
|
||||
import { FetchCustomerInput } from '../schemas';
|
||||
import { Customer } from '../models';
|
||||
import { FetchCustomerInput, Customer } from '../schemas';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CustomerFacade {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { AssignedPayerDTO } from '@generated/swagger/crm-api';
|
||||
import { Payer } from './payer';
|
||||
import { EntityContainer } from '@isa/common/data-access';
|
||||
|
||||
export type AssignedPayer = AssignedPayerDTO & {
|
||||
payer: EntityContainer<Payer>;
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
import { CustomerDTO } from '@generated/swagger/crm-api';
|
||||
import { CustomerType } from './customer-type';
|
||||
import { AssignedPayer } from './assigned-payer';
|
||||
|
||||
export interface Customer extends CustomerDTO {
|
||||
customerType: CustomerType;
|
||||
payers: Array<AssignedPayer>;
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
export * from './assigned-payer';
|
||||
export * from './bonus-card-info.model';
|
||||
export * from './country';
|
||||
export * from './customer-type';
|
||||
export * from './customer.model';
|
||||
export * from './payer';
|
||||
export * from './shipping-address.model';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { ShippingAddressDTO } from '@generated/swagger/crm-api';
|
||||
|
||||
export type ShippingAddress = ShippingAddressDTO;
|
||||
@@ -1,54 +1,57 @@
|
||||
import { effect, inject, Injectable, resource, signal } from '@angular/core';
|
||||
import { CrmTabMetadataService, ShippingAddressService } from '../services';
|
||||
import { TabService } from '@isa/core/tabs';
|
||||
import { ShippingAddress } from '../models';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerShippingAddressResource {
|
||||
#shippingAddressService = inject(ShippingAddressService);
|
||||
|
||||
#params = signal<{
|
||||
shippingAddressId: number | undefined;
|
||||
}>({
|
||||
shippingAddressId: undefined,
|
||||
});
|
||||
|
||||
params(params: { shippingAddressId?: number }) {
|
||||
this.#params.update((p) => ({ ...p, ...params }));
|
||||
}
|
||||
|
||||
readonly resource = resource({
|
||||
params: () => this.#params(),
|
||||
loader: async ({ params, abortSignal }): Promise<ShippingAddress | undefined> => {
|
||||
if (!params.shippingAddressId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const res = await this.#shippingAddressService.fetchShippingAddress(
|
||||
{
|
||||
shippingAddressId: params.shippingAddressId,
|
||||
},
|
||||
abortSignal,
|
||||
);
|
||||
|
||||
return res.result as ShippingAddress;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SelectedCustomerShippingAddressResource extends CustomerShippingAddressResource {
|
||||
#tabId = inject(TabService).activatedTabId;
|
||||
#customerMetadata = inject(CrmTabMetadataService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
effect(() => {
|
||||
const tabId = this.#tabId();
|
||||
const shippingAddressId = tabId
|
||||
? this.#customerMetadata.selectedShippingAddressId(tabId)
|
||||
: undefined;
|
||||
this.params({ shippingAddressId });
|
||||
});
|
||||
}
|
||||
}
|
||||
import { effect, inject, Injectable, resource, signal } from '@angular/core';
|
||||
import { CrmTabMetadataService, ShippingAddressService } from '../services';
|
||||
import { TabService } from '@isa/core/tabs';
|
||||
import { ShippingAddress } from '../schemas';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerShippingAddressResource {
|
||||
#shippingAddressService = inject(ShippingAddressService);
|
||||
|
||||
#params = signal<{
|
||||
shippingAddressId: number | undefined;
|
||||
}>({
|
||||
shippingAddressId: undefined,
|
||||
});
|
||||
|
||||
params(params: { shippingAddressId?: number }) {
|
||||
this.#params.update((p) => ({ ...p, ...params }));
|
||||
}
|
||||
|
||||
readonly resource = resource({
|
||||
params: () => this.#params(),
|
||||
loader: async ({
|
||||
params,
|
||||
abortSignal,
|
||||
}): Promise<ShippingAddress | undefined> => {
|
||||
if (!params.shippingAddressId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const res = await this.#shippingAddressService.fetchShippingAddress(
|
||||
{
|
||||
shippingAddressId: params.shippingAddressId,
|
||||
},
|
||||
abortSignal,
|
||||
);
|
||||
|
||||
return res.result as ShippingAddress;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SelectedCustomerShippingAddressResource extends CustomerShippingAddressResource {
|
||||
#tabId = inject(TabService).activatedTabId;
|
||||
#customerMetadata = inject(CrmTabMetadataService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
effect(() => {
|
||||
const tabId = this.#tabId();
|
||||
const shippingAddressId = tabId
|
||||
? this.#customerMetadata.selectedShippingAddressId(tabId)
|
||||
: undefined;
|
||||
this.params({ shippingAddressId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,58 +1,66 @@
|
||||
import { effect, inject, Injectable, resource, signal } from '@angular/core';
|
||||
import { CrmTabMetadataService, ShippingAddressService } from '../services';
|
||||
import { TabService } from '@isa/core/tabs';
|
||||
import { ShippingAddress } from '../models';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerShippingAddressesResource {
|
||||
#shippingAddressService = inject(ShippingAddressService);
|
||||
|
||||
#params = signal<{
|
||||
customerId: number | undefined;
|
||||
take?: number | null;
|
||||
skip?: number | null;
|
||||
}>({
|
||||
customerId: undefined,
|
||||
});
|
||||
|
||||
params(params: { customerId?: number; take?: number | null; skip?: number | null }) {
|
||||
this.#params.update((p) => ({ ...p, ...params }));
|
||||
}
|
||||
|
||||
readonly resource = resource({
|
||||
params: () => this.#params(),
|
||||
loader: async ({ params, abortSignal }): Promise<ShippingAddress[] | undefined> => {
|
||||
if (!params.customerId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const res = await this.#shippingAddressService.fetchCustomerShippingAddresses(
|
||||
{
|
||||
customerId: params.customerId,
|
||||
take: params.take,
|
||||
skip: params.skip,
|
||||
},
|
||||
abortSignal,
|
||||
);
|
||||
|
||||
return res.result as ShippingAddress[];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SelectedCustomerShippingAddressesResource extends CustomerShippingAddressesResource {
|
||||
#tabId = inject(TabService).activatedTabId;
|
||||
#customerMetadata = inject(CrmTabMetadataService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
effect(() => {
|
||||
const tabId = this.#tabId();
|
||||
const customerId = tabId
|
||||
? this.#customerMetadata.selectedCustomerId(tabId)
|
||||
: undefined;
|
||||
this.params({ customerId });
|
||||
});
|
||||
}
|
||||
}
|
||||
import { effect, inject, Injectable, resource, signal } from '@angular/core';
|
||||
import { CrmTabMetadataService, ShippingAddressService } from '../services';
|
||||
import { TabService } from '@isa/core/tabs';
|
||||
import { ShippingAddress } from '../schemas';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerShippingAddressesResource {
|
||||
#shippingAddressService = inject(ShippingAddressService);
|
||||
|
||||
#params = signal<{
|
||||
customerId: number | undefined;
|
||||
take?: number | null;
|
||||
skip?: number | null;
|
||||
}>({
|
||||
customerId: undefined,
|
||||
});
|
||||
|
||||
params(params: {
|
||||
customerId?: number;
|
||||
take?: number | null;
|
||||
skip?: number | null;
|
||||
}) {
|
||||
this.#params.update((p) => ({ ...p, ...params }));
|
||||
}
|
||||
|
||||
readonly resource = resource({
|
||||
params: () => this.#params(),
|
||||
loader: async ({
|
||||
params,
|
||||
abortSignal,
|
||||
}): Promise<ShippingAddress[] | undefined> => {
|
||||
if (!params.customerId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const res =
|
||||
await this.#shippingAddressService.fetchCustomerShippingAddresses(
|
||||
{
|
||||
customerId: params.customerId,
|
||||
take: params.take,
|
||||
skip: params.skip,
|
||||
},
|
||||
abortSignal,
|
||||
);
|
||||
|
||||
return res.result as ShippingAddress[];
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SelectedCustomerShippingAddressesResource extends CustomerShippingAddressesResource {
|
||||
#tabId = inject(TabService).activatedTabId;
|
||||
#customerMetadata = inject(CrmTabMetadataService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
effect(() => {
|
||||
const tabId = this.#tabId();
|
||||
const customerId = tabId
|
||||
? this.#customerMetadata.selectedCustomerId(tabId)
|
||||
: undefined;
|
||||
this.params({ customerId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { effect, inject, Injectable, resource, signal } from '@angular/core';
|
||||
import { CrmSearchService, CrmTabMetadataService } from '../services';
|
||||
import { TabService } from '@isa/core/tabs';
|
||||
import { Customer } from '../models';
|
||||
import { Customer } from '../schemas';
|
||||
|
||||
@Injectable()
|
||||
export class CustomerResource {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { EntityContainerSchema } from '@isa/common/data-access';
|
||||
import { z } from 'zod';
|
||||
import { PayerSchema } from './payer.schema';
|
||||
|
||||
export const AssignedPayerSchema = z.object({
|
||||
assignedToCustomer: z.string().describe('Assigned to customer').optional(),
|
||||
isDefault: z.string().describe('Whether this is the default').optional(),
|
||||
payer: EntityContainerSchema(PayerSchema).describe('Payer information').optional(),
|
||||
});
|
||||
|
||||
export type AssignedPayer = z.infer<typeof AssignedPayerSchema>;
|
||||
19
libs/crm/data-access/src/lib/schemas/attribute.schema.ts
Normal file
19
libs/crm/data-access/src/lib/schemas/attribute.schema.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Schema for AttributeDTO
|
||||
* Represents attribute data with date fields as strings (ISO format)
|
||||
*
|
||||
* Note: The API returns start/stop as string (not Date objects).
|
||||
* If date parsing is needed, use z.coerce.date() or parse in application logic.
|
||||
*/
|
||||
export const AttributeSchema = z.object({
|
||||
dataType: z.number().describe('Data type'),
|
||||
formatValidator: z.string().describe('Format validator').optional(),
|
||||
group: z.string().describe('Group').optional(),
|
||||
key: z.string().describe('Key'),
|
||||
name: z.string().describe('Name').optional(),
|
||||
start: z.string().describe('Start').optional(),
|
||||
stop: z.string().describe('Stop').optional(),
|
||||
value: z.string().describe('Value').optional(),
|
||||
});
|
||||
22
libs/crm/data-access/src/lib/schemas/bonus-card.schema.ts
Normal file
22
libs/crm/data-access/src/lib/schemas/bonus-card.schema.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { EntitySchema } from '@isa/common/data-access';
|
||||
import { z } from 'zod';
|
||||
|
||||
/**
|
||||
* Schema for BonusCardDTO
|
||||
* Represents bonus card information with proper type matching
|
||||
*
|
||||
* Note: cardProvider is a number in the API, and dates are returned as strings
|
||||
*/
|
||||
export const BonusCardSchema = z
|
||||
.object({
|
||||
bonusValue: z.number().describe('Bonus value').optional(),
|
||||
cardNumber: z.string().describe('Card number').optional(),
|
||||
cardProvider: z.number().describe('Card provider').optional(),
|
||||
isLocked: z.boolean().describe('Whether locked').optional(),
|
||||
isPaymentEnabled: z.boolean().describe('Whether paymentEnabled').optional(),
|
||||
markedAsLost: z.string().describe('Marked as lost').optional(),
|
||||
suspensionComment: z.string().describe('Suspension comment').optional(),
|
||||
validFrom: z.string().describe('Validity start date').optional(),
|
||||
validThrough: z.string().describe('Valid through').optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
21
libs/crm/data-access/src/lib/schemas/branch.schema.ts
Normal file
21
libs/crm/data-access/src/lib/schemas/branch.schema.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import {
|
||||
AddressSchema,
|
||||
EntityContainerSchema,
|
||||
EntitySchema,
|
||||
LabelSchema,
|
||||
} from '@isa/common/data-access';
|
||||
import { number, z } from 'zod';
|
||||
|
||||
export const BranchSchema = z
|
||||
.object({
|
||||
address: AddressSchema.describe('Address').optional(),
|
||||
banchNumber: z.string().describe('Banch number').optional(),
|
||||
branchType: z.number().describe('Branch type'),
|
||||
isOnline: z.boolean().describe('Whether online').optional(),
|
||||
key: z.string().describe('Key').optional(),
|
||||
label: EntityContainerSchema(LabelSchema).describe('Label').optional(),
|
||||
name: z.string().describe('Name').optional(),
|
||||
parent: z.number().describe('Parent').optional(),
|
||||
shortName: z.string().describe('Short name').optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
96
libs/crm/data-access/src/lib/schemas/customer.schema.ts
Normal file
96
libs/crm/data-access/src/lib/schemas/customer.schema.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import {
|
||||
AddressSchema,
|
||||
CommunicationDetailsSchema,
|
||||
EntityContainerSchema,
|
||||
EntitySchema,
|
||||
GenderSchema,
|
||||
KeyValueOfStringAndStringSchema,
|
||||
LabelSchema,
|
||||
NotificationChannelSchema,
|
||||
OrganisationSchema,
|
||||
} from '@isa/common/data-access';
|
||||
import { z } from 'zod';
|
||||
import { CustomerType } from '../models';
|
||||
import { AssignedPayerSchema } from './assigned-payer.schema';
|
||||
import { AttributeSchema } from './attribute.schema';
|
||||
import { BonusCardSchema } from './bonus-card.schema';
|
||||
import { BranchSchema } from './branch.schema';
|
||||
import { LinkedRecordSchema } from './linked-record.schema';
|
||||
import { ShippingAddressSchema } from './shipping-address.schema';
|
||||
import { UserSchema } from './user.schema';
|
||||
|
||||
export const CustomerSchema = z
|
||||
.object({
|
||||
address: AddressSchema.describe('Address').optional(),
|
||||
agentComment: z.string().describe('Agent comment').optional(),
|
||||
attributes: z
|
||||
.array(EntityContainerSchema(AttributeSchema))
|
||||
.describe('Attribute list')
|
||||
.optional(),
|
||||
bonusCard: EntityContainerSchema(BonusCardSchema)
|
||||
.describe('Bonus card information')
|
||||
.optional(),
|
||||
campaignCode: z.string().describe('Campaign code').optional(),
|
||||
clientChannel: z.number().describe('Client channel').optional(),
|
||||
communicationDetails: CommunicationDetailsSchema.describe(
|
||||
'Communication details',
|
||||
).optional(),
|
||||
createdInBranch: EntityContainerSchema(BranchSchema)
|
||||
.describe('Created in branch')
|
||||
.optional(),
|
||||
customerGroup: z.string().describe('Customer group').optional(),
|
||||
customerNumber: z.string().describe('Customer number').optional(),
|
||||
customerStatus: z.number().describe('Customer status').optional(),
|
||||
customerType: z.nativeEnum(CustomerType).describe('Customer type'),
|
||||
dateOfBirth: z.string().describe('Date of birth').optional(),
|
||||
deactivationComment: z.string().describe('Deactivation comment').optional(),
|
||||
features: z
|
||||
.array(KeyValueOfStringAndStringSchema)
|
||||
.describe('Features')
|
||||
.optional(),
|
||||
fetchOnDeliveryNote: z
|
||||
.boolean()
|
||||
.describe('Fetch on delivery note')
|
||||
.optional(),
|
||||
firstName: z.string().describe('First name').optional(),
|
||||
gender: GenderSchema.describe('Gender').optional(),
|
||||
hasOnlineAccount: z
|
||||
.boolean()
|
||||
.describe('Whether has onlineAccount')
|
||||
.optional(),
|
||||
isGuestAccount: z.boolean().describe('Whether guestAccount').optional(),
|
||||
label: EntityContainerSchema(LabelSchema).describe('Label').optional(),
|
||||
lastName: z.string().describe('Last name').optional(),
|
||||
linkedRecords: z
|
||||
.array(LinkedRecordSchema)
|
||||
.describe('List of linked records')
|
||||
.optional(),
|
||||
notificationChannels: NotificationChannelSchema.describe(
|
||||
'Notification channels',
|
||||
).optional(),
|
||||
orderCount: z.number().describe('Number of orders').optional(),
|
||||
organisation: OrganisationSchema.describe(
|
||||
'Organisation information',
|
||||
).optional(),
|
||||
payers: z.array(AssignedPayerSchema).describe('Payers').optional(),
|
||||
preferredPaymentType: z
|
||||
.number()
|
||||
.describe('PreferredPayment type')
|
||||
.optional(),
|
||||
shippingAddresses: z
|
||||
.array(EntityContainerSchema(ShippingAddressSchema))
|
||||
.describe('Shipping addresses')
|
||||
.optional(),
|
||||
statusChangeComment: z
|
||||
.string()
|
||||
.describe('Status change comment')
|
||||
.optional(),
|
||||
statusComment: z.string().describe('Status comment').optional(),
|
||||
title: z.string().describe('Title').optional(),
|
||||
user: EntityContainerSchema(UserSchema)
|
||||
.describe('User information')
|
||||
.optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
|
||||
export type Customer = z.infer<typeof CustomerSchema>;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const FetchCustomerCardsSchema = z.object({
|
||||
customerId: z.number().int(),
|
||||
customerId: z.number().int().describe('Unique customer identifier'),
|
||||
});
|
||||
|
||||
export type FetchCustomerCards = z.infer<typeof FetchCustomerCardsSchema>;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const FetchCustomerShippingAddressesSchema = z.object({
|
||||
customerId: z.number().int(),
|
||||
take: z.number().int().optional().nullable(),
|
||||
skip: z.number().int().optional().nullable(),
|
||||
customerId: z.number().int().describe('Unique customer identifier'),
|
||||
take: z.number().int().optional().describe('Number of items to return per page').nullable(),
|
||||
skip: z.number().int().optional().describe('Number of items to skip for pagination').nullable(),
|
||||
});
|
||||
|
||||
export type FetchCustomerShippingAddresses = z.infer<typeof FetchCustomerShippingAddressesSchema>;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const FetchCustomerSchema = z.object({
|
||||
customerId: z.number().int(),
|
||||
eagerLoading: z.number().optional(),
|
||||
customerId: z.number().int().describe('Unique customer identifier'),
|
||||
eagerLoading: z.number().describe('Eager loading').optional(),
|
||||
});
|
||||
|
||||
export type FetchCustomer = z.infer<typeof FetchCustomerSchema>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const FetchShippingAddressSchema = z.object({
|
||||
shippingAddressId: z.number().int(),
|
||||
shippingAddressId: z.number().int().describe('ShippingAddress identifier'),
|
||||
});
|
||||
|
||||
export type FetchShippingAddress = z.infer<typeof FetchShippingAddressSchema>;
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
export * from './fetch-customer-cards.schema';
|
||||
export * from './fetch-customer-shipping-addresses.schema';
|
||||
export * from './fetch-customer.schema';
|
||||
export * from './fetch-shipping-address.schema';
|
||||
export * from './assigned-payer.schema';
|
||||
export * from './attribute.schema';
|
||||
export * from './bonus-card.schema';
|
||||
export * from './branch.schema';
|
||||
export * from './customer.schema';
|
||||
export * from './fetch-customer-cards.schema';
|
||||
export * from './fetch-customer-shipping-addresses.schema';
|
||||
export * from './fetch-customer.schema';
|
||||
export * from './fetch-shipping-address.schema';
|
||||
export * from './linked-record.schema';
|
||||
export * from './notification-channel.schema';
|
||||
export * from './payer-status.schema';
|
||||
export * from './payer.schema';
|
||||
export * from './payment-settings.schema';
|
||||
export * from './shipping-address.schema';
|
||||
export * from './user.schema';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const LinkedRecordSchema = z.object({
|
||||
isSource: z.boolean().describe('Whether source').optional(),
|
||||
number: z.string().describe('Number').optional(),
|
||||
pk: z.string().describe('Pk').optional(),
|
||||
repository: z.string().describe('Repository').optional(),
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @deprecated This schema has been moved to @isa/common/data-access.
|
||||
* Please update imports to use:
|
||||
* import { NotificationChannelSchema, NotificationChannel } from '@isa/common/data-access';
|
||||
*
|
||||
* This re-export will be removed in a future version.
|
||||
*/
|
||||
export {
|
||||
NotificationChannelSchema,
|
||||
NotificationChannel,
|
||||
} from '@isa/common/data-access';
|
||||
14
libs/crm/data-access/src/lib/schemas/payer-status.schema.ts
Normal file
14
libs/crm/data-access/src/lib/schemas/payer-status.schema.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PayerStatus = {
|
||||
NotSet: 0,
|
||||
Blocked: 1,
|
||||
Check: 2,
|
||||
LowDegreeOfCreditworthiness: 4,
|
||||
Dunning1: 8,
|
||||
Dunning2: 16,
|
||||
} as const;
|
||||
|
||||
export const PayerStatusSchema = z.nativeEnum(PayerStatus).describe('Payer status');
|
||||
|
||||
export type PayerStatus = z.infer<typeof PayerStatusSchema>;
|
||||
38
libs/crm/data-access/src/lib/schemas/payer.schema.ts
Normal file
38
libs/crm/data-access/src/lib/schemas/payer.schema.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
AddressSchema,
|
||||
CommunicationDetailsSchema,
|
||||
EntityContainerSchema,
|
||||
EntitySchema,
|
||||
GenderSchema,
|
||||
LabelSchema,
|
||||
OrganisationSchema,
|
||||
PayerType,
|
||||
} from '@isa/common/data-access';
|
||||
import { z } from 'zod';
|
||||
import { PayerStatusSchema } from './payer-status.schema';
|
||||
import { PaymentSettingsSchema } from './payment-settings.schema';
|
||||
|
||||
export const PayerSchema = z
|
||||
.object({
|
||||
address: AddressSchema.describe('Address').optional(),
|
||||
agentComment: z.string().describe('Agent comment').optional(),
|
||||
communicationDetails: CommunicationDetailsSchema.describe('Communication details').optional(),
|
||||
deactivationComment: z.string().describe('Deactivation comment').optional(),
|
||||
defaultPaymentPeriod: z.number().describe('Default payment period').optional(),
|
||||
firstName: z.string().describe('First name').optional(),
|
||||
gender: GenderSchema.describe('Gender').optional(),
|
||||
isGuestAccount: z.boolean().describe('Whether guestAccount').optional(),
|
||||
label: EntityContainerSchema(LabelSchema).describe('Label').optional(),
|
||||
lastName: z.string().describe('Last name').optional(),
|
||||
organisation: OrganisationSchema.describe('Organisation information').optional(),
|
||||
payerGroup: z.string().describe('Payer group').optional(),
|
||||
payerNumber: z.string().describe('Unique payer account number').optional(),
|
||||
payerStatus: PayerStatusSchema.describe('Current status of the payer account').optional(),
|
||||
payerType: z.nativeEnum(PayerType).describe('Payer type').optional(),
|
||||
paymentTypes: z.array(PaymentSettingsSchema).describe('Payment types').optional(),
|
||||
standardInvoiceText: z.string().describe('Standard invoice text').optional(),
|
||||
statusChangeComment: z.string().describe('Status change comment').optional(),
|
||||
statusComment: z.string().describe('Status comment').optional(),
|
||||
title: z.string().describe('Title').optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
@@ -0,0 +1,9 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PaymentSettingsSchema = z.object({
|
||||
allow: z.string().describe('Allow').optional(),
|
||||
channel: z.string().describe('Communication channel').optional(),
|
||||
denaiedReason: z.string().describe('Denaied reason').optional(),
|
||||
deny: z.string().describe('Deny').optional(),
|
||||
paymentType: z.number().int().positive().describe('Payment type').optional(),
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import {
|
||||
AddressSchema,
|
||||
CommunicationDetailsSchema,
|
||||
EntitySchema,
|
||||
GenderSchema,
|
||||
OrganisationSchema,
|
||||
} from '@isa/common/data-access';
|
||||
import z from 'zod';
|
||||
|
||||
export const ShippingAddressSchema = z
|
||||
.object({
|
||||
address: AddressSchema.describe('Address').optional(),
|
||||
agentomment: z.string().describe('Agentomment').optional(),
|
||||
communicationDetails: CommunicationDetailsSchema.describe('Communication details').optional(),
|
||||
firstName: z.string().describe('First name').optional(),
|
||||
gender: GenderSchema.describe('Gender').optional(),
|
||||
lastName: z.string().describe('Last name').optional(),
|
||||
organisation: OrganisationSchema.describe('Organisation information').optional(),
|
||||
title: z.string().describe('Title').optional(),
|
||||
type: z.number().describe('Type').optional(),
|
||||
validated: z.string().describe('Validated').optional(),
|
||||
validationResult: z.number().describe('Validation result').optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
|
||||
export type ShippingAddress = z.infer<typeof ShippingAddressSchema>;
|
||||
13
libs/crm/data-access/src/lib/schemas/user.schema.ts
Normal file
13
libs/crm/data-access/src/lib/schemas/user.schema.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { EntitySchema, GenderSchema } from '@isa/common/data-access';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const UserSchema = z
|
||||
.object({
|
||||
email: z.string().email().describe('Email address').optional(),
|
||||
firstName: z.string().describe('First name').optional(),
|
||||
gender: GenderSchema.describe('Gender').optional(),
|
||||
lastName: z.string().describe('Last name').optional(),
|
||||
name: z.string().describe('Name').optional(),
|
||||
title: z.string().describe('Title').optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
@@ -1,6 +1,7 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { CustomerService } from '@generated/swagger/crm-api';
|
||||
import {
|
||||
Customer,
|
||||
FetchCustomerCardsInput,
|
||||
FetchCustomerCardsSchema,
|
||||
FetchCustomerInput,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
takeUntilAborted,
|
||||
} from '@isa/common/data-access';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { BonusCardInfo, Customer } from '../models';
|
||||
import { BonusCardInfo } from '../models';
|
||||
import { logger } from '@isa/core/logging';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
|
||||
@@ -1,79 +1,79 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { ShippingAddressService as GeneratedShippingAddressService } from '@generated/swagger/crm-api';
|
||||
import {
|
||||
FetchCustomerShippingAddressesInput,
|
||||
FetchCustomerShippingAddressesSchema,
|
||||
FetchShippingAddressInput,
|
||||
FetchShippingAddressSchema,
|
||||
} from '../schemas';
|
||||
import {
|
||||
catchResponseArgsErrorPipe,
|
||||
ListResponseArgs,
|
||||
ResponseArgs,
|
||||
takeUntilAborted,
|
||||
} from '@isa/common/data-access';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { ShippingAddress } from '../models';
|
||||
import { logger } from '@isa/core/logging';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ShippingAddressService {
|
||||
#shippingAddressService = inject(GeneratedShippingAddressService);
|
||||
#logger = logger(() => ({
|
||||
service: 'ShippingAddressService',
|
||||
}));
|
||||
|
||||
async fetchCustomerShippingAddresses(
|
||||
params: FetchCustomerShippingAddressesInput,
|
||||
abortSignal?: AbortSignal,
|
||||
): Promise<ListResponseArgs<ShippingAddress>> {
|
||||
this.#logger.info('Fetching customer shipping addresses from API');
|
||||
const { customerId, take, skip } =
|
||||
FetchCustomerShippingAddressesSchema.parse(params);
|
||||
|
||||
let req$ = this.#shippingAddressService
|
||||
.ShippingAddressGetShippingAddresses({ customerId, take, skip })
|
||||
.pipe(catchResponseArgsErrorPipe());
|
||||
|
||||
if (abortSignal) {
|
||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await firstValueFrom(req$);
|
||||
this.#logger.debug('Successfully fetched customer shipping addresses');
|
||||
return res as ListResponseArgs<ShippingAddress>;
|
||||
} catch (error) {
|
||||
this.#logger.error('Error fetching customer shipping addresses', error);
|
||||
return {
|
||||
result: [],
|
||||
totalCount: 0,
|
||||
} as unknown as ListResponseArgs<ShippingAddress>;
|
||||
}
|
||||
}
|
||||
|
||||
async fetchShippingAddress(
|
||||
params: FetchShippingAddressInput,
|
||||
abortSignal?: AbortSignal,
|
||||
): Promise<ResponseArgs<ShippingAddress>> {
|
||||
this.#logger.info('Fetching shipping address from API');
|
||||
const { shippingAddressId } = FetchShippingAddressSchema.parse(params);
|
||||
|
||||
let req$ = this.#shippingAddressService
|
||||
.ShippingAddressGetShippingaddress(shippingAddressId)
|
||||
.pipe(catchResponseArgsErrorPipe());
|
||||
|
||||
if (abortSignal) {
|
||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await firstValueFrom(req$);
|
||||
this.#logger.debug('Successfully fetched shipping address');
|
||||
return res as ResponseArgs<ShippingAddress>;
|
||||
} catch (error) {
|
||||
this.#logger.error('Error fetching shipping address', error);
|
||||
return undefined as unknown as ResponseArgs<ShippingAddress>;
|
||||
}
|
||||
}
|
||||
}
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { ShippingAddressService as GeneratedShippingAddressService } from '@generated/swagger/crm-api';
|
||||
import {
|
||||
FetchCustomerShippingAddressesInput,
|
||||
FetchCustomerShippingAddressesSchema,
|
||||
FetchShippingAddressInput,
|
||||
FetchShippingAddressSchema,
|
||||
ShippingAddress,
|
||||
} from '../schemas';
|
||||
import {
|
||||
catchResponseArgsErrorPipe,
|
||||
ListResponseArgs,
|
||||
ResponseArgs,
|
||||
takeUntilAborted,
|
||||
} from '@isa/common/data-access';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { logger } from '@isa/core/logging';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ShippingAddressService {
|
||||
#shippingAddressService = inject(GeneratedShippingAddressService);
|
||||
#logger = logger(() => ({
|
||||
service: 'ShippingAddressService',
|
||||
}));
|
||||
|
||||
async fetchCustomerShippingAddresses(
|
||||
params: FetchCustomerShippingAddressesInput,
|
||||
abortSignal?: AbortSignal,
|
||||
): Promise<ListResponseArgs<ShippingAddress>> {
|
||||
this.#logger.info('Fetching customer shipping addresses from API');
|
||||
const { customerId, take, skip } =
|
||||
FetchCustomerShippingAddressesSchema.parse(params);
|
||||
|
||||
let req$ = this.#shippingAddressService
|
||||
.ShippingAddressGetShippingAddresses({ customerId, take, skip })
|
||||
.pipe(catchResponseArgsErrorPipe());
|
||||
|
||||
if (abortSignal) {
|
||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await firstValueFrom(req$);
|
||||
this.#logger.debug('Successfully fetched customer shipping addresses');
|
||||
return res as ListResponseArgs<ShippingAddress>;
|
||||
} catch (error) {
|
||||
this.#logger.error('Error fetching customer shipping addresses', error);
|
||||
return {
|
||||
result: [],
|
||||
totalCount: 0,
|
||||
} as unknown as ListResponseArgs<ShippingAddress>;
|
||||
}
|
||||
}
|
||||
|
||||
async fetchShippingAddress(
|
||||
params: FetchShippingAddressInput,
|
||||
abortSignal?: AbortSignal,
|
||||
): Promise<ResponseArgs<ShippingAddress>> {
|
||||
this.#logger.info('Fetching shipping address from API');
|
||||
const { shippingAddressId } = FetchShippingAddressSchema.parse(params);
|
||||
|
||||
let req$ = this.#shippingAddressService
|
||||
.ShippingAddressGetShippingaddress(shippingAddressId)
|
||||
.pipe(catchResponseArgsErrorPipe());
|
||||
|
||||
if (abortSignal) {
|
||||
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await firstValueFrom(req$);
|
||||
this.#logger.debug('Successfully fetched shipping address');
|
||||
return res as ResponseArgs<ShippingAddress>;
|
||||
} catch (error) {
|
||||
this.#logger.error('Error fetching shipping address', error);
|
||||
return undefined as unknown as ResponseArgs<ShippingAddress>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user