@evenicanpm/storefront-core 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -3
- package/src/api-manager/README.md +52 -27
- package/src/api-manager/datasources/d365/d365-cart.datasource.ts +166 -17
- package/src/api-manager/datasources/d365/d365-invoice.datasource.ts +100 -0
- package/src/api-manager/datasources/d365/d365-order.datasource.ts +75 -18
- package/src/api-manager/datasources/d365/d365-product.datasource.ts +19 -1
- package/src/api-manager/datasources/d365/d365-user.datasource.ts +96 -22
- package/src/api-manager/datasources/d365/d365.datasource.ts +3 -0
- package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +10 -3
- package/src/api-manager/datasources/e4/e4.datasource.ts +9 -0
- package/src/api-manager/datasources/e4/order/e4-order.datasource.ts +7 -4
- package/src/api-manager/datasources/e4/user/e4-user.datasource.ts +4 -0
- package/src/api-manager/index.ts +54 -3
- package/src/api-manager/lib/get-graphql-client.ts +11 -5
- package/src/api-manager/schemas/cart.schema.ts +10 -1
- package/src/api-manager/schemas/invoice.schema.ts +55 -0
- package/src/api-manager/schemas/order.schema.ts +13 -1
- package/src/api-manager/schemas/user.schema.ts +8 -0
- package/src/api-manager/services/create-query.ts +4 -10
- package/src/api-manager/services/invoice/queries/get-invoice-details.ts +18 -0
- package/src/api-manager/services/invoice/queries/get-invoices.ts +18 -0
- package/src/api-manager/services/order/queries/get-order-details.ts +1 -1
- package/src/api-manager/services/order/queries/get-orders.ts +6 -3
- package/src/api-manager/services/user/queries/get-customer-balance.ts +20 -0
- package/src/api-manager/types/Datasource.ts +21 -2
- package/src/auth/better-auth.ts +1 -1
- package/src/cms/blocks/block-manager.tsx +18 -3
- package/src/cms/blocks/components/cta-banner.tsx +65 -0
- package/src/cms/blocks/components/hero-image.tsx +83 -0
- package/src/cms/blocks/index.tsx +2 -0
- package/src/cms/blocks/interfaces.ts +20 -0
- package/src/cms/draft-mode-badge.tsx +26 -0
- package/src/cms/queries.ts +81 -0
- package/src/components/flex-box/flex-box.tsx +2 -0
- package/src/components/header/components/user.tsx +37 -12
- package/src/components/mini-cart/mini-cart.tsx +3 -3
- package/src/components/wishlist-dialogs/add-to-wishlist/compound/wishlist-dialog-header.tsx +1 -0
- package/src/pages/account/account-navigation.tsx +88 -60
- package/src/pages/account/account-routes.ts +52 -0
- package/src/pages/account/orders/order-history-filter-types.tsx +26 -0
- package/src/pages/account/orders/order-history-filters-panel.tsx +375 -0
- package/src/pages/account/orders/order-history-header.tsx +54 -0
- package/src/pages/account/orders/order-history-pagination.tsx +55 -0
- package/src/pages/account/orders/order-history-root.tsx +125 -0
- package/src/pages/account/orders/order-history-row.tsx +110 -0
- package/src/pages/account/orders/order-history-search-and-filter.tsx +449 -0
- package/src/pages/account/orders/order-history-search-bar.tsx +84 -0
- package/src/pages/account/orders/order-history-search-dropdown.tsx +53 -0
- package/src/pages/account/orders/order-history-sort.tsx +90 -0
- package/src/pages/account/orders/order-history-table.tsx +54 -0
- package/src/pages/account/orders/order-row.tsx +2 -2
- package/src/pages/account/orders/orders-drop-down-handler.tsx +19 -0
- package/src/pages/account/table-header.tsx +20 -0
- package/src/pages/account/wishlist/wishlist-item.tsx +1 -1
- package/src/pages/blog/blog-card.tsx +9 -3
- package/src/pages/blog/blog-detail-view.tsx +150 -0
- package/src/pages/blog/blog-list-view.tsx +59 -0
- package/src/pages/cart/estimate-shipping.tsx +6 -5
- package/src/pages/checkout/checkout-alt-form/checkout-form.tsx +43 -21
- package/src/pages/checkout/checkout-alt-form/steps/payment/payment-details.tsx +144 -19
- package/src/pages/cms-page-view.tsx +53 -0
- package/src/pages/quickorder/order-upload.tsx +12 -6
- package/src/pages/quickorder/quick-order.tsx +25 -20
|
@@ -26,11 +26,15 @@ import {
|
|
|
26
26
|
updateProductListLinesAsync,
|
|
27
27
|
readAsync as wishlistReadAsync,
|
|
28
28
|
} from "@msdyn365-commerce/retail-proxy/dist/DataActions/ProductListsDataActions.g";
|
|
29
|
+
import { getCustomerBalanceAsync } from "@msdyn365-commerce/retail-proxy/dist/DataActions/StoreOperationsDataActions.g";
|
|
30
|
+
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
29
31
|
import jwt from "jsonwebtoken";
|
|
30
32
|
import { uniq } from "lodash";
|
|
31
33
|
import type {
|
|
32
34
|
CopyCartToWishlistInput,
|
|
35
|
+
CustomerBalances,
|
|
33
36
|
ExtendedWishlist,
|
|
37
|
+
GetCustomerBalanceInput,
|
|
34
38
|
User,
|
|
35
39
|
UserCounts,
|
|
36
40
|
Wishlist,
|
|
@@ -51,6 +55,8 @@ function decodeIdTokenClaims(token: string): IdTokenClaims {
|
|
|
51
55
|
return decoded as IdTokenClaims;
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
const tracer = trace.getTracer("d365-user-datasource");
|
|
59
|
+
|
|
54
60
|
class D365UserDatasource extends D365DatasourceBase implements UserApi {
|
|
55
61
|
private getRetailContext(context: ICallerContext): IContext {
|
|
56
62
|
return context as unknown as IContext;
|
|
@@ -93,34 +99,102 @@ class D365UserDatasource extends D365DatasourceBase implements UserApi {
|
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
async getUser(): Promise<User | null> {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
102
|
+
return tracer.startActiveSpan("d365.getUser", async (span) => {
|
|
103
|
+
try {
|
|
104
|
+
const context = this.context;
|
|
105
|
+
if (!context.requestContext.user.isAuthenticated) {
|
|
106
|
+
span.setAttributes({ "d365.user.authenticated": false });
|
|
107
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let customer: Customer;
|
|
112
|
+
try {
|
|
113
|
+
customer = await readAsync(this.getRetailContext(context), "");
|
|
114
|
+
} catch {
|
|
115
|
+
const token = decodeIdTokenClaims(context.requestContext.user.token);
|
|
116
|
+
customer = await createCustomerAsync(this.getRetailContext(context), {
|
|
117
|
+
AccountNumber: "",
|
|
118
|
+
Email: Array.isArray(token.emails) ? token.emails[0] : token.email,
|
|
119
|
+
FirstName: token.given_name,
|
|
120
|
+
LastName: token.family_name || ".",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const mappedAddresses = (customer.Addresses ?? []).map((a) => ({
|
|
125
|
+
...a,
|
|
126
|
+
Id: a.RecordId?.toString() ?? "",
|
|
127
|
+
}));
|
|
128
|
+
|
|
129
|
+
span.setAttributes({
|
|
130
|
+
"d365.user.authenticated": true,
|
|
131
|
+
"d365.user.account_number": customer.AccountNumber ?? "",
|
|
132
|
+
"d365.user.email": customer.Email ?? "",
|
|
133
|
+
"d365.user.first_name": customer.FirstName ?? "",
|
|
134
|
+
"d365.user.last_name": customer.LastName ?? "",
|
|
135
|
+
"d365.user.customer_type": customer.CustomerTypeValue ?? "",
|
|
136
|
+
"d365.user.record_id": customer.RecordId?.toString() ?? "",
|
|
137
|
+
"d365.user.address_count": mappedAddresses.length,
|
|
138
|
+
});
|
|
139
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
...customer,
|
|
143
|
+
Addresses: mappedAddresses,
|
|
144
|
+
} as User;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const message =
|
|
147
|
+
error instanceof Error ? error.message : JSON.stringify(error);
|
|
148
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
149
|
+
span.recordException(
|
|
150
|
+
error instanceof Error ? error : new Error(message),
|
|
151
|
+
);
|
|
152
|
+
throw new Error(`getUser failed: ${message}`);
|
|
153
|
+
} finally {
|
|
154
|
+
span.end();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
118
157
|
}
|
|
119
158
|
|
|
120
159
|
async getUserCounts(): Promise<UserCounts> {
|
|
121
160
|
throw new Error("Method not implemented.");
|
|
122
161
|
}
|
|
123
162
|
|
|
163
|
+
async getCustomerBalance(
|
|
164
|
+
input: GetCustomerBalanceInput,
|
|
165
|
+
): Promise<CustomerBalances> {
|
|
166
|
+
return tracer.startActiveSpan("d365.getCustomerBalance", async (span) => {
|
|
167
|
+
try {
|
|
168
|
+
const context = this.context;
|
|
169
|
+
const balances = await getCustomerBalanceAsync(
|
|
170
|
+
this.getRetailContext(context),
|
|
171
|
+
input.accountNumber,
|
|
172
|
+
input.invoiceAccountNumber,
|
|
173
|
+
);
|
|
174
|
+
span.setAttributes({
|
|
175
|
+
"d365.balance.account_number": input.accountNumber,
|
|
176
|
+
"d365.balance.credit_limit": balances.CreditLimit,
|
|
177
|
+
"d365.balance.invoice_account_balance":
|
|
178
|
+
balances.InvoiceAccountBalance,
|
|
179
|
+
"d365.balance.invoice_account_credit_limit":
|
|
180
|
+
balances.InvoiceAccountCreditLimit,
|
|
181
|
+
});
|
|
182
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
183
|
+
return balances;
|
|
184
|
+
} catch (error) {
|
|
185
|
+
const message =
|
|
186
|
+
error instanceof Error ? error.message : JSON.stringify(error);
|
|
187
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
188
|
+
span.recordException(
|
|
189
|
+
error instanceof Error ? error : new Error(message),
|
|
190
|
+
);
|
|
191
|
+
throw new Error(`getCustomerBalance failed: ${message}`);
|
|
192
|
+
} finally {
|
|
193
|
+
span.end();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
124
198
|
async getWishlists(): Promise<Wishlist[]> {
|
|
125
199
|
const context = this.context;
|
|
126
200
|
const productListType = ProductListType.WishList;
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "@evenicanpm/storefront-core/src/api-manager/types/Datasource";
|
|
19
19
|
import type { ICallerContext } from "@msdyn365-commerce/retail-proxy";
|
|
20
20
|
import { D365ProductDatasource } from ".";
|
|
21
|
+
import D365InvoiceDatasource from "./d365-invoice.datasource";
|
|
21
22
|
|
|
22
23
|
export class D365Datasource extends Datasource implements PrimaryDatasource {
|
|
23
24
|
user: UserApi;
|
|
@@ -28,6 +29,7 @@ export class D365Datasource extends Datasource implements PrimaryDatasource {
|
|
|
28
29
|
organization: OrganizationApi;
|
|
29
30
|
session: SessionApi;
|
|
30
31
|
cart: D365CartDatasource;
|
|
32
|
+
invoice: D365InvoiceDatasource;
|
|
31
33
|
constructor(name: string, context: ICallerContext) {
|
|
32
34
|
super(name);
|
|
33
35
|
this.cart = new D365CartDatasource(context);
|
|
@@ -38,6 +40,7 @@ export class D365Datasource extends Datasource implements PrimaryDatasource {
|
|
|
38
40
|
this.organization = new D365OrganizationDatasource(context);
|
|
39
41
|
this.session = new D365SessionDatasource(context);
|
|
40
42
|
this.user = new D365UserDatasource(context);
|
|
43
|
+
this.invoice = new D365InvoiceDatasource(context);
|
|
41
44
|
}
|
|
42
45
|
// Datasources
|
|
43
46
|
}
|
|
@@ -21,9 +21,16 @@ import { auth } from "@/auth/better-auth";
|
|
|
21
21
|
export async function getContextFromCookie(): Promise<ICallerContext> {
|
|
22
22
|
const cookieStore = await cookies();
|
|
23
23
|
const d365Context = cookieStore.get("D365Context");
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
let accessToken = "";
|
|
25
|
+
try {
|
|
26
|
+
const tokens = await auth.api.getAccessToken({
|
|
27
|
+
headers: await getHeaders(),
|
|
28
|
+
body: { providerId: "entra-external-id" },
|
|
29
|
+
});
|
|
30
|
+
accessToken = tokens?.idToken || tokens?.accessToken || "";
|
|
31
|
+
} catch {
|
|
32
|
+
// User may not be authenticated — continue with empty token
|
|
33
|
+
}
|
|
27
34
|
const locale = await getLocale();
|
|
28
35
|
if (d365Context) {
|
|
29
36
|
const context = JSON.parse(d365Context.value) as ICallerContext;
|
|
@@ -19,6 +19,15 @@ const E4Datasource: PrimaryDatasource = {
|
|
|
19
19
|
product,
|
|
20
20
|
organization,
|
|
21
21
|
categories,
|
|
22
|
+
// To be implemented in future iteration
|
|
23
|
+
invoice: {
|
|
24
|
+
getInvoices: async () => {
|
|
25
|
+
throw new Error("Method not implemented.");
|
|
26
|
+
},
|
|
27
|
+
getInvoiceDetails: async () => {
|
|
28
|
+
throw new Error("Method not implemented.");
|
|
29
|
+
},
|
|
30
|
+
},
|
|
22
31
|
};
|
|
23
32
|
|
|
24
33
|
export default E4Datasource;
|
|
@@ -5,17 +5,19 @@ import {
|
|
|
5
5
|
import getGraphqlClient from "@evenicanpm/storefront-core/src/api-manager/lib/get-graphql-client";
|
|
6
6
|
import type {
|
|
7
7
|
GetSalesOrderDetailsInput,
|
|
8
|
+
GetSalesOrdersInput,
|
|
8
9
|
SalesOrder,
|
|
9
|
-
SalesOrderInput,
|
|
10
10
|
} from "@evenicanpm/storefront-core/src/api-manager/schemas/order.schema";
|
|
11
11
|
import type { OrderApi } from "@evenicanpm/storefront-core/src/api-manager/types/Datasource";
|
|
12
12
|
import { merge } from "object-mapper";
|
|
13
13
|
|
|
14
14
|
const order: OrderApi = {
|
|
15
|
-
async getSalesOrders(input:
|
|
15
|
+
async getSalesOrders(input: GetSalesOrdersInput): Promise<SalesOrder[]> {
|
|
16
16
|
const e4Api = await getGraphqlClient(true);
|
|
17
17
|
|
|
18
|
-
const { data, errors } = await e4Api.e4OrderListSM({
|
|
18
|
+
const { data, errors } = await e4Api.e4OrderListSM({
|
|
19
|
+
id: input?.orderSearchCriteria?.CustomerAccountNumber ?? "",
|
|
20
|
+
});
|
|
19
21
|
|
|
20
22
|
if (errors) {
|
|
21
23
|
throw new Error("Error getting orders");
|
|
@@ -30,9 +32,10 @@ const order: OrderApi = {
|
|
|
30
32
|
input: GetSalesOrderDetailsInput,
|
|
31
33
|
): Promise<SalesOrder> {
|
|
32
34
|
const e4Api = await getGraphqlClient(true);
|
|
35
|
+
if (!input?.transactionId) throw new Error("transactionId is required");
|
|
33
36
|
|
|
34
37
|
const { data, errors } = await e4Api.e4OrderReadMD({
|
|
35
|
-
id: input
|
|
38
|
+
id: input.transactionId,
|
|
36
39
|
});
|
|
37
40
|
|
|
38
41
|
if (errors) {
|
|
@@ -138,6 +138,10 @@ const user: UserApi = {
|
|
|
138
138
|
async copyCartToWishlist(_input: CopyCartToWishlistInput): Promise<Wishlist> {
|
|
139
139
|
throw new Error("copyCartToWishlist not implemented");
|
|
140
140
|
},
|
|
141
|
+
|
|
142
|
+
async getCustomerBalance(_input) {
|
|
143
|
+
throw new Error("getCustomerBalance not implemented");
|
|
144
|
+
},
|
|
141
145
|
};
|
|
142
146
|
|
|
143
147
|
export default user;
|
package/src/api-manager/index.ts
CHANGED
|
@@ -1,23 +1,74 @@
|
|
|
1
1
|
import { D365Datasource } from "@evenicanpm/storefront-core/src/api-manager/datasources/d365/index";
|
|
2
2
|
import { getContextFromCookie } from "@evenicanpm/storefront-core/src/api-manager/datasources/d365/utils/get-context-cookie";
|
|
3
3
|
import E4Datasource from "@evenicanpm/storefront-core/src/api-manager/datasources/e4/e4.datasource";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
Datasource,
|
|
6
|
+
DatasourceApis,
|
|
7
|
+
SecondaryDatasource,
|
|
8
|
+
} from "@evenicanpm/storefront-core/src/api-manager/types/Datasource";
|
|
9
|
+
|
|
10
|
+
const OVERRIDES_FILE = "./overrides.datasource.ts";
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Returns the active commerce datasource based on the API_MANAGER_PRIMARY
|
|
8
14
|
* environment variable. Defaults to "e4" when the variable is not set.
|
|
9
15
|
*
|
|
16
|
+
* Supports project-level function overrides via
|
|
17
|
+
* src/extensions/api-manager-overrides/overrides.datasource.ts
|
|
18
|
+
*
|
|
10
19
|
* Supported values: "e4" | "d365"
|
|
11
20
|
*/
|
|
12
21
|
async function createApiManager(): Promise<Datasource> {
|
|
13
22
|
const primary = process.env.API_MANAGER_PRIMARY ?? "e4";
|
|
14
23
|
|
|
24
|
+
let datasource: Datasource;
|
|
15
25
|
if (primary === "d365") {
|
|
16
26
|
const context = await getContextFromCookie();
|
|
17
|
-
|
|
27
|
+
datasource = new D365Datasource("d365", context);
|
|
28
|
+
} else {
|
|
29
|
+
datasource = E4Datasource;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const storefrontOverrides: { [key: string]: any } = {};
|
|
33
|
+
|
|
34
|
+
// @ts-expect-error
|
|
35
|
+
function importAll(r) {
|
|
36
|
+
r.keys().forEach((key: string) => {
|
|
37
|
+
storefrontOverrides[key] = r(key);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Arguments must be literals not variables.
|
|
42
|
+
importAll(
|
|
43
|
+
// @ts-expect-error
|
|
44
|
+
require.context(
|
|
45
|
+
"@storefront/extensions/api-manager-overrides",
|
|
46
|
+
true,
|
|
47
|
+
/overrides\.datasource\.ts/,
|
|
48
|
+
),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const projectOverrides: SecondaryDatasource | undefined =
|
|
52
|
+
storefrontOverrides[OVERRIDES_FILE]?.default;
|
|
53
|
+
|
|
54
|
+
if (projectOverrides) {
|
|
55
|
+
for (const entityName of Object.keys(projectOverrides) as Array<
|
|
56
|
+
keyof DatasourceApis
|
|
57
|
+
>) {
|
|
58
|
+
const entityOverrides = projectOverrides[entityName];
|
|
59
|
+
if (!entityOverrides) continue;
|
|
60
|
+
|
|
61
|
+
if (datasource[entityName]) {
|
|
62
|
+
// Merge override methods into the existing entity
|
|
63
|
+
Object.assign(datasource[entityName] as object, entityOverrides);
|
|
64
|
+
} else {
|
|
65
|
+
// Non-core entity added entirely from overrides
|
|
66
|
+
(datasource as any)[entityName] = entityOverrides;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
18
69
|
}
|
|
19
70
|
|
|
20
|
-
return
|
|
71
|
+
return datasource;
|
|
21
72
|
}
|
|
22
73
|
|
|
23
74
|
export default createApiManager;
|
|
@@ -27,11 +27,17 @@ const getGraphQLClient = async (withAuth = false) => {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (withAuth) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
try {
|
|
31
|
+
const tokens = await auth.api.getAccessToken({
|
|
32
|
+
headers: await getHeaders(),
|
|
33
|
+
body: { providerId: "entra-external-id" },
|
|
34
|
+
});
|
|
35
|
+
const accessToken = tokens?.idToken || tokens?.accessToken;
|
|
36
|
+
if (accessToken) {
|
|
37
|
+
headers.Authorization = `Bearer ${accessToken}`;
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
// User may not be authenticated — continue without auth header
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
|
|
@@ -54,9 +54,10 @@ export const getCardAcceptPointInput = z.object({
|
|
|
54
54
|
export const checkoutInput = z.object({
|
|
55
55
|
id: z.string(),
|
|
56
56
|
receiptEmail: z.string(),
|
|
57
|
-
tokenizedPaymentCard: tokenizedPaymentCardSchema,
|
|
57
|
+
tokenizedPaymentCard: tokenizedPaymentCardSchema.optional(),
|
|
58
58
|
currency: z.string(),
|
|
59
59
|
amount: z.number(),
|
|
60
|
+
paymentMethod: z.enum(["card", "on-account"]).default("card"),
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
export const updateCartLineDeliveryModeInput = z.object({
|
|
@@ -82,6 +83,13 @@ const InventorySearchCartLinesCriteriaInput = z.object({
|
|
|
82
83
|
allDimensionsSelected: z.boolean(),
|
|
83
84
|
});
|
|
84
85
|
|
|
86
|
+
export const updateInvoiceLineInput = z.object({
|
|
87
|
+
cartId: z.string(),
|
|
88
|
+
cartLineId: z.string(),
|
|
89
|
+
price: z.number(),
|
|
90
|
+
version: z.number().optional(),
|
|
91
|
+
});
|
|
92
|
+
|
|
85
93
|
// Typescript Types
|
|
86
94
|
// export type Cart = z.infer<typeof cartSchema>;
|
|
87
95
|
// export type CartLine = z.infer<typeof cartLineSchema>;
|
|
@@ -108,3 +116,4 @@ export type CheckoutInput = z.infer<typeof checkoutInput>;
|
|
|
108
116
|
export type InventorySearchCartLinesCriteriaInput = z.infer<
|
|
109
117
|
typeof InventorySearchCartLinesCriteriaInput
|
|
110
118
|
>;
|
|
119
|
+
export type UpdateInvoiceLineInput = z.infer<typeof updateInvoiceLineInput>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export interface InvoiceSearchCriteria {
|
|
2
|
+
InvoiceIds?: string[];
|
|
3
|
+
CustomerId?: string;
|
|
4
|
+
BusinessPartnerId?: string;
|
|
5
|
+
InvoiceTypeValues?: number[];
|
|
6
|
+
InvoicePaidStatusValues?: number[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface GetInvoicesInput {
|
|
10
|
+
InvoiceSearchCriteria: InvoiceSearchCriteria;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface InvoiceDetailsSearchCriteria {
|
|
14
|
+
InvoiceId?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface GetInvoicesDetailsInput {
|
|
18
|
+
InvoiceSearchCriteria: InvoiceDetailsSearchCriteria;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface SalesInvoiceLine {
|
|
22
|
+
ItemId?: string;
|
|
23
|
+
Description?: string;
|
|
24
|
+
Quantity?: number;
|
|
25
|
+
Price?: number;
|
|
26
|
+
NetAmount?: number;
|
|
27
|
+
LineDiscount?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Invoice {
|
|
31
|
+
Id?: string;
|
|
32
|
+
CustomerName?: string;
|
|
33
|
+
CustomerAccountNumber?: string;
|
|
34
|
+
TotalAmount?: number;
|
|
35
|
+
InvoiceDate?: Date;
|
|
36
|
+
InvoiceDueDate?: Date;
|
|
37
|
+
InvoicePaidStatusValue?: number;
|
|
38
|
+
AmountPaid?: number;
|
|
39
|
+
AmountBalance?: number;
|
|
40
|
+
CurrencyCode?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface InvoiceDetails {
|
|
44
|
+
Id?: string;
|
|
45
|
+
AmountBalance?: number;
|
|
46
|
+
AmountPaid?: number;
|
|
47
|
+
DueDate?: Date;
|
|
48
|
+
SalesInvoiceLine?: SalesInvoiceLine[];
|
|
49
|
+
OrderedByCustomerName?: string;
|
|
50
|
+
Name?: string;
|
|
51
|
+
InvoiceDate?: Date;
|
|
52
|
+
InvoiceSubtotal?: number;
|
|
53
|
+
TotalTaxAmount?: number;
|
|
54
|
+
Amount?: number;
|
|
55
|
+
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
orderSearchCriteriaSchema,
|
|
3
|
+
pagingInfoSchema,
|
|
2
4
|
salesLineSchema,
|
|
3
5
|
salesOrderSchema,
|
|
4
6
|
searchLocationSchema,
|
|
5
7
|
simpleProductSchema,
|
|
8
|
+
sortColumnSchema,
|
|
6
9
|
} from "@evenicanpm/storefront-core/src/api-manager/schemas/d365.schema";
|
|
7
10
|
import z from "zod";
|
|
8
11
|
|
|
9
12
|
const getSalesOrderDetailsInput = z.object({
|
|
10
|
-
transactionId: z.string(),
|
|
13
|
+
transactionId: z.string().optional(),
|
|
14
|
+
salesId: z.string().optional(),
|
|
11
15
|
searchLocation: searchLocationSchema.optional(),
|
|
12
16
|
});
|
|
13
17
|
|
|
@@ -22,9 +26,17 @@ const extendedSalesOrderSchema = salesOrderSchema
|
|
|
22
26
|
.omit({ SalesLines: true })
|
|
23
27
|
.extend({ SalesLines: extendedSalesLineSchema.array().optional() });
|
|
24
28
|
|
|
29
|
+
const getSalesOrdersInput = z.object({
|
|
30
|
+
orderSearchCriteria: orderSearchCriteriaSchema,
|
|
31
|
+
sort: sortColumnSchema.optional(),
|
|
32
|
+
paging: pagingInfoSchema.optional(),
|
|
33
|
+
});
|
|
34
|
+
|
|
25
35
|
export type GetSalesOrderDetailsInput = z.infer<
|
|
26
36
|
typeof getSalesOrderDetailsInput
|
|
27
37
|
>;
|
|
38
|
+
export type GetSalesOrdersInput = z.infer<typeof getSalesOrdersInput>;
|
|
39
|
+
|
|
28
40
|
export type SalesOrderInput = z.infer<typeof salesOrderInput>;
|
|
29
41
|
export type SalesOrder = z.infer<typeof extendedSalesOrderSchema>;
|
|
30
42
|
export type SalesLine = z.infer<typeof extendedSalesLineSchema>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type customerBalancesSchema,
|
|
2
3
|
customerSchema,
|
|
3
4
|
productListLineSchema,
|
|
4
5
|
productListSchema,
|
|
@@ -17,6 +18,13 @@ export const extendedCustomerSchema = customerSchema.extend({
|
|
|
17
18
|
|
|
18
19
|
export type User = z.infer<typeof extendedCustomerSchema>;
|
|
19
20
|
export type UserCounts = z.infer<typeof userCountsSchema>;
|
|
21
|
+
export type CustomerBalances = z.infer<typeof customerBalancesSchema>;
|
|
22
|
+
|
|
23
|
+
export const getCustomerBalanceInput = z.object({
|
|
24
|
+
accountNumber: z.string(),
|
|
25
|
+
invoiceAccountNumber: z.string().optional(),
|
|
26
|
+
});
|
|
27
|
+
export type GetCustomerBalanceInput = z.infer<typeof getCustomerBalanceInput>;
|
|
20
28
|
|
|
21
29
|
// Wishlist
|
|
22
30
|
|
|
@@ -73,7 +73,10 @@ export const createQuery = <TInput, TOutput>(
|
|
|
73
73
|
input?: TInput,
|
|
74
74
|
options?: { enabled: boolean },
|
|
75
75
|
): UseQueryResult<TOutput> =>
|
|
76
|
-
useQuery({
|
|
76
|
+
useQuery({
|
|
77
|
+
...getQueryOptions(input),
|
|
78
|
+
...(options?.enabled !== undefined && { enabled: options.enabled }),
|
|
79
|
+
}),
|
|
77
80
|
useSuspenseData: (input?: TInput): UseSuspenseQueryResult<TOutput> =>
|
|
78
81
|
useSuspenseQuery(getQueryOptions(input)),
|
|
79
82
|
fetchData: (queryClient: QueryClient, input?: TInput) =>
|
|
@@ -97,15 +100,6 @@ export function getApiFromPath<TInput, TOutput>(
|
|
|
97
100
|
const [entity, method] = path;
|
|
98
101
|
const result = apiManager[entity][method];
|
|
99
102
|
|
|
100
|
-
if (process.env.NODE_ENV === "development") {
|
|
101
|
-
// eslint-disable-next-line no-console
|
|
102
|
-
console.log(`[CREATE QUERY] Accessing API Path:`, {
|
|
103
|
-
entity,
|
|
104
|
-
method,
|
|
105
|
-
result,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
103
|
// Function reference loses 'this' context — re-bind for d365 classes.
|
|
110
104
|
if (typeof result === "function") {
|
|
111
105
|
return (result as (input?: TInput) => Promise<TOutput>).bind(
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GetInvoicesDetailsInput } from "@evenicanpm/storefront-core/src/api-manager/schemas/invoice.schema";
|
|
2
|
+
import {
|
|
3
|
+
createApiPath,
|
|
4
|
+
createQuery,
|
|
5
|
+
} from "@evenicanpm/storefront-core/src/api-manager/services/create-query";
|
|
6
|
+
import type { SalesInvoice } from "@msdyn365-commerce/retail-proxy/dist";
|
|
7
|
+
|
|
8
|
+
const apiPath = createApiPath("invoice", "getInvoiceDetails");
|
|
9
|
+
const config = {
|
|
10
|
+
queryKey: "invoices",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getInvoices = createQuery<GetInvoicesDetailsInput, SalesInvoice>(
|
|
14
|
+
apiPath,
|
|
15
|
+
config,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export default getInvoices;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createApiPath,
|
|
3
|
+
createQuery,
|
|
4
|
+
} from "@evenicanpm/storefront-core/src/api-manager/services/create-query";
|
|
5
|
+
import type { OrderInvoice } from "@msdyn365-commerce/retail-proxy/dist";
|
|
6
|
+
import type { GetInvoicesInput } from "../../../schemas/invoice.schema";
|
|
7
|
+
|
|
8
|
+
const apiPath = createApiPath("invoice", "getInvoices");
|
|
9
|
+
const config = {
|
|
10
|
+
queryKey: "invoices",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const getInvoices = createQuery<GetInvoicesInput, OrderInvoice[]>(
|
|
14
|
+
apiPath,
|
|
15
|
+
config,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export default getInvoices;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
GetSalesOrdersInput,
|
|
2
3
|
SalesOrder,
|
|
3
|
-
SalesOrderInput,
|
|
4
4
|
} from "@evenicanpm/storefront-core/src/api-manager/schemas/order.schema";
|
|
5
5
|
import {
|
|
6
6
|
createApiPath,
|
|
@@ -9,9 +9,12 @@ import {
|
|
|
9
9
|
|
|
10
10
|
const apiPath = createApiPath("order", "getSalesOrders");
|
|
11
11
|
const config = {
|
|
12
|
-
queryKey: "
|
|
12
|
+
queryKey: "SalesOrders",
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
const getOrders = createQuery<
|
|
15
|
+
const getOrders = createQuery<GetSalesOrdersInput, SalesOrder[]>(
|
|
16
|
+
apiPath,
|
|
17
|
+
config,
|
|
18
|
+
);
|
|
16
19
|
|
|
17
20
|
export default getOrders;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CustomerBalances,
|
|
3
|
+
GetCustomerBalanceInput,
|
|
4
|
+
} from "@evenicanpm/storefront-core/src/api-manager/schemas/user.schema";
|
|
5
|
+
import {
|
|
6
|
+
createApiPath,
|
|
7
|
+
createQuery,
|
|
8
|
+
} from "@evenicanpm/storefront-core/src/api-manager/services/create-query";
|
|
9
|
+
|
|
10
|
+
const apiPath = createApiPath("user", "getCustomerBalance");
|
|
11
|
+
|
|
12
|
+
const getCustomerBalance = createQuery<
|
|
13
|
+
GetCustomerBalanceInput,
|
|
14
|
+
CustomerBalances
|
|
15
|
+
>(apiPath, {
|
|
16
|
+
queryKey: "customerBalance",
|
|
17
|
+
disableProperties: ["accountNumber"],
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export default getCustomerBalance;
|