diff --git a/apps/reaction/package.json b/apps/reaction/package.json index a1b05d2c2d1..2577a8a4d9f 100644 --- a/apps/reaction/package.json +++ b/apps/reaction/package.json @@ -32,8 +32,6 @@ "@reactioncommerce/api-plugin-bull-queue": "0.0.0", "@reactioncommerce/api-plugin-carts": "1.3.5", "@reactioncommerce/api-plugin-catalogs": "1.1.2", - "@reactioncommerce/api-plugin-discounts": "1.0.4", - "@reactioncommerce/api-plugin-discounts-codes": "1.2.4", "@reactioncommerce/api-plugin-email": "1.1.5", "@reactioncommerce/api-plugin-email-smtp": "1.0.8", "@reactioncommerce/api-plugin-email-templates": "1.1.7", diff --git a/apps/reaction/plugins.json b/apps/reaction/plugins.json index c42312babb8..073752344dc 100644 --- a/apps/reaction/plugins.json +++ b/apps/reaction/plugins.json @@ -26,8 +26,6 @@ "payments": "@reactioncommerce/api-plugin-payments", "paymentsStripeSCA": "@reactioncommerce/api-plugin-payments-stripe-sca", "paymentsExample": "@reactioncommerce/api-plugin-payments-example", - "discounts": "@reactioncommerce/api-plugin-discounts", - "discountCodes": "@reactioncommerce/api-plugin-discounts-codes", "surcharges": "@reactioncommerce/api-plugin-surcharges", "shipments": "@reactioncommerce/api-plugin-shipments", "shipmentsFlatRate": "@reactioncommerce/api-plugin-shipments-flat-rate", diff --git a/apps/reaction/tests/integration/api/mutations/discountCodes/createDiscountCodeMutation.graphql b/apps/reaction/tests/integration/api/mutations/discountCodes/createDiscountCodeMutation.graphql deleted file mode 100644 index e0eb3476ff1..00000000000 --- a/apps/reaction/tests/integration/api/mutations/discountCodes/createDiscountCodeMutation.graphql +++ /dev/null @@ -1,44 +0,0 @@ -mutation ( - $shopId: ID!, - $discountCode: DiscountCodeInput! -) { - createDiscountCode(input: { - shopId: $shopId - discountCode: $discountCode - }) { - discountCode { - _id - shop { - _id - } - code - label - description - discountMethod - discount - transactions { - cartId - userId - appliedAt - } - calculation { - method - } - conditions { - accountLimit - audience - enabled - permissions - redemptionLimit - order { - min - max - startDate - endDate - } - products - tags - } - } - } -} \ No newline at end of file diff --git a/apps/reaction/tests/integration/api/mutations/discountCodes/deleteDiscountCodeMutation.graphql b/apps/reaction/tests/integration/api/mutations/discountCodes/deleteDiscountCodeMutation.graphql deleted file mode 100644 index 785b8b71e4d..00000000000 --- a/apps/reaction/tests/integration/api/mutations/discountCodes/deleteDiscountCodeMutation.graphql +++ /dev/null @@ -1,44 +0,0 @@ -mutation ( - $discountCodeId: ID!, - $shopId: ID!, -) { - deleteDiscountCode(input: { - discountCodeId: $discountCodeId - shopId: $shopId - }) { - discountCode { - _id - shop { - _id - } - code - label - description - discountMethod - discount - transactions { - cartId - userId - appliedAt - } - calculation { - method - } - conditions { - accountLimit - audience - enabled - permissions - redemptionLimit - order { - min - max - startDate - endDate - } - products - tags - } - } - } -} \ No newline at end of file diff --git a/apps/reaction/tests/integration/api/mutations/discountCodes/discountCodes.test.js b/apps/reaction/tests/integration/api/mutations/discountCodes/discountCodes.test.js deleted file mode 100644 index 4bc3d438830..00000000000 --- a/apps/reaction/tests/integration/api/mutations/discountCodes/discountCodes.test.js +++ /dev/null @@ -1,300 +0,0 @@ -import encodeOpaqueId from "@reactioncommerce/api-utils/encodeOpaqueId.js"; -import decodeOpaqueIdForNamespace from "@reactioncommerce/api-utils/decodeOpaqueIdForNamespace.js"; -import importAsString from "@reactioncommerce/api-utils/importAsString.js"; -import insertPrimaryShop from "@reactioncommerce/api-utils/tests/insertPrimaryShop.js"; -import Factory from "/tests/util/factory.js"; -import { importPluginsJSONFile, ReactionTestAPICore } from "@reactioncommerce/api-core"; - -const createDiscountCodeMutation = importAsString("./createDiscountCodeMutation.graphql"); -const updateDiscountCodeMutation = importAsString("./updateDiscountCodeMutation.graphql"); -const deleteDiscountCodeMutation = importAsString("./deleteDiscountCodeMutation.graphql"); - -jest.setTimeout(300000); - -let createDiscountCode; -let mockAdminAccount; -let deleteDiscountCode; -let shopId; -let shopOpaqueId; -let testApp; -let discountCodeOpaqueId; -let updateDiscountCode; - -beforeAll(async () => { - testApp = new ReactionTestAPICore(); - const plugins = await importPluginsJSONFile("../../../../../plugins.json", (pluginList) => { - // Remove the `files` plugin when testing. Avoids lots of errors. - delete pluginList.files; - - return pluginList; - }); - await testApp.reactionNodeApp.registerPlugins(plugins); - await testApp.start(); - shopId = await insertPrimaryShop(testApp.context); - - const adminGroup = Factory.Group.makeOne({ - _id: "adminGroup", - createdBy: null, - name: "admin", - permissions: ["reaction:legacy:discounts/create", "reaction:legacy:discounts/delete", "reaction:legacy:discounts/read", "reaction:legacy:discounts/update"], - slug: "admin", - shopId - }); - await testApp.collections.Groups.insertOne(adminGroup); - - createDiscountCode = testApp.mutate(createDiscountCodeMutation); - updateDiscountCode = testApp.mutate(updateDiscountCodeMutation); - deleteDiscountCode = testApp.mutate(deleteDiscountCodeMutation); - - mockAdminAccount = Factory.Account.makeOne({ - _id: "mockAdminAccount", - groups: [adminGroup._id], - shopId - }); - await testApp.createUserAndAccount(mockAdminAccount); - - shopOpaqueId = encodeOpaqueId("reaction/shop", shopId); -}); - -// There is no need to delete any test data from collections because -// testApp.stop() will drop the entire test database. Each integration -// test file gets its own test database. -afterAll(() => testApp.stop()); - -test("user can add a discount code", async () => { - await testApp.setLoggedInUser(mockAdminAccount); - - const discountCodeInput = { - shopId: shopOpaqueId, - discountCode: { - code: "25OFF", - label: "25% Off", - description: "Take 25% on all orders under $400", - discount: "0.25", - discountMethod: "code", - calculation: { - method: "discount" - }, - conditions: { - accountLimit: 1, - order: { - min: 0.00, - max: 400.00, - startDate: "2019-11-14T18:30:03.658Z", - endDate: "2021-01-01T08:00:00.000Z" - }, - redemptionLimit: 0, - audience: ["customer"], - permissions: ["guest", "anonymous"], - products: ["product-id"], - tags: ["tag-id"], - enabled: true - }, - transactions: [{ - cartId: "cart-id", - userId: "user-id", - appliedAt: "2019-11-18T18:30:03.658Z" - }] - } - }; - - let result; - try { - result = await createDiscountCode(discountCodeInput); - } catch (error) { - expect(error).toBeUndefined(); - return; - } - - const { _id: createdDiscountCodeOpaqueId, ...createdDiscountCode } = result.createDiscountCode.discountCode; - - // Save this for the next tests for updating and deleting; - discountCodeOpaqueId = createdDiscountCodeOpaqueId; - - // Validate the response - // _id is omitted since the ID is tested for proper opaque ID conversion in the DB test below. - const expectedDiscountCodeResponse = { - shop: { - _id: shopOpaqueId - }, - code: "25OFF", - label: "25% Off", - description: "Take 25% on all orders under $400", - discount: "0.25", - discountMethod: "code", - calculation: { - method: "discount" - }, - conditions: { - accountLimit: 1, - order: { - min: 0.00, - max: 400.00, - startDate: "2019-11-14T18:30:03.658Z", - endDate: "2021-01-01T08:00:00.000Z" - }, - redemptionLimit: 0, - audience: ["customer"], - permissions: ["guest", "anonymous"], - products: ["product-id"], - tags: ["tag-id"], - enabled: true - }, - transactions: [{ - cartId: "cart-id", - userId: "user-id", - appliedAt: "2019-11-18T18:30:03.658Z" - }] - }; - - expect(createdDiscountCode).toEqual(expectedDiscountCodeResponse); -}); - -test("user can update an existing discount code", async () => { - await testApp.setLoggedInUser(mockAdminAccount); - - const discountCodeInput = { - discountCodeId: discountCodeOpaqueId, - shopId: shopOpaqueId, - discountCode: { - code: "50OFF", - label: "50% Off", - description: "Take 50% on all orders over $100", - discount: "0.50", - discountMethod: "code", - calculation: { - method: "discount" - }, - conditions: { - accountLimit: 1, - order: { - min: 100.00, - startDate: "2019-11-14T18:30:03.658Z", - endDate: "2021-01-01T08:00:00.000Z" - }, - redemptionLimit: 0, - audience: ["customer"], - permissions: ["guest", "anonymous"], - products: ["product-id"], - tags: ["tag-id"], - enabled: true - } - } - }; - - let result; - try { - result = await updateDiscountCode(discountCodeInput); - } catch (error) { - expect(error).toBeUndefined(); - return; - } - - const { _id: updatedDiscountCodeOpaqueId, ...updatedDiscountCode } = result.updateDiscountCode.discountCode; - - // Validate the response - // _id is omitted since the ID is tested for proper opaque ID conversion in the DB test below. - const expectedDiscountCodeResponse = { - shop: { - _id: shopOpaqueId - }, - code: "50OFF", - label: "50% Off", - description: "Take 50% on all orders over $100", - discount: "0.50", - discountMethod: "code", - calculation: { - method: "discount" - }, - conditions: { - accountLimit: 1, - order: { - min: 100.00, - max: null, - startDate: "2019-11-14T18:30:03.658Z", - endDate: "2021-01-01T08:00:00.000Z" - }, - redemptionLimit: 0, - audience: ["customer"], - permissions: ["guest", "anonymous"], - products: ["product-id"], - tags: ["tag-id"], - enabled: true - }, - transactions: [{ - cartId: "cart-id", - userId: "user-id", - appliedAt: "2019-11-18T18:30:03.658Z" - }] - }; - - expect(updatedDiscountCode).toEqual(expectedDiscountCodeResponse); -}); - -test("user can delete an existing discount code", async () => { - await testApp.setLoggedInUser(mockAdminAccount); - - const discountCodeInput = { - discountCodeId: discountCodeOpaqueId, - shopId: shopOpaqueId - }; - - let result; - try { - result = await deleteDiscountCode(discountCodeInput); - } catch (error) { - expect(error).toBeUndefined(); - return; - } - - const { _id: deletedDiscountCodeOpaqueId, ...deletedDiscountCode } = result.deleteDiscountCode.discountCode; - - // Validate the response - // _id is omitted since the ID is tested for proper opaque ID conversion in the DB test below. - const expectedDiscountCodeResponse = { - shop: { - _id: shopOpaqueId - }, - code: "50OFF", - label: "50% Off", - description: "Take 50% on all orders over $100", - discount: "0.50", - discountMethod: "code", - calculation: { - method: "discount" - }, - conditions: { - accountLimit: 1, - order: { - min: 100.00, - max: null, - startDate: "2019-11-14T18:30:03.658Z", - endDate: "2021-01-01T08:00:00.000Z" - }, - redemptionLimit: 0, - audience: ["customer"], - permissions: ["guest", "anonymous"], - products: ["product-id"], - tags: ["tag-id"], - enabled: true - }, - transactions: [{ - cartId: "cart-id", - userId: "user-id", - appliedAt: "2019-11-18T18:30:03.658Z" - }] - }; - - expect(deletedDiscountCode).toEqual(expectedDiscountCodeResponse); - - // Check the database for the deleted DiscountCode document - const deletedDiscountCodeDatabaseId = decodeOpaqueIdForNamespace("reaction/discount")(deletedDiscountCodeOpaqueId); - - const removedDiscountCode = await testApp.collections.Discounts.findOne({ - _id: deletedDiscountCodeDatabaseId, - shopId - }); - - // Expect the discount code to be removed from the database - expect(removedDiscountCode).toBeNull(); -}); diff --git a/apps/reaction/tests/integration/api/mutations/discountCodes/updateDiscountCodeMutation.graphql b/apps/reaction/tests/integration/api/mutations/discountCodes/updateDiscountCodeMutation.graphql deleted file mode 100644 index b5f83aa4981..00000000000 --- a/apps/reaction/tests/integration/api/mutations/discountCodes/updateDiscountCodeMutation.graphql +++ /dev/null @@ -1,46 +0,0 @@ -mutation ( - $discountCodeId: ID!, - $shopId: ID!, - $discountCode: DiscountCodeInput! -) { - updateDiscountCode(input: { - discountCodeId: $discountCodeId - shopId: $shopId - discountCode: $discountCode - }) { - discountCode { - _id - shop { - _id - } - code - label - description - discountMethod - discount - transactions { - cartId - userId - appliedAt - } - calculation { - method - } - conditions { - accountLimit - audience - enabled - permissions - redemptionLimit - order { - min - max - startDate - endDate - } - products - tags - } - } - } -} \ No newline at end of file diff --git a/apps/reaction/tests/integration/api/queries/discountCodes/__snapshots__/discountCodes.test.js.snap b/apps/reaction/tests/integration/api/queries/discountCodes/__snapshots__/discountCodes.test.js.snap deleted file mode 100644 index 1e10d1827b0..00000000000 --- a/apps/reaction/tests/integration/api/queries/discountCodes/__snapshots__/discountCodes.test.js.snap +++ /dev/null @@ -1,26 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`throws access-denied when getting discount codes if not an admin 1`] = ` -Object { - "extensions": Object { - "code": "FORBIDDEN", - "exception": Object { - "details": Object {}, - "error": "access-denied", - "eventData": Object {}, - "isClientSafe": true, - "reason": "Access Denied", - }, - }, - "locations": Array [ - Object { - "column": 3, - "line": 2, - }, - ], - "message": "Access Denied", - "path": Array [ - "discountCodes", - ], -} -`; diff --git a/apps/reaction/tests/integration/api/queries/discountCodes/discountCodes.test.js b/apps/reaction/tests/integration/api/queries/discountCodes/discountCodes.test.js deleted file mode 100644 index 12aba9d475b..00000000000 --- a/apps/reaction/tests/integration/api/queries/discountCodes/discountCodes.test.js +++ /dev/null @@ -1,150 +0,0 @@ -import importAsString from "@reactioncommerce/api-utils/importAsString.js"; -import insertPrimaryShop from "@reactioncommerce/api-utils/tests/insertPrimaryShop.js"; -import Factory from "/tests/util/factory.js"; -import { importPluginsJSONFile, ReactionTestAPICore } from "@reactioncommerce/api-core"; - -const discountCodesQuery = importAsString("./discountCodesQuery.graphql"); - -jest.setTimeout(300000); - -const internalShopId = "123"; -const opaqueShopId = "cmVhY3Rpb24vc2hvcDoxMjM="; // reaction/shop:123 -const shopName = "Test Shop"; -const discountCodeDocuments = []; - -for (let index = 10; index < 25; index += 1) { - const doc = Factory.Discounts.makeOne({ - _id: `discountCode-${index}`, - shopId: internalShopId, - code: `${index}OFF`, - label: `${index} Off`, - description: `Take $${index} off on all orders over $${index}`, - discount: `${index}`, - discountMethod: "code", - calculation: { - method: "discount" - }, - conditions: { - accountLimit: 1, - order: { - min: index, - startDate: "2019-11-14T18:30:03.658Z", - endDate: "2021-01-01T08:00:00.000Z" - }, - redemptionLimit: 0, - audience: ["customer"], - permissions: ["guest", "anonymous"], - products: ["product-id"], - tags: ["tag-id"], - enabled: true - }, - transactions: [{ - cartId: "cart-id", - userId: "user-id", - appliedAt: "2019-11-18T18:30:03.658Z" - }] - }); - - discountCodeDocuments.push(doc); -} - -const adminGroup = Factory.Group.makeOne({ - _id: "adminGroup", - createdBy: null, - name: "admin", - permissions: ["reaction:legacy:discounts/read"], - slug: "admin", - shopId: internalShopId -}); - -const customerGroup = Factory.Group.makeOne({ - _id: "customerGroup", - createdBy: null, - name: "customer", - permissions: ["customer"], - slug: "customer", - shopId: internalShopId -}); - -const mockAdminAccount = Factory.Account.makeOne({ - groups: [adminGroup._id], - shopId: internalShopId -}); - -const mockCustomerAccount = Factory.Account.makeOne({ - groups: [customerGroup._id], - shopId: internalShopId -}); - -let testApp; -let discountCodes; - -beforeAll(async () => { - testApp = new ReactionTestAPICore(); - const plugins = await importPluginsJSONFile("../../../../../plugins.json", (pluginList) => { - // Remove the `files` plugin when testing. Avoids lots of errors. - delete pluginList.files; - - return pluginList; - }); - await testApp.reactionNodeApp.registerPlugins(plugins); - await testApp.start(); - - await insertPrimaryShop(testApp.context, { _id: internalShopId, name: shopName }); - - await Promise.all(discountCodeDocuments.map((doc) => ( - testApp.collections.Discounts.insertOne(doc) - ))); - - await testApp.collections.Groups.insertOne(adminGroup); - await testApp.collections.Groups.insertOne(customerGroup); - - await testApp.createUserAndAccount(mockCustomerAccount); - await testApp.createUserAndAccount(mockAdminAccount); - - discountCodes = testApp.query(discountCodesQuery); -}); - -// There is no need to delete any test data from collections because -// testApp.stop() will drop the entire test database. Each integration -// test file gets its own test database. -afterAll(() => testApp.stop()); - -test("throws access-denied when getting discount codes if not an admin", async () => { - await testApp.setLoggedInUser(mockCustomerAccount); - - try { - await discountCodes({ - shopId: opaqueShopId - }); - } catch (errors) { - expect(errors[0]).toMatchSnapshot(); - } -}); - -test("returns discount records if user is an admin", async () => { - await testApp.setLoggedInUser(mockAdminAccount); - - const result = await discountCodes({ - shopId: opaqueShopId, - first: 5, - offset: 0 - }); - expect(result.discountCodes.nodes.length).toEqual(5); - expect(result.discountCodes.nodes[0].code).toEqual("10OFF"); - expect(result.discountCodes.nodes[4].code).toEqual("14OFF"); -}); - - -test("returns discount records on second page if user is an admin", async () => { - await testApp.setLoggedInUser(mockAdminAccount); - - const result = await discountCodes({ - shopId: opaqueShopId, - first: 5, - offset: 5 - }); - expect(result.discountCodes.nodes.length).toEqual(5); - expect(result.discountCodes.nodes[0].code).toEqual("15OFF"); - expect(result.discountCodes.nodes[4].code).toEqual("19OFF"); -}); diff --git a/apps/reaction/tests/integration/api/queries/discountCodes/discountCodesQuery.graphql b/apps/reaction/tests/integration/api/queries/discountCodes/discountCodesQuery.graphql deleted file mode 100644 index 9172094d691..00000000000 --- a/apps/reaction/tests/integration/api/queries/discountCodes/discountCodesQuery.graphql +++ /dev/null @@ -1,52 +0,0 @@ -query discountCodes( - $shopId: ID!, - $first: ConnectionLimitInt, - $last: ConnectionLimitInt, - $before: ConnectionCursor, - $after: ConnectionCursor, - $offset: Int -) { - discountCodes( - shopId: $shopId, - first: $first, - last: $last, - before: $before, - after: $after, - offset: $offset - ) { - nodes { - _id - shop { - _id - } - code - label - description - discountMethod - discount - transactions { - cartId - userId - appliedAt - } - calculation { - method - } - conditions { - accountLimit - audience - enabled - permissions - redemptionLimit - order { - min - max - startDate - endDate - } - products - tags - } - } - } -} \ No newline at end of file diff --git a/apps/reaction/tests/util/factory.js b/apps/reaction/tests/util/factory.js index fd1521fa87d..9e264c3c1ce 100644 --- a/apps/reaction/tests/util/factory.js +++ b/apps/reaction/tests/util/factory.js @@ -26,10 +26,6 @@ import { CatalogProductVariant } from "@reactioncommerce/api-plugin-catalogs/src/simpleSchemas.js"; -import { - DiscountCodes -} from "@reactioncommerce/api-plugin-discounts-codes/src/simpleSchemas.js"; - import { EmailTemplates } from "@reactioncommerce/api-plugin-email-templates/src/simpleSchemas.js"; @@ -119,7 +115,6 @@ const schemasToAddToFactory = { CatalogProductVariant, CommonOrder, CommonOrderItem, - Discounts: DiscountCodes, Email, EmailTemplates, FulfillmentMethod, diff --git a/packages/api-plugin-discounts-codes/README.md b/packages/api-plugin-discounts-codes/README.md index d8111a2ed59..7a0ff81aa17 100644 --- a/packages/api-plugin-discounts-codes/README.md +++ b/packages/api-plugin-discounts-codes/README.md @@ -3,6 +3,9 @@ [![npm (scoped)](https://img.shields.io/npm/v/@reactioncommerce/api-plugin-discounts-codes.svg)](https://www.npmjs.com/package/@reactioncommerce/api-plugin-discounts-codes) [![CircleCI](https://circleci.com/gh/reactioncommerce/api-plugin-discounts-codes.svg?style=svg)](https://circleci.com/gh/reactioncommerce/api-plugin-discounts-codes) +## This repository is deprecated +This plugin is deprecated and will be removed in a future release. Please use the `@reactioncommetce/api-plugin-promotions` plugin instead. + ## Summary Discount Codes plugin for the Reaction API diff --git a/packages/api-plugin-discounts/README.md b/packages/api-plugin-discounts/README.md index b10022a405f..70d67284b19 100644 --- a/packages/api-plugin-discounts/README.md +++ b/packages/api-plugin-discounts/README.md @@ -3,6 +3,8 @@ [![npm (scoped)](https://img.shields.io/npm/v/@reactioncommerce/api-plugin-discounts.svg)](https://www.npmjs.com/package/@reactioncommerce/api-plugin-discounts) [![CircleCI](https://circleci.com/gh/reactioncommerce/api-plugin-discounts.svg?style=svg)](https://circleci.com/gh/reactioncommerce/api-plugin-discounts) +## This repository is deprecated +This plugin is deprecated and will be removed in a future release. Please use the `@reactioncommetce/api-plugin-promotions` plugin instead. ## Summary Discounts plugin for the [Reaction API](https://github.com/reactioncommerce/reaction) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 78aa3b247c0..ffbc685e6bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,8 +151,6 @@ importers: '@reactioncommerce/api-plugin-bull-queue': 0.0.0 '@reactioncommerce/api-plugin-carts': 1.3.5 '@reactioncommerce/api-plugin-catalogs': 1.1.2 - '@reactioncommerce/api-plugin-discounts': 1.0.4 - '@reactioncommerce/api-plugin-discounts-codes': 1.2.4 '@reactioncommerce/api-plugin-email': 1.1.5 '@reactioncommerce/api-plugin-email-smtp': 1.0.8 '@reactioncommerce/api-plugin-email-templates': 1.1.7 @@ -217,8 +215,6 @@ importers: '@reactioncommerce/api-plugin-bull-queue': link:../../packages/api-plugin-bull-queue '@reactioncommerce/api-plugin-carts': link:../../packages/api-plugin-carts '@reactioncommerce/api-plugin-catalogs': link:../../packages/api-plugin-catalogs - '@reactioncommerce/api-plugin-discounts': link:../../packages/api-plugin-discounts - '@reactioncommerce/api-plugin-discounts-codes': link:../../packages/api-plugin-discounts-codes '@reactioncommerce/api-plugin-email': link:../../packages/api-plugin-email '@reactioncommerce/api-plugin-email-smtp': link:../../packages/api-plugin-email-smtp '@reactioncommerce/api-plugin-email-templates': link:../../packages/api-plugin-email-templates