Skip to content

Commit 9e145bf

Browse files
feat(loyalty-plugin,medusa,utils): open source loyalty plugin (#14711)
* Port over loyalty plugin to core plugins and make it default * Add changeset * Update zod imports * Fix query keys * Update tests * Include loyalty plugin dependency for tests * Add plugins build to artifacts * debug * debug * Include .medusa * Include .medusa/server * Resolve glob pattern ignoring hidden folders * Debug * Debug * Revert "Debug" This reverts commit 7ed5768. * Revert _medusa approach This reverts commit 95828aa. * Try only updating turbo * Update yarn.lock * Log before upload artifacts step * Add debug logs * Include medusa as dev dependency so plugin command doesn't fail * Try to resolve build dependency issues with turbo config * build plugins separetly * Verify if we need to manipulate .medusa to avoid glob bug * Cleanup * place plugin build inside cache-deps action like normal packages * Avoid releasing events in hooks workflow executions * Remove loyalty plugin from default plugins * Update changeset * Update deps * Update tests * Remove loyalty plugin from Medusa deps to fix github job * Update lock file * Update lock file * Update imports and upgrade to latest medusa * Fix --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
1 parent 84caf7c commit 9e145bf

370 files changed

Lines changed: 28748 additions & 34 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/humble-poets-juggle.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@medusajs/loyalty-plugin": minor
3+
"@medusajs/utils": patch
4+
"@medusajs/medusa": patch
5+
---
6+
7+
feat(loyalty-plugin,medusa,utils): open source loyalty plugin

.eslintrc.js

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const path = require("path");
1+
const path = require("path")
22

33
module.exports = {
44
root: true,
@@ -84,13 +84,22 @@ module.exports = {
8484
path.join(__dirname, "./packages/admin/admin-bundler/tsconfig.json"),
8585
path.join(__dirname, "./packages/admin/admin-sdk/tsconfig.json"),
8686
path.join(__dirname, "./packages/admin/admin-shared/tsconfig.json"),
87-
path.join(__dirname, "./packages/admin/admin-vite-plugin/tsconfig.json"),
87+
path.join(
88+
__dirname,
89+
"./packages/admin/admin-vite-plugin/tsconfig.json"
90+
),
8891
path.join(__dirname, "./packages/admin/dashboard/tsconfig.json"),
8992

90-
path.join(__dirname, "./packages/cli/create-medusa-app/tsconfig.json"),
93+
path.join(
94+
__dirname,
95+
"./packages/cli/create-medusa-app/tsconfig.json"
96+
),
9197
path.join(__dirname, "./packages/cli/medusa-cli/tsconfig.json"),
9298
path.join(__dirname, "./packages/cli/medusa-dev-cli/tsconfig.json"),
93-
path.join(__dirname, "./packages/cli/oas/medusa-oas-cli/tsconfig.json"),
99+
path.join(
100+
__dirname,
101+
"./packages/cli/oas/medusa-oas-cli/tsconfig.json"
102+
),
94103

95104
path.join(__dirname, "./packages/core/core-flows/tsconfig.json"),
96105
path.join(__dirname, "./packages/core/framework/tsconfig.json"),
@@ -104,9 +113,15 @@ module.exports = {
104113
path.join(__dirname, "./packages/deps/tsconfig.json"),
105114

106115
path.join(__dirname, "./packages/design-system/icons/tsconfig.json"),
107-
path.join(__dirname, "./packages/design-system/toolbox/tsconfig.json"),
116+
path.join(
117+
__dirname,
118+
"./packages/design-system/toolbox/tsconfig.json"
119+
),
108120
path.join(__dirname, "./packages/design-system/ui/tsconfig.json"),
109-
path.join(__dirname, "./packages/design-system/ui-preset/tsconfig.json"),
121+
path.join(
122+
__dirname,
123+
"./packages/design-system/ui-preset/tsconfig.json"
124+
),
110125

111126
path.join(__dirname, "./packages/medusa/tsconfig.json"),
112127

@@ -116,14 +131,23 @@ module.exports = {
116131
path.join(__dirname, "./packages/modules/analytics/tsconfig.json"),
117132
path.join(__dirname, "./packages/modules/api-key/tsconfig.json"),
118133
path.join(__dirname, "./packages/modules/auth/tsconfig.json"),
119-
path.join(__dirname, "./packages/modules/cache-inmemory/tsconfig.json"),
134+
path.join(
135+
__dirname,
136+
"./packages/modules/cache-inmemory/tsconfig.json"
137+
),
120138
path.join(__dirname, "./packages/modules/cache-redis/tsconfig.json"),
121139
path.join(__dirname, "./packages/modules/caching/tsconfig.json"),
122140
path.join(__dirname, "./packages/modules/cart/tsconfig.json"),
123141
path.join(__dirname, "./packages/modules/currency/tsconfig.json"),
124142
path.join(__dirname, "./packages/modules/customer/tsconfig.json"),
125-
path.join(__dirname, "./packages/modules/event-bus-local/tsconfig.json"),
126-
path.join(__dirname, "./packages/modules/event-bus-redis/tsconfig.json"),
143+
path.join(
144+
__dirname,
145+
"./packages/modules/event-bus-local/tsconfig.json"
146+
),
147+
path.join(
148+
__dirname,
149+
"./packages/modules/event-bus-redis/tsconfig.json"
150+
),
127151
path.join(__dirname, "./packages/modules/file/tsconfig.json"),
128152
path.join(__dirname, "./packages/modules/fulfillment/tsconfig.json"),
129153
path.join(__dirname, "./packages/modules/index/tsconfig.json"),
@@ -137,32 +161,87 @@ module.exports = {
137161
path.join(__dirname, "./packages/modules/product/tsconfig.json"),
138162
path.join(__dirname, "./packages/modules/promotion/tsconfig.json"),
139163
path.join(__dirname, "./packages/modules/region/tsconfig.json"),
140-
path.join(__dirname, "./packages/modules/sales-channel/tsconfig.json"),
164+
path.join(
165+
__dirname,
166+
"./packages/modules/sales-channel/tsconfig.json"
167+
),
141168
path.join(__dirname, "./packages/modules/settings/tsconfig.json"),
142-
path.join(__dirname, "./packages/modules/stock-location/tsconfig.json"),
169+
path.join(
170+
__dirname,
171+
"./packages/modules/stock-location/tsconfig.json"
172+
),
143173
path.join(__dirname, "./packages/modules/store/tsconfig.json"),
144174
path.join(__dirname, "./packages/modules/tax/tsconfig.json"),
145175
path.join(__dirname, "./packages/modules/translation/tsconfig.json"),
146176
path.join(__dirname, "./packages/modules/user/tsconfig.json"),
147-
path.join(__dirname, "./packages/modules/workflow-engine-inmemory/tsconfig.json"),
148-
path.join(__dirname, "./packages/modules/workflow-engine-redis/tsconfig.json"),
177+
path.join(
178+
__dirname,
179+
"./packages/modules/workflow-engine-inmemory/tsconfig.json"
180+
),
181+
path.join(
182+
__dirname,
183+
"./packages/modules/workflow-engine-redis/tsconfig.json"
184+
),
149185

150-
path.join(__dirname, "./packages/modules/providers/analytics-local/tsconfig.json"),
151-
path.join(__dirname, "./packages/modules/providers/analytics-posthog/tsconfig.json"),
152-
path.join(__dirname, "./packages/modules/providers/auth-emailpass/tsconfig.json"),
153-
path.join(__dirname, "./packages/modules/providers/auth-github/tsconfig.json"),
154-
path.join(__dirname, "./packages/modules/providers/auth-google/tsconfig.json"),
155-
path.join(__dirname, "./packages/modules/providers/caching-redis/tsconfig.json"),
156-
path.join(__dirname, "./packages/modules/providers/file-local/tsconfig.json"),
157-
path.join(__dirname, "./packages/modules/providers/file-s3/tsconfig.json"),
158-
path.join(__dirname, "./packages/modules/providers/fulfillment-manual/tsconfig.json"),
159-
path.join(__dirname, "./packages/modules/providers/locking-postgres/tsconfig.json"),
160-
path.join(__dirname, "./packages/modules/providers/locking-redis/tsconfig.json"),
161-
path.join(__dirname, "./packages/modules/providers/notification-local/tsconfig.json"),
162-
path.join(__dirname, "./packages/modules/providers/notification-sendgrid/tsconfig.json"),
163-
path.join(__dirname, "./packages/modules/providers/payment-stripe/tsconfig.json"),
186+
path.join(
187+
__dirname,
188+
"./packages/modules/providers/analytics-local/tsconfig.json"
189+
),
190+
path.join(
191+
__dirname,
192+
"./packages/modules/providers/analytics-posthog/tsconfig.json"
193+
),
194+
path.join(
195+
__dirname,
196+
"./packages/modules/providers/auth-emailpass/tsconfig.json"
197+
),
198+
path.join(
199+
__dirname,
200+
"./packages/modules/providers/auth-github/tsconfig.json"
201+
),
202+
path.join(
203+
__dirname,
204+
"./packages/modules/providers/auth-google/tsconfig.json"
205+
),
206+
path.join(
207+
__dirname,
208+
"./packages/modules/providers/caching-redis/tsconfig.json"
209+
),
210+
path.join(
211+
__dirname,
212+
"./packages/modules/providers/file-local/tsconfig.json"
213+
),
214+
path.join(
215+
__dirname,
216+
"./packages/modules/providers/file-s3/tsconfig.json"
217+
),
218+
path.join(
219+
__dirname,
220+
"./packages/modules/providers/fulfillment-manual/tsconfig.json"
221+
),
222+
path.join(
223+
__dirname,
224+
"./packages/modules/providers/locking-postgres/tsconfig.json"
225+
),
226+
path.join(
227+
__dirname,
228+
"./packages/modules/providers/locking-redis/tsconfig.json"
229+
),
230+
path.join(
231+
__dirname,
232+
"./packages/modules/providers/notification-local/tsconfig.json"
233+
),
234+
path.join(
235+
__dirname,
236+
"./packages/modules/providers/notification-sendgrid/tsconfig.json"
237+
),
238+
path.join(
239+
__dirname,
240+
"./packages/modules/providers/payment-stripe/tsconfig.json"
241+
),
164242

165243
path.join(__dirname, "./packages/plugins/draft-order/tsconfig.json"),
244+
path.join(__dirname, "./packages/plugins/loyalty/tsconfig.json"),
166245
],
167246
},
168247
rules: {

.github/actions/cache-deps/action.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,14 @@ runs:
2727
- run: yarn build
2828
shell: bash
2929
if: ${{ inputs.skip-build != 'true' }}
30+
31+
- name: Build plugins
32+
run: |
33+
for plugin_dir in packages/plugins/*/; do
34+
if [ -f "${plugin_dir}package.json" ]; then
35+
name=$(node -p "require('./${plugin_dir}package.json').name")
36+
yarn workspace "$name" run build
37+
fi
38+
done
39+
shell: bash
40+
if: ${{ inputs.skip-build != 'true' }}

.github/workflows/action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ jobs:
4242
uses: actions/upload-artifact@v4
4343
with:
4444
name: build-artifacts
45+
include-hidden-files: true
4546
path: |
4647
packages/**/dist
48+
packages/plugins/*/.medusa/server
4749
integration-tests/**/dist
4850
!packages/**/node_modules
4951
retention-days: 1

CONTRIBUTING.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,15 @@ The code snippets in this section assume that your forked Medusa project and the
116116
"@medusajs/telemetry": "file:../medusa/packages/medusa-telemetry",
117117
"@medusajs/settings": "file:../medusa/packages/modules/settings",
118118
"@medusajs/draft-order": "file:../medusa/packages/plugins/draft-order",
119+
"@medusajs/loyalty-plugin": "file:../medusa/packages/plugins/loyalty",
119120
"@medusajs/deps": "file:../medusa/packages/deps",
120121
"@medusajs/caching-redis": "file:../medusa/packages/modules/providers/caching-redis",
121122
"@medusajs/caching": "file:../medusa/packages/modules/caching",
122123
"@medusajs/translation": "file:../medusa/packages/modules/translation",
123124
}
124125
```
125126

126-
If you're using `pnpm`, use `pnpm.overrides` instead of `resolutions`:
127+
If you're using `pnpm`, use `pnpm.overrides` instead of `resolutions`:
127128

128129
```json
129130
// test project package.json (for pnpm)
@@ -198,6 +199,7 @@ The code snippets in this section assume that your forked Medusa project and the
198199
"@medusajs/telemetry": "file:../medusa/packages/medusa-telemetry",
199200
"@medusajs/settings": "file:../medusa/packages/modules/settings",
200201
"@medusajs/draft-order": "file:../medusa/packages/plugins/draft-order",
202+
"@medusajs/loyalty-plugin": "file:../medusa/packages/plugins/loyalty",
201203
"@medusajs/deps": "file:../medusa/packages/deps",
202204
"@medusajs/caching-redis": "file:../medusa/packages/modules/providers/caching-redis",
203205
"@medusajs/caching": "file:../medusa/packages/modules/caching",
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
2+
import {
3+
adminHeaders,
4+
createAdminUser,
5+
} from "../../../../helpers/create-admin-user"
6+
7+
jest.setTimeout(60 * 1000)
8+
9+
const giftCardPayload = {
10+
currency_code: "USD",
11+
value: 1000,
12+
code: "TEST1",
13+
line_item_id: "lin_123",
14+
}
15+
16+
const giftCardResponse = {
17+
id: expect.any(String),
18+
code: "TEST1",
19+
currency_code: "USD",
20+
expires_at: null,
21+
line_item_id: "lin_123",
22+
status: "redeemed", // cards are automatically redeemed i.e. SCA is created upon creation
23+
value: 1000,
24+
}
25+
26+
medusaIntegrationTestRunner({
27+
testSuite: ({ dbConnection, api, getContainer }) => {
28+
beforeEach(async () => {
29+
await createAdminUser(dbConnection, adminHeaders, getContainer())
30+
})
31+
32+
describe("GET /admin/gift-cards", () => {
33+
beforeEach(async () => {
34+
await api.post(
35+
`/admin/customers`,
36+
{ email: "test@test.com" },
37+
adminHeaders
38+
)
39+
40+
await api.post(`/admin/gift-cards`, { ...giftCardPayload }, adminHeaders)
41+
})
42+
43+
it("successfully returns all gift cards", async () => {
44+
const {
45+
data: { gift_cards: giftCards },
46+
} = await api.get(`/admin/gift-cards`, adminHeaders)
47+
48+
expect(giftCards).toEqual([expect.objectContaining({ code: "TEST1" })])
49+
})
50+
})
51+
52+
describe("GET /admin/gift-cards/:id", () => {
53+
it("should retrieve a gift card by id", async () => {
54+
const {
55+
data: { gift_card: createdGiftCard },
56+
} = await api.post(`/admin/gift-cards`, giftCardPayload, adminHeaders)
57+
58+
const {
59+
data: { gift_card },
60+
} = await api.get(
61+
`/admin/gift-cards/${createdGiftCard.id}`,
62+
adminHeaders
63+
)
64+
65+
expect(gift_card).toEqual(expect.objectContaining(giftCardResponse))
66+
})
67+
68+
it("should throw an error if the gift card does not exist", async () => {
69+
const { response } = await api
70+
.get(`/admin/gift-cards/does-not-exist`, adminHeaders)
71+
.catch((e) => e)
72+
73+
expect(response.data).toEqual({
74+
message: "GiftCard id not found: does-not-exist",
75+
type: "not_found",
76+
})
77+
})
78+
})
79+
80+
describe("POST /admin/gift-cards", () => {
81+
it("successfully creates a gift card", async () => {
82+
const {
83+
data: { gift_card },
84+
} = await api.post(`/admin/gift-cards`, giftCardPayload, adminHeaders)
85+
86+
expect(gift_card).toEqual(expect.objectContaining(giftCardResponse))
87+
})
88+
})
89+
90+
describe("POST /admin/gift-cards/:id", () => {
91+
it("should update a gift card by id", async () => {
92+
const {
93+
data: { gift_card: createdGiftCard },
94+
} = await api.post(`/admin/gift-cards`, giftCardPayload, adminHeaders)
95+
96+
const {
97+
data: { gift_card },
98+
} = await api.post(
99+
`/admin/gift-cards/${createdGiftCard.id}`,
100+
{
101+
status: "redeemed",
102+
note: "This is a test note",
103+
},
104+
adminHeaders
105+
)
106+
107+
expect(gift_card).toEqual(
108+
expect.objectContaining({
109+
status: "redeemed",
110+
note: "This is a test note",
111+
})
112+
)
113+
})
114+
115+
it("should throw an error if the gift card does not exist", async () => {
116+
const { response } = await api
117+
.post(
118+
`/admin/gift-cards/does-not-exist`,
119+
{
120+
status: "redeemed",
121+
note: "This is a test note",
122+
},
123+
adminHeaders
124+
)
125+
.catch((e) => e)
126+
127+
expect(response.data).toEqual({
128+
message: "GiftCard id not found: does-not-exist",
129+
type: "not_found",
130+
})
131+
})
132+
})
133+
},
134+
})

0 commit comments

Comments
 (0)