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
@@ -1,10 +0,0 @@
|
||||
export const BuyerType = {
|
||||
NotSet: 0,
|
||||
ContactCustomer: 1,
|
||||
BranchCustomer: 2,
|
||||
Staff: 4,
|
||||
B2C: 8,
|
||||
B2B: 16,
|
||||
} as const;
|
||||
|
||||
export type BuyerType = (typeof BuyerType)[keyof typeof BuyerType];
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from './async-result';
|
||||
export * from './batch-response-args';
|
||||
export * from './buyer-type';
|
||||
export * from './callback-result';
|
||||
export * from './entity-cotnainer';
|
||||
export * from './entity-status';
|
||||
|
||||
@@ -2,11 +2,11 @@ import z from 'zod';
|
||||
|
||||
export const AddressSchema = z
|
||||
.object({
|
||||
street: z.string().optional(),
|
||||
streetNumber: z.string().optional(),
|
||||
postalCode: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
country: z.string().optional(),
|
||||
additionalInfo: z.string().optional(),
|
||||
street: z.string().describe('Street name').optional(),
|
||||
streetNumber: z.string().describe('Street number').optional(),
|
||||
postalCode: z.string().describe('Postal code').optional(),
|
||||
city: z.string().describe('City name').optional(),
|
||||
country: z.string().describe('Country').optional(),
|
||||
additionalInfo: z.string().describe('Additional information').optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
@@ -6,12 +6,12 @@ import { GenderSchema } from './gender.schema';
|
||||
import { OrganisationSchema } from './organisation.schema';
|
||||
|
||||
export const AddresseeWithReferenceSchema = EntityReferenceSchema.extend({
|
||||
address: AddressSchema.optional(),
|
||||
communicationDetails: CommunicationDetailsSchema.optional(),
|
||||
firstName: z.string().optional(),
|
||||
lastName: z.string().optional(),
|
||||
gender: GenderSchema.optional(),
|
||||
locale: z.string().optional(),
|
||||
organisation: OrganisationSchema.optional(),
|
||||
title: z.string().optional(),
|
||||
address: AddressSchema.describe('Address').optional(),
|
||||
communicationDetails: CommunicationDetailsSchema.describe('Communication details').optional(),
|
||||
firstName: z.string().describe('First name').optional(),
|
||||
lastName: z.string().describe('Last name').optional(),
|
||||
gender: GenderSchema.describe('Gender').optional(),
|
||||
locale: z.string().describe('Locale').optional(),
|
||||
organisation: OrganisationSchema.describe('Organisation information').optional(),
|
||||
title: z.string().describe('Title').optional(),
|
||||
});
|
||||
|
||||
14
libs/common/data-access/src/lib/schemas/buyer-type.schema.ts
Normal file
14
libs/common/data-access/src/lib/schemas/buyer-type.schema.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const BuyerType = {
|
||||
NotSet: 0,
|
||||
ContactCustomer: 1,
|
||||
BranchCustomer: 2,
|
||||
Staff: 4,
|
||||
B2C: 8,
|
||||
B2B: 16,
|
||||
} as const;
|
||||
|
||||
export const BuyerTypeSchema = z.nativeEnum(BuyerType).describe('Buyer type');
|
||||
|
||||
export type BuyerType = z.infer<typeof BuyerTypeSchema>;
|
||||
@@ -1,8 +1,8 @@
|
||||
import z from 'zod';
|
||||
|
||||
export const CommunicationDetailsSchema = z.object({
|
||||
email: z.string().optional(),
|
||||
phone: z.string().optional(),
|
||||
mobile: z.string().optional(),
|
||||
fax: z.string().optional(),
|
||||
email: z.string().describe('Email address').optional(),
|
||||
phone: z.string().describe('Phone number').optional(),
|
||||
mobile: z.string().describe('Mobile phone number').optional(),
|
||||
fax: z.string().describe('Fax number').optional(),
|
||||
});
|
||||
|
||||
@@ -14,5 +14,5 @@ import { EntityReferenceContainerSchema } from './entity-reference-container.sch
|
||||
*/
|
||||
export const EntityContainerSchema = <T extends z.ZodTypeAny>(dataSchema: T) =>
|
||||
EntityReferenceContainerSchema.extend({
|
||||
data: dataSchema.optional(),
|
||||
data: dataSchema.describe('Data').optional(),
|
||||
});
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { z } from 'zod';
|
||||
import { ExternalReferenceSchema } from './external-reference.schema';
|
||||
|
||||
/**
|
||||
* Schema for EntityDTOReferenceContainer
|
||||
* Base container type for entity references with metadata
|
||||
*
|
||||
* Note: externalReference uses z.any() to avoid type conflicts between
|
||||
* our optional ExternalReferenceSchema and the generated DTOs which require externalStatus
|
||||
*/
|
||||
export const EntityReferenceContainerSchema = z.object({
|
||||
displayLabel: z.string().optional(),
|
||||
enabled: z.boolean().optional(),
|
||||
externalReference: ExternalReferenceSchema.optional(),
|
||||
id: z.number().optional(),
|
||||
pId: z.string().optional(),
|
||||
selected: z.boolean().optional(),
|
||||
uId: z.string().optional(),
|
||||
displayLabel: z.string().describe('Display label').optional(),
|
||||
enabled: z.boolean().describe('Whether this is enabled').optional(),
|
||||
externalReference: z.any().describe('External system reference').optional(),
|
||||
id: z.number().describe('Unique identifier').optional(),
|
||||
pId: z.string().describe('P identifier').optional(),
|
||||
selected: z.boolean().describe('Whether this option is currently selected').optional(),
|
||||
uId: z.string().describe('U identifier').optional(),
|
||||
});
|
||||
|
||||
export type EntityReferenceContainer = z.infer<
|
||||
|
||||
@@ -2,7 +2,7 @@ import z from 'zod';
|
||||
import { EntityReferenceContainerSchema } from './entity-reference-container.schema';
|
||||
|
||||
export const EntityReferenceSchema = z.object({
|
||||
pId: z.string().optional(),
|
||||
reference: EntityReferenceContainerSchema.optional(),
|
||||
source: z.number().optional(),
|
||||
pId: z.string().describe('P identifier').optional(),
|
||||
reference: EntityReferenceContainerSchema.describe('Reference').optional(),
|
||||
source: z.number().describe('Source').optional(),
|
||||
});
|
||||
|
||||
@@ -4,4 +4,4 @@ import { EntityStatus } from '../models';
|
||||
/**
|
||||
* EntityStatus is a bitwise enum with values: 0 | 1 | 2 | 4 | 8
|
||||
*/
|
||||
export const EntityStatusSchema = z.nativeEnum(EntityStatus);
|
||||
export const EntityStatusSchema = z.nativeEnum(EntityStatus).describe('Entity status');
|
||||
|
||||
12
libs/common/data-access/src/lib/schemas/entity.schema.ts
Normal file
12
libs/common/data-access/src/lib/schemas/entity.schema.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { z } from 'zod';
|
||||
import { EntityStatusSchema } from './entity-status.schema';
|
||||
|
||||
export const EntitySchema = z.object({
|
||||
changed: z.string().describe('Changed').optional(),
|
||||
created: z.string().describe('Created').optional(),
|
||||
id: z.number().int().positive().describe('Unique identifier').optional(),
|
||||
pId: z.string().describe('P identifier').optional(),
|
||||
status: EntityStatusSchema.describe('Current status').optional(),
|
||||
uId: z.string().describe('U identifier').optional(),
|
||||
version: z.number().int().nonnegative().describe('Version').optional(),
|
||||
});
|
||||
@@ -5,17 +5,24 @@ import { EntityStatusSchema } from './entity-status.schema';
|
||||
* Schema for ExternalReferenceDTO
|
||||
* Represents external system reference information
|
||||
*
|
||||
* Note: externalStatus is REQUIRED in all generated ExternalReferenceDTO types
|
||||
* Note: In the generated DTOs, externalStatus is REQUIRED when ExternalReferenceDTO is present.
|
||||
* However, we make all fields optional in this schema because:
|
||||
* 1. This schema is used within EntityReferenceContainerSchema where externalReference itself is optional
|
||||
* 2. When constructing objects, we often omit externalReference entirely
|
||||
* 3. Type compatibility: our inferred types must be assignable to the generated DTOs
|
||||
*
|
||||
* When using this schema to create objects that will be passed to generated API clients,
|
||||
* either omit externalReference entirely OR ensure externalStatus is provided.
|
||||
*/
|
||||
export const ExternalReferenceSchema = z.object({
|
||||
externalChanged: z.string().optional(),
|
||||
externalCreated: z.string().optional(),
|
||||
externalNumber: z.string().optional(),
|
||||
externalPK: z.string().optional(),
|
||||
externalRepository: z.string().optional(),
|
||||
externalStatus: EntityStatusSchema,
|
||||
externalVersion: z.number().optional(),
|
||||
publishToken: z.string().optional(),
|
||||
externalChanged: z.string().describe('External changed').optional(),
|
||||
externalCreated: z.string().describe('External created').optional(),
|
||||
externalNumber: z.string().describe('External number').optional(),
|
||||
externalPK: z.string().describe('External p k').optional(),
|
||||
externalRepository: z.string().describe('External repository').optional(),
|
||||
externalStatus: EntityStatusSchema.describe('External status').optional(),
|
||||
externalVersion: z.number().describe('External version').optional(),
|
||||
publishToken: z.string().describe('Publish token').optional(),
|
||||
});
|
||||
|
||||
export type ExternalReference = z.infer<typeof ExternalReferenceSchema>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import z from 'zod';
|
||||
import { Gender } from '../models';
|
||||
|
||||
export const GenderSchema = z.nativeEnum(Gender);
|
||||
export const GenderSchema = z.nativeEnum(Gender).describe('Gender');
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
export * from './address.schema';
|
||||
export * from './addressee-with-reference.schema';
|
||||
export * from './buyer-type.schema';
|
||||
export * from './communication-details.schema';
|
||||
export * from './entity-container.schema';
|
||||
export * from './entity-reference-container.schema';
|
||||
export * from './entity-reference.schema';
|
||||
export * from './entity-status.schema';
|
||||
export * from './entity.schema';
|
||||
export * from './external-reference.schema';
|
||||
export * from './gender.schema';
|
||||
export * from './key-value.schema';
|
||||
export * from './label.schema';
|
||||
export * from './notification-channel.schema';
|
||||
export * from './organisation-names.schema';
|
||||
export * from './organisation.schema';
|
||||
export * from './payment-type.schema';
|
||||
export * from './price-value.schema';
|
||||
export * from './price.schema';
|
||||
export * from './quantity-unit-type.schema';
|
||||
export * from './touch-base.schema';
|
||||
export * from './vat-type.schema';
|
||||
export * from './vat-value.schema';
|
||||
|
||||
25
libs/common/data-access/src/lib/schemas/key-value.schema.ts
Normal file
25
libs/common/data-access/src/lib/schemas/key-value.schema.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import z from 'zod';
|
||||
|
||||
export const KeyValueSchema = <
|
||||
TK extends z.ZodTypeAny,
|
||||
TV extends z.ZodTypeAny,
|
||||
>(
|
||||
keySchema: TK,
|
||||
valueSchema: TV,
|
||||
) =>
|
||||
z.object({
|
||||
command: z.string().describe('Command').optional(),
|
||||
description: z.string().describe('Description text').optional(),
|
||||
enabled: z.boolean().describe('Whether this is enabled').optional(),
|
||||
group: z.string().describe('Group').optional(),
|
||||
key: keySchema.describe('Key').optional(),
|
||||
label: z.string().describe('Label').optional(),
|
||||
selected: z.boolean().describe('Whether this option is currently selected').optional(),
|
||||
sort: z.number().describe('Sort criteria').optional(),
|
||||
value: valueSchema.describe('Value').optional(),
|
||||
});
|
||||
|
||||
export const KeyValueOfStringAndStringSchema = KeyValueSchema(
|
||||
z.string(),
|
||||
z.string(),
|
||||
);
|
||||
9
libs/common/data-access/src/lib/schemas/label.schema.ts
Normal file
9
libs/common/data-access/src/lib/schemas/label.schema.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { z } from 'zod';
|
||||
import { EntitySchema } from './entity.schema';
|
||||
|
||||
export const LabelSchema = z
|
||||
.object({
|
||||
key: z.string().describe('Key').optional(),
|
||||
name: z.string().describe('Name').optional(),
|
||||
})
|
||||
.extend(EntitySchema.shape);
|
||||
@@ -0,0 +1,14 @@
|
||||
import z from 'zod';
|
||||
|
||||
export const NotificationChannel = {
|
||||
NotSet: 0,
|
||||
Email: 1,
|
||||
SMS: 2,
|
||||
Phone: 4,
|
||||
Fax: 8,
|
||||
Postal: 16,
|
||||
} as const;
|
||||
|
||||
export const NotificationChannelSchema = z.nativeEnum(NotificationChannel).describe('Notification channel');
|
||||
|
||||
export type NotificationChannel = z.infer<typeof NotificationChannelSchema>;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const OrganisationNamesSchema = z.object({
|
||||
department: z.string().optional(),
|
||||
legalForm: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
nameSuffix: z.string().optional(),
|
||||
department: z.string().describe('Department').optional(),
|
||||
legalForm: z.string().describe('Legal form').optional(),
|
||||
name: z.string().describe('Name').optional(),
|
||||
nameSuffix: z.string().describe('Name suffix').optional(),
|
||||
});
|
||||
|
||||
@@ -2,8 +2,8 @@ import z from 'zod';
|
||||
import { OrganisationNamesSchema } from './organisation-names.schema';
|
||||
|
||||
export const OrganisationSchema = OrganisationNamesSchema.extend({
|
||||
costUnit: z.string().optional(),
|
||||
gln: z.string().optional(),
|
||||
sector: z.string().optional(),
|
||||
vatId: z.string().optional(),
|
||||
costUnit: z.string().describe('Cost unit').optional(),
|
||||
gln: z.string().describe('Gln').optional(),
|
||||
sector: z.string().describe('Sector').optional(),
|
||||
vatId: z.string().describe('Vat identifier').optional(),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import z from 'zod';
|
||||
|
||||
export const PaymentType = {
|
||||
NotSet: 0,
|
||||
WhenCollecting: 1,
|
||||
Free: 2,
|
||||
Cash: 4,
|
||||
DirectDebit: 8,
|
||||
DebitAdviceMandate: 16,
|
||||
DebitCard: 32,
|
||||
CreditCard: 64,
|
||||
Invoice: 128,
|
||||
PrePayment: 256,
|
||||
Voucher: 512,
|
||||
CollectiveInvoice: 1024,
|
||||
PayPal: 2048,
|
||||
InstantTransfer: 4096,
|
||||
PayOnDelivery: 8192,
|
||||
BonusCard: 16384,
|
||||
AmazonPay: 32768,
|
||||
} as const;
|
||||
|
||||
export const PaymentTypeSchema = z.nativeEnum(PaymentType).describe('Payment type');
|
||||
|
||||
export type PaymentType = z.infer<typeof PaymentTypeSchema>;
|
||||
@@ -1,7 +1,7 @@
|
||||
import z from 'zod';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const PriceValueSchema = z.object({
|
||||
value: z.number().optional(),
|
||||
currency: z.string().optional(),
|
||||
currencySymbol: z.string().optional(),
|
||||
value: z.number().describe('Value').optional(),
|
||||
currency: z.string().describe('Currency code').optional(),
|
||||
currencySymbol: z.string().describe('Currency symbol').optional(),
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import z from 'zod';
|
||||
import { z } from 'zod';
|
||||
import { PriceValueSchema } from './price-value.schema';
|
||||
import { VatValueSchema } from './vat-value.schema';
|
||||
|
||||
@@ -55,6 +55,6 @@ import { VatValueSchema } from './vat-value.schema';
|
||||
// Effort: ~4 hours | Impact: High | Risk: Low
|
||||
// See: complexity-analysis.md (TypeScript Section, Issue 5)
|
||||
export const PriceSchema = z.object({
|
||||
value: PriceValueSchema.optional(),
|
||||
vat: VatValueSchema.optional(),
|
||||
value: PriceValueSchema.describe('Value').optional(),
|
||||
vat: VatValueSchema.describe('Value Added Tax').optional(),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const QuantityUnitType = {
|
||||
NotSet: 0,
|
||||
Pieces: 1,
|
||||
Weight: 2,
|
||||
Length: 4,
|
||||
Area: 8,
|
||||
Volume: 16,
|
||||
DigitalSize: 32,
|
||||
Time: 64,
|
||||
Resolution: 128,
|
||||
Money: 256,
|
||||
} as const;
|
||||
|
||||
export const QuantityUnitTypeSchema = z.nativeEnum(QuantityUnitType).describe('QuantityUnit type');
|
||||
|
||||
export type QuantityUnitType = z.infer<typeof QuantityUnitTypeSchema>;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const TouchBaseSchema = z.object({});
|
||||
@@ -1,4 +1,4 @@
|
||||
import z from 'zod';
|
||||
import { VatType } from '../models';
|
||||
|
||||
export const VatTypeSchema = z.nativeEnum(VatType).optional();
|
||||
export const VatTypeSchema = z.nativeEnum(VatType).optional().describe('Vat type');
|
||||
|
||||
@@ -2,8 +2,8 @@ import z from 'zod';
|
||||
import { VatTypeSchema } from './vat-type.schema';
|
||||
|
||||
export const VatValueSchema = z.object({
|
||||
value: z.number().optional(),
|
||||
label: z.string().optional(),
|
||||
inPercent: z.number().optional(),
|
||||
vatType: VatTypeSchema.optional(),
|
||||
value: z.number().describe('Value').optional(),
|
||||
label: z.string().describe('Label').optional(),
|
||||
inPercent: z.number().describe('In percent').optional(),
|
||||
vatType: VatTypeSchema.describe('VAT type').optional(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user