diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d56cf85d..af8e2359 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ * @martijnvdbrug # IS Outfitters have the ability to approve and merge eachothers PR's for Accept Blue -/packages/vendure-plugin-accept-blue/ @is0utfitters @mschipperheyn \ No newline at end of file +/packages/vendure-plugin-accept-blue/ @is0utfitters @mschipperheyn @martijnvdbrug \ No newline at end of file diff --git a/packages/vendure-plugin-accept-blue/CHANGELOG.md b/packages/vendure-plugin-accept-blue/CHANGELOG.md index 936444c3..091ce6f7 100644 --- a/packages/vendure-plugin-accept-blue/CHANGELOG.md +++ b/packages/vendure-plugin-accept-blue/CHANGELOG.md @@ -1,6 +1,11 @@ +# 2.1.0 (2025-01-10) + +- Allow updating created subscriptions via the Admin API +- Moved refunding to admin-api, and only allow with permission UpdateOrder + # 2.0.2 (2025-01-09) -- Correct ctx not being public +- Publicly expose ctx in AcceptBlueTransactionEvent # 2.0.1 (2025-01-09) diff --git a/packages/vendure-plugin-accept-blue/README.md b/packages/vendure-plugin-accept-blue/README.md index 182c3625..797d99e1 100644 --- a/packages/vendure-plugin-accept-blue/README.md +++ b/packages/vendure-plugin-accept-blue/README.md @@ -175,6 +175,33 @@ mutation { The arguments `amount` and `cvv2` are optional, see [the Accept Blue Docs for more info](https://docs.accept.blue/api/v2#tag/processing-credit/paths/~1transactions~1refund). +## Updating Subscriptions + +You can update created subscriptions in Accept Blue as Admin via de admin-api with `UpdateOrder` permissions: + +```graphql +mutation { + updateAcceptBlueSubscription( + input: { + id: 11820 + title: "New Title For Updated Subscription" + frequency: daily + } + ) { + id + name + variantId + recurring { + interval + intervalCount + } + # ... additional subscription fields + } +} +``` + +This wil emit an `AcceptBlueSubscriptionEvent` of type `updated`. + ## CORS If you run into CORS issues loading the Accept Blue hosted tokenization javascript library, you might need to remove the `cross-origin` key on your `script` tag. diff --git a/packages/vendure-plugin-accept-blue/package.json b/packages/vendure-plugin-accept-blue/package.json index 21873990..4924b2f6 100644 --- a/packages/vendure-plugin-accept-blue/package.json +++ b/packages/vendure-plugin-accept-blue/package.json @@ -1,6 +1,6 @@ { "name": "@pinelab/vendure-plugin-accept-blue", - "version": "2.0.2", + "version": "2.1.0", "description": "Vendure plugin for creating subscriptions with the Accept Blue platform", "author": "Martijn van de Brug ", "homepage": "https://pinelab-plugins.com/", diff --git a/packages/vendure-plugin-accept-blue/src/accept-blue-plugin.ts b/packages/vendure-plugin-accept-blue/src/accept-blue-plugin.ts index 01a61b56..22d5435b 100644 --- a/packages/vendure-plugin-accept-blue/src/accept-blue-plugin.ts +++ b/packages/vendure-plugin-accept-blue/src/accept-blue-plugin.ts @@ -3,11 +3,12 @@ import { SubscriptionStrategy } from '../../util/src/subscription/subscription-s import { AcceptBlueService } from './api/accept-blue-service'; import { acceptBluePaymentHandler } from './api/accept-blue-handler'; import { PLUGIN_INIT_OPTIONS } from './constants'; -import { commonApiExtensions } from './api/api-extensions'; +import { adminApiExtensions, shopApiExtensions } from './api/api-extensions'; import { AcceptBlueCommonResolver } from './api/accept-blue-common-resolvers'; import { AcceptBlueController } from './api/accept-blue-controller'; import { DefaultSubscriptionStrategy } from '../../util/src/subscription/default-subscription-strategy'; import { rawBodyMiddleware } from '../../util/src/raw-body.middleware'; +import { AcceptBlueAdminResolver } from './api/accept-blue-admin-resolver'; interface AcceptBluePluginOptionsInput { subscriptionStrategy?: SubscriptionStrategy; @@ -19,11 +20,11 @@ export type AcceptBluePluginOptions = Required; @VendurePlugin({ imports: [PluginCommonModule], adminApiExtensions: { - schema: commonApiExtensions, - resolvers: [AcceptBlueCommonResolver], + schema: adminApiExtensions, + resolvers: [AcceptBlueCommonResolver, AcceptBlueAdminResolver], }, shopApiExtensions: { - schema: commonApiExtensions, + schema: shopApiExtensions, resolvers: [AcceptBlueCommonResolver], }, controllers: [AcceptBlueController], diff --git a/packages/vendure-plugin-accept-blue/src/api/accept-blue-admin-resolver.ts b/packages/vendure-plugin-accept-blue/src/api/accept-blue-admin-resolver.ts new file mode 100644 index 00000000..e2bf4919 --- /dev/null +++ b/packages/vendure-plugin-accept-blue/src/api/accept-blue-admin-resolver.ts @@ -0,0 +1,38 @@ +import { Args, Mutation, Resolver } from '@nestjs/graphql'; +import { Allow, Ctx, Permission, RequestContext } from '@vendure/core'; +import { AcceptBlueService } from './accept-blue-service'; +import { + Mutation as GraphqlMutation, + MutationRefundAcceptBlueTransactionArgs, + MutationUpdateAcceptBlueSubscriptionArgs, +} from './generated/graphql'; + +@Resolver() +export class AcceptBlueAdminResolver { + constructor(private acceptBlueService: AcceptBlueService) {} + + @Mutation() + @Allow(Permission.UpdateOrder) + async refundAcceptBlueTransaction( + @Ctx() ctx: RequestContext, + @Args() + { transactionId, amount, cvv2 }: MutationRefundAcceptBlueTransactionArgs + ): Promise { + return await this.acceptBlueService.refund( + ctx, + transactionId, + amount ?? undefined, + cvv2 ?? undefined + ); + } + + @Mutation() + @Allow(Permission.UpdateOrder) + async updateAcceptBlueSubscription( + @Ctx() ctx: RequestContext, + @Args() + { input }: MutationUpdateAcceptBlueSubscriptionArgs + ): Promise { + return await this.acceptBlueService.updateSubscription(ctx, input); + } +} diff --git a/packages/vendure-plugin-accept-blue/src/api/accept-blue-client.ts b/packages/vendure-plugin-accept-blue/src/api/accept-blue-client.ts index 69a30be5..be8bc8c7 100644 --- a/packages/vendure-plugin-accept-blue/src/api/accept-blue-client.ts +++ b/packages/vendure-plugin-accept-blue/src/api/accept-blue-client.ts @@ -7,7 +7,7 @@ import { AcceptBlueCustomer, AcceptBluePaymentMethod, AcceptBlueRecurringSchedule, - AcceptBlueRecurringScheduleInput, + AcceptBlueRecurringScheduleCreateInput, AcceptBlueRecurringScheduleTransaction, CheckPaymentMethodInput, NoncePaymentMethodInput, @@ -15,6 +15,7 @@ import { AcceptBlueWebhookInput, AcceptBlueWebhook, CustomFields, + AcceptBlueRecurringScheduleUpdateInput, } from '../types'; import { isSameCard, isSameCheck } from '../util'; @@ -132,6 +133,26 @@ export class AcceptBlueClient { ); } + async updateRecurringSchedule( + id: number, + input: AcceptBlueRecurringScheduleUpdateInput + ): Promise { + const formattedInput = { + ...input, + amount: input.amount ? input.amount / 100 : undefined, + // Accept Blue requires dates to be in 'yyyy-mm-dd' format + next_run_date: input.next_run_date + ? this.toDateString(input.next_run_date) + : undefined, + }; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return await this.request( + 'patch', + `recurring-schedules/${id}`, + formattedInput + ); + } + async getTransactionsForRecurringSchedule( id: number ): Promise { @@ -179,7 +200,7 @@ export class AcceptBlueClient { async createRecurringSchedule( customerId: number, - input: AcceptBlueRecurringScheduleInput + input: AcceptBlueRecurringScheduleCreateInput ): Promise { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const result: AcceptBlueRecurringSchedule = await this.request( diff --git a/packages/vendure-plugin-accept-blue/src/api/accept-blue-common-resolvers.ts b/packages/vendure-plugin-accept-blue/src/api/accept-blue-common-resolvers.ts index 2d9e91f9..1184caff 100644 --- a/packages/vendure-plugin-accept-blue/src/api/accept-blue-common-resolvers.ts +++ b/packages/vendure-plugin-accept-blue/src/api/accept-blue-common-resolvers.ts @@ -1,18 +1,9 @@ +import { Args, Parent, Query, ResolveField, Resolver } from '@nestjs/graphql'; import { - Args, - Parent, - Query, - ResolveField, - Resolver, - Mutation, -} from '@nestjs/graphql'; -import { - Allow, Ctx, Customer, EntityHydrator, OrderLine, - Permission, RequestContext, } from '@vendure/core'; import { @@ -24,10 +15,8 @@ import { AcceptBlueService } from './accept-blue-service'; import { AcceptBlueSubscription, Query as GraphqlQuery, - Mutation as GraphqlMutation, QueryPreviewAcceptBlueSubscriptionsArgs, QueryPreviewAcceptBlueSubscriptionsForProductArgs, - MutationRefundAcceptBlueTransactionArgs, } from './generated/graphql'; @Resolver() @@ -76,21 +65,6 @@ export class AcceptBlueCommonResolver { })); } - @Mutation() - @Allow(Permission.Authenticated) - async refundAcceptBlueTransaction( - @Ctx() ctx: RequestContext, - @Args() - { transactionId, amount, cvv2 }: MutationRefundAcceptBlueTransactionArgs - ): Promise { - return await this.acceptBlueService.refund( - ctx, - transactionId, - amount ?? undefined, - cvv2 ?? undefined - ); - } - @ResolveField('acceptBlueHostedTokenizationKey') @Resolver('PaymentMethodQuote') async acceptBlueHostedTokenizationKey( diff --git a/packages/vendure-plugin-accept-blue/src/api/accept-blue-service.ts b/packages/vendure-plugin-accept-blue/src/api/accept-blue-service.ts index 5943d04c..31623b0f 100644 --- a/packages/vendure-plugin-accept-blue/src/api/accept-blue-service.ts +++ b/packages/vendure-plugin-accept-blue/src/api/accept-blue-service.ts @@ -11,6 +11,7 @@ import { Logger, Order, OrderLine, + OrderService, PaymentMethod, PaymentMethodEvent, PaymentMethodService, @@ -51,8 +52,10 @@ import { AcceptBlueRefundResult, AcceptBlueSubscription, AcceptBlueTransaction, + UpdateAcceptBlueSubscriptionInput, } from './generated/graphql'; -import { AcceptBlueTransactionEvent } from './accept-blue-transaction-event'; +import { AcceptBlueTransactionEvent } from '../events/accept-blue-transaction-event'; +import { AcceptBlueSubscriptionEvent } from '../events/accept-blue-subscription-event'; @Injectable() export class AcceptBlueService implements OnApplicationBootstrap { @@ -61,7 +64,8 @@ export class AcceptBlueService implements OnApplicationBootstrap { private readonly paymentMethodService: PaymentMethodService, private readonly customerService: CustomerService, private readonly entityHydrator: EntityHydrator, - private connection: TransactionalConnection, + private readonly orderService: OrderService, + private readonly connection: TransactionalConnection, private eventBus: EventBus, moduleRef: ModuleRef, @Inject(PLUGIN_INIT_OPTIONS) @@ -297,6 +301,47 @@ export class AcceptBlueService implements OnApplicationBootstrap { return recurringSchedules; } + async updateSubscription( + ctx: RequestContext, + input: UpdateAcceptBlueSubscriptionInput + ): Promise { + const scheduleId = input.id; + const orderLine = await this.findOrderLineByScheduleId(ctx, scheduleId); + if (!orderLine) { + throw new UserInputError( + `No order exists with an Accept Blue subscription id of ${scheduleId}` + ); + } + await this.entityHydrator.hydrate(ctx, orderLine, { + relations: ['order', 'productVariant'], + }); + const client = await this.getClientForChannel(ctx); + const schedule = await client.updateRecurringSchedule(scheduleId, { + title: input.title ?? undefined, + amount: input.amount ?? undefined, + frequency: input.frequency ?? undefined, + next_run_date: input.nextRunDate ?? undefined, + num_left: input.numLeft ?? undefined, + active: input.active ?? undefined, + receipt_email: input.receiptEmail || undefined, + }); + // Write History entry on order + await this.orderService.addNoteToOrder(ctx, { + id: orderLine.order.id, + note: `Subscription updated: ${JSON.stringify(input)}`, + isPublic: true, + }); + const subscription = this.mapToGraphqlSubscription( + schedule, + orderLine.productVariant.id + ); + // Publish event + await this.eventBus.publish( + new AcceptBlueSubscriptionEvent(ctx, subscription, 'updated', input) + ); + return subscription; + } + /** * Resolve the subscriptions for an order line. For a placed order, this will also fetch transactions per subscription */ diff --git a/packages/vendure-plugin-accept-blue/src/api/api-extensions.ts b/packages/vendure-plugin-accept-blue/src/api/api-extensions.ts index f905ba38..43d47776 100644 --- a/packages/vendure-plugin-accept-blue/src/api/api-extensions.ts +++ b/packages/vendure-plugin-accept-blue/src/api/api-extensions.ts @@ -6,7 +6,7 @@ const _codegenAdditions = gql` scalar JSON `; -export const commonApiExtensions = gql` +const commonApiExtensions = gql` enum AcceptBlueSubscriptionInterval { week month @@ -118,6 +118,37 @@ export const commonApiExtensions = gql` savedAcceptBluePaymentMethods: [AcceptBluePaymentMethod!]! } + enum AcceptBlueFrequencyInput { + daily + weekly + biweekly + monthly + bimonthly + quarterly + biannually + annually + } + + input UpdateAcceptBlueSubscriptionInput { + id: Int! + title: String + frequency: AcceptBlueFrequencyInput + """ + Amount in cents to bill customer + """ + amount: Int + nextRunDate: DateTime + """ + Number of times the schedule has left to bill. Set to 0 for ongoing + """ + numLeft: Int + active: Boolean + """ + An email address to send a customer receipt to each time the schedule runs + """ + receiptEmail: String + } + extend type Query { previewAcceptBlueSubscriptions( productVariantId: ID! @@ -128,12 +159,30 @@ export const commonApiExtensions = gql` customInputs: JSON ): [AcceptBlueSubscription!]! } +`; + +export const shopApiExtensions = gql` + ${commonApiExtensions} +`; + +export const adminApiExtensions = gql` + ${commonApiExtensions} extend type Mutation { + """ + Refund a transaction by ID + """ refundAcceptBlueTransaction( transactionId: Int! amount: Int cvv2: String ): AcceptBlueRefundResult! + + """ + Update the given subscription in Accept Blue + """ + updateAcceptBlueSubscription( + input: UpdateAcceptBlueSubscriptionInput! + ): AcceptBlueSubscription! } `; diff --git a/packages/vendure-plugin-accept-blue/src/events/accept-blue-subscription-event.ts b/packages/vendure-plugin-accept-blue/src/events/accept-blue-subscription-event.ts new file mode 100644 index 00000000..6424587d --- /dev/null +++ b/packages/vendure-plugin-accept-blue/src/events/accept-blue-subscription-event.ts @@ -0,0 +1,19 @@ +import { RequestContext, VendureEvent } from '@vendure/core'; +import { + AcceptBlueSubscription, + UpdateAcceptBlueSubscriptionInput, +} from '../api/generated/graphql'; + +/** + * This event is fired when a subscription (schedule) has been updated in Accept Blue via the graphql API. + */ +export class AcceptBlueSubscriptionEvent extends VendureEvent { + constructor( + ctx: RequestContext, + public subscription: AcceptBlueSubscription, + public type: 'created' | 'updated' | 'deleted', + public input?: UpdateAcceptBlueSubscriptionInput + ) { + super(); + } +} diff --git a/packages/vendure-plugin-accept-blue/src/api/accept-blue-transaction-event.ts b/packages/vendure-plugin-accept-blue/src/events/accept-blue-transaction-event.ts similarity index 100% rename from packages/vendure-plugin-accept-blue/src/api/accept-blue-transaction-event.ts rename to packages/vendure-plugin-accept-blue/src/events/accept-blue-transaction-event.ts diff --git a/packages/vendure-plugin-accept-blue/src/index.ts b/packages/vendure-plugin-accept-blue/src/index.ts index e5031dc2..21ce1315 100644 --- a/packages/vendure-plugin-accept-blue/src/index.ts +++ b/packages/vendure-plugin-accept-blue/src/index.ts @@ -4,7 +4,8 @@ export * from '../../util/src/subscription/subscription-helper'; export * from './accept-blue-plugin'; export * from './api/accept-blue-service'; export * from './api/accept-blue-client'; -export * from './api/accept-blue-transaction-event'; +export * from './events/accept-blue-transaction-event'; +export * from './events/accept-blue-subscription-event'; export * from './api/accept-blue-handler'; export * from './api/accept-blue-common-resolvers'; export * from './api/custom-field-types'; diff --git a/packages/vendure-plugin-accept-blue/src/types.ts b/packages/vendure-plugin-accept-blue/src/types.ts index d82e4529..a9a32ba4 100644 --- a/packages/vendure-plugin-accept-blue/src/types.ts +++ b/packages/vendure-plugin-accept-blue/src/types.ts @@ -264,7 +264,10 @@ export interface AcceptBlueRecurringSchedule { transaction_count: number; } -export interface AcceptBlueRecurringScheduleInput { +/** + * Input type for creating a new recurring schedule + */ +export interface AcceptBlueRecurringScheduleCreateInput { title: string; amount: number; payment_method_id: number; @@ -275,6 +278,19 @@ export interface AcceptBlueRecurringScheduleInput { receipt_email?: string; use_this_source_key?: boolean; } +/** + * Input type for updating an existing recurring schedule + */ +export interface AcceptBlueRecurringScheduleUpdateInput { + title?: string; + amount?: number; + payment_method_id?: number; + frequency?: Frequency; + next_run_date?: Date; + num_left?: number; + active?: boolean; + receipt_email?: string; +} export interface AcceptBlueRecurringScheduleTransaction { id: number; diff --git a/packages/vendure-plugin-accept-blue/test/accept-blue.spec.ts b/packages/vendure-plugin-accept-blue/test/accept-blue.spec.ts index 69a19156..a297e7c8 100644 --- a/packages/vendure-plugin-accept-blue/test/accept-blue.spec.ts +++ b/packages/vendure-plugin-accept-blue/test/accept-blue.spec.ts @@ -25,7 +25,7 @@ import { } from '@vendure/testing'; import { afterEach, beforeAll, describe, expect, it } from 'vitest'; import { initialData } from '../../test/src/initial-data'; -import { AcceptBluePlugin } from '../src'; +import { AcceptBluePlugin, AcceptBlueSubscriptionEvent } from '../src'; import { AcceptBlueClient } from '../src/api/accept-blue-client'; import { acceptBluePaymentHandler } from '../src/api/accept-blue-handler'; import { DataSource } from 'typeorm'; @@ -41,6 +41,7 @@ import { ADD_PAYMENT_TO_ORDER, CREATE_PAYMENT_METHOD, GET_CUSTOMER_WITH_ID, + GET_HISTORY_ENTRIES, GET_ORDER_BY_CODE, GET_USER_SAVED_PAYMENT_METHOD, PREVIEW_SUBSCRIPTIONS_FOR_PRODUCT, @@ -48,7 +49,7 @@ import { REFUND_TRANSACTION, SET_SHIPPING_METHOD, TRANSITION_ORDER_TO, - UPDATE_CUSTOMER_BLUE_ID, + UPDATE_SUBSCRIPTION, } from './helpers/graphql-helpers'; import { checkChargeResult, @@ -60,7 +61,12 @@ import { createMockWebhook, createSignature, } from './helpers/mocks'; -import { AcceptBlueTransactionEvent } from '../src/api/accept-blue-transaction-event'; +import { AcceptBlueTransactionEvent } from '../src/events/accept-blue-transaction-event'; +import { + AcceptBlueSubscription, + MutationUpdateAcceptBlueSubscriptionArgs, + UpdateAcceptBlueSubscriptionInput, +} from '../src/api/generated/graphql'; let server: TestServer; let adminClient: SimpleGraphQLClient; @@ -457,7 +463,7 @@ describe('Payment with Saved Payment Method', () => { }); }); -describe('Refunds and transactions', () => { +describe('Transactions', () => { let orderLineWithSubscription: OrderLine; it('Emits transaction event for incoming schedule payments webhook', async () => { @@ -536,8 +542,11 @@ describe('Refunds and transactions', () => { expect(transaction.cardDetails).toBeDefined(); expect(transaction.amount).toBeDefined(); }); +}); +describe('Admin API', () => { it('Refunds a transaction', async () => { + await adminClient.asSuperAdmin(); let refundRequest: any; nockInstance .post(`/transactions/refund`, (body) => { @@ -552,7 +561,7 @@ describe('Refunds and transactions', () => { error_details: { detail: 'An error detail object' }, reference_number: 123, }); - const { refundAcceptBlueTransaction } = await shopClient.query( + const { refundAcceptBlueTransaction } = await adminClient.query( REFUND_TRANSACTION, { transactionId: 123, @@ -574,10 +583,10 @@ describe('Refunds and transactions', () => { }); it('Fails to refund when not logged in', async () => { - await shopClient.asAnonymousUser(); + await adminClient.asAnonymousUser(); let error: any; try { - await shopClient.query(REFUND_TRANSACTION, { + await adminClient.query(REFUND_TRANSACTION, { transactionId: 123, amount: 4567, cvv2: '999', @@ -587,10 +596,6 @@ describe('Refunds and transactions', () => { } expect(error?.response?.errors?.[0]?.extensions.code).toEqual('FORBIDDEN'); }); -}); - -describe('Admin API', () => { - // Just smoke test 1 call, so we know resolvers and schema are also loaded for admin API it('Gets saved payment methods for customer', async () => { nockInstance @@ -599,9 +604,89 @@ describe('Admin API', () => { `/customers/${haydenZiemeCustomerDetails.id}/payment-methods?limit=100` ) .reply(200, haydenSavedPaymentMethods); + await adminClient.asSuperAdmin(); const { customer } = await adminClient.query(GET_CUSTOMER_WITH_ID, { id: '1', }); expect(customer?.savedAcceptBluePaymentMethods?.length).toBeGreaterThan(0); }); + + it('Does not allow updating subscriptions by unauthorized admins', async () => { + await adminClient.asAnonymousUser(); + const updateRequest = adminClient.query< + { updateAcceptBlueSubscription: AcceptBlueSubscription }, + MutationUpdateAcceptBlueSubscriptionArgs + >(UPDATE_SUBSCRIPTION, { + input: { + id: 123, + active: false, + }, + }); + await expect(updateRequest).rejects.toThrowError( + 'You are not currently authorized to perform this action' + ); + }); + + const events: AcceptBlueSubscriptionEvent[] = []; + + it('Updates a subscription', async () => { + server.app + .get(EventBus) + .ofType(AcceptBlueSubscriptionEvent) + .subscribe((event) => events.push(event)); + await adminClient.asSuperAdmin(); + const scheduleId = 6014; // This ID was created earlier in test, and added to an order + let updateRequest: any; + nockInstance + .persist() + .patch(`/recurring-schedules/${scheduleId}`, (body) => { + updateRequest = body; + return true; + }) + .reply(200, createMockRecurringScheduleResult(scheduleId)); + const tenDaysFromNow = new Date(); + tenDaysFromNow.setDate(tenDaysFromNow.getDate() + 10); + await adminClient.query( + UPDATE_SUBSCRIPTION, + { + input: { + id: scheduleId, + amount: 4321, + active: false, + frequency: 'biannually', + nextRunDate: tenDaysFromNow, + numLeft: 5, + title: 'Updated title', + receiptEmail: 'newCustomer@pinelab.studio', + }, + } + ); + expect(updateRequest).toEqual({ + active: false, + title: 'Updated title', + amount: 43.21, + frequency: 'biannually', + next_run_date: tenDaysFromNow.toISOString().substring(0, 10), // Take yyyy-mm-dd + num_left: 5, + receipt_email: 'newCustomer@pinelab.studio', + }); + }); + + it('Has created history entries', async () => { + await adminClient.asSuperAdmin(); + const { order } = await adminClient.query(GET_HISTORY_ENTRIES, { + id: placedOrder?.id, + }); + const entry = order.history.items.find( + (entry: any) => entry.type === 'ORDER_NOTE' + ); + expect(entry?.data.note).toContain('Subscription updated:'); + }); + + it('Has published Subscription Event', async () => { + const event = events[0]; + expect(events.length).toBe(1); + expect(event.subscription.id).toBe(6014); + expect(event.type).toBe('updated'); + }); }); diff --git a/packages/vendure-plugin-accept-blue/test/helpers/graphql-helpers.ts b/packages/vendure-plugin-accept-blue/test/helpers/graphql-helpers.ts index 72068142..40edf9b3 100644 --- a/packages/vendure-plugin-accept-blue/test/helpers/graphql-helpers.ts +++ b/packages/vendure-plugin-accept-blue/test/helpers/graphql-helpers.ts @@ -169,6 +169,22 @@ export const GET_ORDER_BY_CODE = gql` } `; +export const GET_HISTORY_ENTRIES = gql` + query GetHistoryEntries($id: ID!) { + order(id: $id) { + id + code + history { + items { + id + type + data + } + } + } + } +`; + export const SET_SHIPPING_METHOD = gql` mutation SetShippingMethod($id: [ID!]!) { setOrderShippingMethod(shippingMethodId: $id) { @@ -223,20 +239,19 @@ export const GET_CUSTOMER_WITH_ID = gql` ${ACCEPT_BLUE_PAYMENT_METHOD_FRAGMENT} `; -export const UPDATE_CUSTOMER_BLUE_ID = gql` - mutation UpdateCustomer($customerId: ID!, $acceptBlueCustomerId: Int!) { - updateCustomer( - input: { - id: $customerId - customFields: { acceptBlueCustomerId: $acceptBlueCustomerId } - } - ) { - ... on Customer { - id - emailAddress - } - ... on ErrorResult { - message +export const UPDATE_SUBSCRIPTION = gql` + mutation UpdateSubscription($input: UpdateAcceptBlueSubscriptionInput!) { + updateAcceptBlueSubscription(input: $input) { + name + variantId + amountDueNow + priceIncludesTax + recurring { + amount + interval + intervalCount + startDate + endDate } } }