|
|
@@ -14,9 +14,118 @@ export const ACTIVE_ORDER_INPUT_FIELD_NAME = 'activeOrderInput';
|
|
|
* and set it on the current Session, and then read the session to obtain the active Order.
|
|
|
* This behaviour is defined by the {@link DefaultActiveOrderStrategy}.
|
|
|
*
|
|
|
+ * The `InputType` generic argument should correspond to the input type defined by the
|
|
|
+ * `defineInputType()` method.
|
|
|
+ *
|
|
|
+ * When `defineInputType()` is used, then the following Shop API operations will receive an additional
|
|
|
+ * `activeOrderInput` argument allowing the active order input to be specified:
|
|
|
+ *
|
|
|
+ * - `activeOrder`
|
|
|
+ * - `eligibleShippingMethods`
|
|
|
+ * - `eligiblePaymentMethods`
|
|
|
+ * - `nextOrderStates`
|
|
|
+ * - `addItemToOrder`
|
|
|
+ * - `adjustOrderLine`
|
|
|
+ * - `removeOrderLine`
|
|
|
+ * - `removeAllOrderLines`
|
|
|
+ * - `applyCouponCode`
|
|
|
+ * - `removeCouponCode`
|
|
|
+ * - `addPaymentToOrder`
|
|
|
+ * - `setCustomerForOrder`
|
|
|
+ * - `setOrderShippingAddress`
|
|
|
+ * - `setOrderBillingAddress`
|
|
|
+ * - `setOrderShippingMethod`
|
|
|
+ * - `setOrderCustomFields`
|
|
|
+ * - `transitionOrderToState`
|
|
|
+ *
|
|
|
+ * @example
|
|
|
+ * ```GraphQL {hl_lines=[5]}
|
|
|
+ * mutation AddItemToOrder {
|
|
|
+ * addItemToOrder(
|
|
|
+ * productVariantId: 42,
|
|
|
+ * quantity: 1,
|
|
|
+ * activeOrderInput: { token: "123456" }
|
|
|
+ * ) {
|
|
|
+ * ...on Order {
|
|
|
+ * id
|
|
|
+ * # ...etc
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ *
|
|
|
+ * @example
|
|
|
+ * ```TypeScript
|
|
|
+ * import { ID } from '\@vendure/common/lib/shared-types';
|
|
|
+ * import {
|
|
|
+ * ActiveOrderStrategy,
|
|
|
+ * CustomerService,
|
|
|
+ * idsAreEqual,
|
|
|
+ * Injector,
|
|
|
+ * Order,
|
|
|
+ * OrderService,
|
|
|
+ * RequestContext,
|
|
|
+ * TransactionalConnection,
|
|
|
+ * } from '\@vendure/core';
|
|
|
+ * import gql from 'graphql-tag';
|
|
|
+ *
|
|
|
+ * // This strategy assumes a "orderToken" custom field is defined on the Order
|
|
|
+ * // entity, and uses that token to perform a lookup to determine the active Order.
|
|
|
+ * //
|
|
|
+ * // Additionally, it does _not_ define a `createActiveOrder()` method, which
|
|
|
+ * // means that a custom mutation would be required to create the initial Order in
|
|
|
+ * // the first place and set the "orderToken" custom field.
|
|
|
+ * class TokenActiveOrderStrategy implements ActiveOrderStrategy<{ token: string }> {
|
|
|
+ * readonly name = 'orderToken';
|
|
|
+ *
|
|
|
+ * private connection: TransactionalConnection;
|
|
|
+ * private orderService: OrderService;
|
|
|
+ *
|
|
|
+ * init(injector: Injector) {
|
|
|
+ * this.connection = injector.get(TransactionalConnection);
|
|
|
+ * this.orderService = injector.get(OrderService);
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * defineInputType = () => gql`
|
|
|
+ * input OrderTokenActiveOrderInput {
|
|
|
+ * token: String
|
|
|
+ * }
|
|
|
+ * `;
|
|
|
+ *
|
|
|
+ * async determineActiveOrder(ctx: RequestContext, input: { token: string }) {
|
|
|
+ * const qb = this.connection
|
|
|
+ * .getRepository(ctx, Order)
|
|
|
+ * .createQueryBuilder('order')
|
|
|
+ * .leftJoinAndSelect('order.customer', 'customer')
|
|
|
+ * .leftJoinAndSelect('customer.user', 'user')
|
|
|
+ * .where('order.customFields.orderToken = :orderToken', { orderToken: input.token });
|
|
|
+ *
|
|
|
+ * const order = await qb.getOne();
|
|
|
+ * if (!order) {
|
|
|
+ * return;
|
|
|
+ * }
|
|
|
+ * // Ensure the active user is the owner of this Order
|
|
|
+ * const orderUserId = order.customer && order.customer.user && order.customer.user.id;
|
|
|
+ * if (order.customer && idsAreEqual(orderUserId, ctx.activeUserId)) {
|
|
|
+ * return order;
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ * }
|
|
|
+ *
|
|
|
+ * // in vendure-config.ts
|
|
|
+ * export const config = {
|
|
|
+ * // ...
|
|
|
+ * orderOptions: {
|
|
|
+ * activeOrderStrategy: new TokenActiveOrderStrategy(),
|
|
|
+ * },
|
|
|
+ * }
|
|
|
+ * ```
|
|
|
+ *
|
|
|
* @since 1.9.0
|
|
|
+ * @docsCategory orders
|
|
|
*/
|
|
|
-export interface ActiveOrderStrategy extends InjectableStrategy {
|
|
|
+export interface ActiveOrderStrategy<InputType extends Record<string, any> | void = void>
|
|
|
+ extends InjectableStrategy {
|
|
|
/**
|
|
|
* @description
|
|
|
* The name of the strategy, e.g. "orderByToken", which will also be used as the
|
|
|
@@ -26,10 +135,8 @@ export interface ActiveOrderStrategy extends InjectableStrategy {
|
|
|
|
|
|
/**
|
|
|
* @description
|
|
|
- * Defines the type of the GraphQL Input object expected by the `authenticate`
|
|
|
- * mutation. The final input object will be a map, with the key being the name
|
|
|
- * of the strategy. The shape of the input object should match the generic `Data`
|
|
|
- * type argument.
|
|
|
+ * Defines the type of the GraphQL Input object expected by the `activeOrderInput`
|
|
|
+ * input argument.
|
|
|
*
|
|
|
* @example
|
|
|
* For example, given the following:
|
|
|
@@ -44,8 +151,8 @@ export interface ActiveOrderStrategy extends InjectableStrategy {
|
|
|
* }
|
|
|
* ```
|
|
|
*
|
|
|
- * assuming the strategy name is "my_auth", then the resulting call to `authenticate`
|
|
|
- * would look like:
|
|
|
+ * assuming the strategy name is "orderByToken", then the resulting call to `activeOrder` (or any of the other
|
|
|
+ * affected Shop API operations) would look like:
|
|
|
*
|
|
|
* ```GraphQL
|
|
|
* activeOrder(activeOrderInput: {
|
|
|
@@ -70,15 +177,15 @@ export interface ActiveOrderStrategy extends InjectableStrategy {
|
|
|
* If automatic creation of an Order does not make sense in your strategy, then leave this method
|
|
|
* undefined. You'll then need to take care of creating an order manually by defining a custom mutation.
|
|
|
*/
|
|
|
- createActiveOrder?: (ctx: RequestContext, inputs: any) => Promise<Order>;
|
|
|
+ createActiveOrder?: (ctx: RequestContext, input: InputType) => Promise<Order>;
|
|
|
|
|
|
/**
|
|
|
* @description
|
|
|
* This method is used to determine the active Order based on the current RequestContext in addition to any
|
|
|
* input values provided, as defined by the `defineInputType` method of this strategy.
|
|
|
*
|
|
|
- * Note that this method is invoked frequently so you should aim to keep it efficient. The returned Order,
|
|
|
+ * Note that this method is invoked frequently, so you should aim to keep it efficient. The returned Order,
|
|
|
* for example, does not need to have its various relations joined.
|
|
|
*/
|
|
|
- determineActiveOrder(ctx: RequestContext, inputs: any): Promise<Order | undefined>;
|
|
|
+ determineActiveOrder(ctx: RequestContext, input: InputType): Promise<Order | undefined>;
|
|
|
}
|