@reactionary/medusa 0.10.23 → 0.10.25
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/capabilities/company-registration.capability.js +116 -0
- package/capabilities/company.capability.js +257 -0
- package/capabilities/employee-invitation.capability.js +221 -0
- package/capabilities/employee.capability.js +265 -0
- package/core/initialize.js +84 -0
- package/factories/category/category.factory.js +11 -1
- package/factories/company/company.factory.js +83 -0
- package/factories/company-registration/company-registration.factory.js +31 -0
- package/factories/employee/employee.factory.js +48 -0
- package/factories/employee-invitation/employee-invitation.factory.js +79 -0
- package/factories/index.js +4 -0
- package/index.js +4 -0
- package/package.json +2 -2
- package/schema/capabilities.schema.js +6 -1
- package/src/capabilities/company-registration.capability.d.ts +25 -0
- package/src/capabilities/company.capability.d.ts +37 -0
- package/src/capabilities/employee-invitation.capability.d.ts +18 -0
- package/src/capabilities/employee.capability.d.ts +37 -0
- package/src/core/initialize.types.d.ts +22 -2
- package/src/factories/company/company.factory.d.ts +45 -0
- package/src/factories/company-registration/company-registration.factory.d.ts +10 -0
- package/src/factories/employee/employee.factory.d.ts +32 -0
- package/src/factories/employee-invitation/employee-invitation.factory.d.ts +40 -0
- package/src/factories/index.d.ts +4 -0
- package/src/index.d.ts +4 -0
- package/src/schema/capabilities.schema.d.ts +30 -2
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
import { FetchError } from "@medusajs/js-sdk";
|
|
12
|
+
import {
|
|
13
|
+
EmployeeCapability,
|
|
14
|
+
EmployeeMutationAssignRoleSchema,
|
|
15
|
+
EmployeeMutationRemoveEmployeeSchema,
|
|
16
|
+
EmployeeMutationUnassignRoleSchema,
|
|
17
|
+
EmployeePaginatedListSchema,
|
|
18
|
+
EmployeeQueryByEmailSchema,
|
|
19
|
+
EmployeeQueryListSchema,
|
|
20
|
+
EmployeeSchema,
|
|
21
|
+
Reactionary,
|
|
22
|
+
error,
|
|
23
|
+
success
|
|
24
|
+
} from "@reactionary/core";
|
|
25
|
+
import createDebug from "debug";
|
|
26
|
+
import { handleProviderError } from "../utils/medusa-helpers.js";
|
|
27
|
+
const debug = createDebug("reactionary:medusa:employee");
|
|
28
|
+
const EMPLOYEE_FIELDS = ["*", "customer.*"].join(",");
|
|
29
|
+
class MedusaEmployeeCapability extends EmployeeCapability {
|
|
30
|
+
constructor(config, cache, context, medusaApi, factory) {
|
|
31
|
+
super(cache, context);
|
|
32
|
+
this.medusaApi = medusaApi;
|
|
33
|
+
this.config = config;
|
|
34
|
+
this.factory = factory;
|
|
35
|
+
}
|
|
36
|
+
medusaApi;
|
|
37
|
+
config;
|
|
38
|
+
factory;
|
|
39
|
+
// company.taxIdentifier is the real, caller-chosen business tax id - not the Medusa-internal company
|
|
40
|
+
// id the REST API is keyed by - so it has to be resolved to that id before it can be used in a path.
|
|
41
|
+
async resolveCompanyId(taxIdentifier) {
|
|
42
|
+
const client = await this.medusaApi.getClient();
|
|
43
|
+
try {
|
|
44
|
+
const response = await client.client.fetch(
|
|
45
|
+
`/store/companies/by-tax-identifier/${encodeURIComponent(taxIdentifier)}`,
|
|
46
|
+
{ method: "GET" }
|
|
47
|
+
);
|
|
48
|
+
return response.company.id;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
if (err instanceof FetchError && err.status === 404) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* ponytail: there's no `customer_id` or `role` filter on the backend's employee list route, so
|
|
58
|
+
* resolving an employee by customer id, or listing by role, means scanning the company's employee
|
|
59
|
+
* list client-side via iterateCompanyEmployeePages. Upgrade path: ask the backend to add `customer_id`
|
|
60
|
+
* and `role` filters to `StoreGetEmployeeParams`.
|
|
61
|
+
*/
|
|
62
|
+
async fetchCompanyEmployees(companyId, opts = {}) {
|
|
63
|
+
const client = await this.medusaApi.getClient();
|
|
64
|
+
const response = await client.client.fetch(`/store/companies/${companyId}/employees`, {
|
|
65
|
+
method: "GET",
|
|
66
|
+
query: {
|
|
67
|
+
fields: EMPLOYEE_FIELDS,
|
|
68
|
+
email: opts.email,
|
|
69
|
+
q: opts.q,
|
|
70
|
+
limit: opts.limit ?? 1e3,
|
|
71
|
+
offset: opts.offset ?? 0
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return { employees: response.employees, count: response.count };
|
|
75
|
+
}
|
|
76
|
+
async *iterateCompanyEmployeePages(companyId, opts = {}) {
|
|
77
|
+
const pageSize = 1e3;
|
|
78
|
+
let offset = 0;
|
|
79
|
+
let count = Infinity;
|
|
80
|
+
while (offset < count) {
|
|
81
|
+
const page = await this.fetchCompanyEmployees(companyId, { ...opts, limit: pageSize, offset });
|
|
82
|
+
yield page.employees;
|
|
83
|
+
count = page.count;
|
|
84
|
+
offset += pageSize;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async findEmployeeByCustomerId(companyId, customerId) {
|
|
88
|
+
for await (const employees of this.iterateCompanyEmployeePages(companyId)) {
|
|
89
|
+
const match = employees.find((employee) => employee.customer?.id === customerId);
|
|
90
|
+
if (match) {
|
|
91
|
+
return match;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return void 0;
|
|
95
|
+
}
|
|
96
|
+
async listEmployees(payload) {
|
|
97
|
+
debug("listEmployees", payload);
|
|
98
|
+
try {
|
|
99
|
+
const companyId = await this.resolveCompanyId(payload.search.company.taxIdentifier);
|
|
100
|
+
if (!companyId) {
|
|
101
|
+
return error({ type: "NotFound", identifier: payload.search.company });
|
|
102
|
+
}
|
|
103
|
+
const { pageNumber, pageSize } = payload.search.paginationOptions;
|
|
104
|
+
const q = [payload.search.firstName, payload.search.lastName].filter(Boolean).join(" ") || void 0;
|
|
105
|
+
let employees;
|
|
106
|
+
let count;
|
|
107
|
+
if (payload.search.role) {
|
|
108
|
+
const role = this.factory.mapRole(payload.search.role);
|
|
109
|
+
const matches = [];
|
|
110
|
+
for await (const page2 of this.iterateCompanyEmployeePages(companyId, { email: payload.search.email, q })) {
|
|
111
|
+
matches.push(...page2.filter((employee) => employee.role === role));
|
|
112
|
+
}
|
|
113
|
+
const start = (pageNumber - 1) * pageSize;
|
|
114
|
+
employees = matches.slice(start, start + pageSize);
|
|
115
|
+
count = matches.length;
|
|
116
|
+
} else {
|
|
117
|
+
({ employees, count } = await this.fetchCompanyEmployees(companyId, {
|
|
118
|
+
email: payload.search.email,
|
|
119
|
+
q,
|
|
120
|
+
limit: pageSize,
|
|
121
|
+
offset: (pageNumber - 1) * pageSize
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
const page = employees.map((employee) => ({
|
|
125
|
+
company: payload.search.company,
|
|
126
|
+
employee
|
|
127
|
+
}));
|
|
128
|
+
return success(
|
|
129
|
+
this.factory.parseEmployeePaginatedList(
|
|
130
|
+
this.context,
|
|
131
|
+
{ items: page, totalCount: count },
|
|
132
|
+
payload
|
|
133
|
+
)
|
|
134
|
+
);
|
|
135
|
+
} catch (err) {
|
|
136
|
+
handleProviderError("list employees", err);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async getByEmail(payload) {
|
|
140
|
+
debug("getByEmail", payload);
|
|
141
|
+
try {
|
|
142
|
+
const companyId = await this.resolveCompanyId(payload.company.taxIdentifier);
|
|
143
|
+
if (!companyId) {
|
|
144
|
+
return error({ type: "NotFound", identifier: payload.company });
|
|
145
|
+
}
|
|
146
|
+
const { employees } = await this.fetchCompanyEmployees(companyId, { email: payload.email });
|
|
147
|
+
const employee = employees[0];
|
|
148
|
+
if (!employee) {
|
|
149
|
+
return error({ type: "NotFound", identifier: payload });
|
|
150
|
+
}
|
|
151
|
+
return success(
|
|
152
|
+
this.factory.parseEmployee(this.context, { company: payload.company, employee })
|
|
153
|
+
);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
handleProviderError("get employee by email", err);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async updateEmployeeRole(company, employeeIdentifier, role) {
|
|
159
|
+
const companyId = await this.resolveCompanyId(company.taxIdentifier);
|
|
160
|
+
if (!companyId) {
|
|
161
|
+
return error({ type: "NotFound", identifier: company });
|
|
162
|
+
}
|
|
163
|
+
const existing = await this.findEmployeeByCustomerId(companyId, employeeIdentifier.userId);
|
|
164
|
+
if (!existing) {
|
|
165
|
+
return error({ type: "NotFound", identifier: employeeIdentifier });
|
|
166
|
+
}
|
|
167
|
+
const client = await this.medusaApi.getClient();
|
|
168
|
+
const response = await client.client.fetch(
|
|
169
|
+
`/store/companies/${companyId}/employees/${existing.id}`,
|
|
170
|
+
{
|
|
171
|
+
method: "POST",
|
|
172
|
+
body: { role },
|
|
173
|
+
query: { fields: EMPLOYEE_FIELDS }
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
return success(
|
|
177
|
+
this.factory.parseEmployee(this.context, {
|
|
178
|
+
company,
|
|
179
|
+
employee: response.employee
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
async assignRole(payload) {
|
|
184
|
+
debug("assignRole", payload);
|
|
185
|
+
try {
|
|
186
|
+
return await this.updateEmployeeRole(
|
|
187
|
+
payload.company,
|
|
188
|
+
payload.employeeIdentifier,
|
|
189
|
+
this.factory.mapRole(payload.role)
|
|
190
|
+
);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
handleProviderError("assign employee role", err);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async unassignRole(payload) {
|
|
196
|
+
debug("unassignRole", payload);
|
|
197
|
+
try {
|
|
198
|
+
return await this.updateEmployeeRole(
|
|
199
|
+
payload.company,
|
|
200
|
+
payload.employeeIdentifier,
|
|
201
|
+
"employee"
|
|
202
|
+
);
|
|
203
|
+
} catch (err) {
|
|
204
|
+
handleProviderError("unassign employee role", err);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async removeEmployee(payload) {
|
|
208
|
+
debug("removeEmployee", payload);
|
|
209
|
+
try {
|
|
210
|
+
const companyId = await this.resolveCompanyId(payload.company.taxIdentifier);
|
|
211
|
+
if (!companyId) {
|
|
212
|
+
return error({ type: "NotFound", identifier: payload.company });
|
|
213
|
+
}
|
|
214
|
+
const existing = await this.findEmployeeByCustomerId(
|
|
215
|
+
companyId,
|
|
216
|
+
payload.employeeIdentifier.userId
|
|
217
|
+
);
|
|
218
|
+
if (!existing) {
|
|
219
|
+
return error({
|
|
220
|
+
type: "NotFound",
|
|
221
|
+
identifier: payload.employeeIdentifier
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
const client = await this.medusaApi.getClient();
|
|
225
|
+
await client.client.fetch(`/store/companies/${companyId}/employees/${existing.id}`, {
|
|
226
|
+
method: "DELETE"
|
|
227
|
+
});
|
|
228
|
+
return success(void 0);
|
|
229
|
+
} catch (err) {
|
|
230
|
+
handleProviderError("remove employee", err);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
__decorateClass([
|
|
235
|
+
Reactionary({
|
|
236
|
+
inputSchema: EmployeeQueryListSchema,
|
|
237
|
+
outputSchema: EmployeePaginatedListSchema
|
|
238
|
+
})
|
|
239
|
+
], MedusaEmployeeCapability.prototype, "listEmployees", 1);
|
|
240
|
+
__decorateClass([
|
|
241
|
+
Reactionary({
|
|
242
|
+
inputSchema: EmployeeQueryByEmailSchema,
|
|
243
|
+
outputSchema: EmployeeSchema
|
|
244
|
+
})
|
|
245
|
+
], MedusaEmployeeCapability.prototype, "getByEmail", 1);
|
|
246
|
+
__decorateClass([
|
|
247
|
+
Reactionary({
|
|
248
|
+
inputSchema: EmployeeMutationAssignRoleSchema,
|
|
249
|
+
outputSchema: EmployeeSchema
|
|
250
|
+
})
|
|
251
|
+
], MedusaEmployeeCapability.prototype, "assignRole", 1);
|
|
252
|
+
__decorateClass([
|
|
253
|
+
Reactionary({
|
|
254
|
+
inputSchema: EmployeeMutationUnassignRoleSchema,
|
|
255
|
+
outputSchema: EmployeeSchema
|
|
256
|
+
})
|
|
257
|
+
], MedusaEmployeeCapability.prototype, "unassignRole", 1);
|
|
258
|
+
__decorateClass([
|
|
259
|
+
Reactionary({
|
|
260
|
+
inputSchema: EmployeeMutationRemoveEmployeeSchema
|
|
261
|
+
})
|
|
262
|
+
], MedusaEmployeeCapability.prototype, "removeEmployee", 1);
|
|
263
|
+
export {
|
|
264
|
+
MedusaEmployeeCapability
|
|
265
|
+
};
|
package/core/initialize.js
CHANGED
|
@@ -5,6 +5,14 @@ import {
|
|
|
5
5
|
CategoryPaginatedResultSchema,
|
|
6
6
|
CategorySchema,
|
|
7
7
|
CheckoutSchema,
|
|
8
|
+
CompanySchema,
|
|
9
|
+
CompanyPaginatedListSchema,
|
|
10
|
+
CompanyRegistrationRequestSchema,
|
|
11
|
+
EmployeeSchema,
|
|
12
|
+
EmployeePaginatedListSchema,
|
|
13
|
+
EmployeeInvitationSchema,
|
|
14
|
+
EmployeeIssuedInvitationSchema,
|
|
15
|
+
EmployeeInvitationPaginatedListSchema,
|
|
8
16
|
InventorySchema,
|
|
9
17
|
OrderSchema,
|
|
10
18
|
OrderSearchResultSchema,
|
|
@@ -20,6 +28,10 @@ import {
|
|
|
20
28
|
import { MedusaCartCapability } from "../capabilities/cart.capability.js";
|
|
21
29
|
import { MedusaCategoryCapability } from "../capabilities/category.capability.js";
|
|
22
30
|
import { MedusaCheckoutCapability } from "../capabilities/checkout.capability.js";
|
|
31
|
+
import { MedusaCompanyCapability } from "../capabilities/company.capability.js";
|
|
32
|
+
import { MedusaCompanyRegistrationCapability } from "../capabilities/company-registration.capability.js";
|
|
33
|
+
import { MedusaEmployeeCapability } from "../capabilities/employee.capability.js";
|
|
34
|
+
import { MedusaEmployeeInvitationCapability } from "../capabilities/employee-invitation.capability.js";
|
|
23
35
|
import { MedusaIdentityCapability } from "../capabilities/identity.capability.js";
|
|
24
36
|
import { MedusaInventoryCapability } from "../capabilities/inventory.capability.js";
|
|
25
37
|
import { MedusaOrderSearchCapability } from "../capabilities/order-search.capability.js";
|
|
@@ -42,6 +54,10 @@ import {
|
|
|
42
54
|
MedusaCartFactory,
|
|
43
55
|
MedusaCategoryFactory,
|
|
44
56
|
MedusaCheckoutFactory,
|
|
57
|
+
MedusaCompanyFactory,
|
|
58
|
+
MedusaCompanyRegistrationFactory,
|
|
59
|
+
MedusaEmployeeFactory,
|
|
60
|
+
MedusaEmployeeInvitationFactory,
|
|
45
61
|
MedusaInventoryFactory,
|
|
46
62
|
MedusaOrderFactory,
|
|
47
63
|
MedusaOrderSearchFactory,
|
|
@@ -140,6 +156,74 @@ function withMedusaCapabilities(configuration, capabilities) {
|
|
|
140
156
|
buildCapabilityArgs
|
|
141
157
|
);
|
|
142
158
|
}
|
|
159
|
+
if (caps.employee?.enabled) {
|
|
160
|
+
client.employee = resolveCapabilityWithFactory(
|
|
161
|
+
capabilities.employee,
|
|
162
|
+
{
|
|
163
|
+
factory: new MedusaEmployeeFactory(EmployeeSchema, EmployeePaginatedListSchema),
|
|
164
|
+
capability: (args) => new MedusaEmployeeCapability(
|
|
165
|
+
args.config,
|
|
166
|
+
args.cache,
|
|
167
|
+
args.context,
|
|
168
|
+
args.medusaApi,
|
|
169
|
+
args.factory
|
|
170
|
+
)
|
|
171
|
+
},
|
|
172
|
+
buildCapabilityArgs
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
if (caps.employeeInvitation?.enabled) {
|
|
176
|
+
client.employeeInvitation = resolveCapabilityWithFactory(
|
|
177
|
+
capabilities.employeeInvitation,
|
|
178
|
+
{
|
|
179
|
+
factory: new MedusaEmployeeInvitationFactory(
|
|
180
|
+
EmployeeInvitationSchema,
|
|
181
|
+
EmployeeIssuedInvitationSchema,
|
|
182
|
+
EmployeeInvitationPaginatedListSchema
|
|
183
|
+
),
|
|
184
|
+
capability: (args) => new MedusaEmployeeInvitationCapability(
|
|
185
|
+
args.config,
|
|
186
|
+
args.cache,
|
|
187
|
+
args.context,
|
|
188
|
+
args.medusaApi,
|
|
189
|
+
args.factory
|
|
190
|
+
)
|
|
191
|
+
},
|
|
192
|
+
buildCapabilityArgs
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (caps.company?.enabled) {
|
|
196
|
+
client.company = resolveCapabilityWithFactory(
|
|
197
|
+
capabilities.company,
|
|
198
|
+
{
|
|
199
|
+
factory: new MedusaCompanyFactory(CompanySchema, CompanyPaginatedListSchema),
|
|
200
|
+
capability: (args) => new MedusaCompanyCapability(
|
|
201
|
+
args.config,
|
|
202
|
+
args.cache,
|
|
203
|
+
args.context,
|
|
204
|
+
args.medusaApi,
|
|
205
|
+
args.factory
|
|
206
|
+
)
|
|
207
|
+
},
|
|
208
|
+
buildCapabilityArgs
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (caps.companyRegistration?.enabled) {
|
|
212
|
+
client.companyRegistration = resolveCapabilityWithFactory(
|
|
213
|
+
capabilities.companyRegistration,
|
|
214
|
+
{
|
|
215
|
+
factory: new MedusaCompanyRegistrationFactory(CompanyRegistrationRequestSchema),
|
|
216
|
+
capability: (args) => new MedusaCompanyRegistrationCapability(
|
|
217
|
+
args.config,
|
|
218
|
+
args.cache,
|
|
219
|
+
args.context,
|
|
220
|
+
args.medusaApi,
|
|
221
|
+
args.factory
|
|
222
|
+
)
|
|
223
|
+
},
|
|
224
|
+
buildCapabilityArgs
|
|
225
|
+
);
|
|
226
|
+
}
|
|
143
227
|
if (caps.productRecommendations?.enabled) {
|
|
144
228
|
client.productRecommendations = resolveDirectCapability(
|
|
145
229
|
capabilities.productRecommendations,
|
|
@@ -15,6 +15,16 @@ class MedusaCategoryFactory {
|
|
|
15
15
|
const name = data.name;
|
|
16
16
|
const slug = data.handle;
|
|
17
17
|
const text = data.description || "";
|
|
18
|
+
const images = [];
|
|
19
|
+
if (data.metadata) {
|
|
20
|
+
const metaDataImages = data.metadata["images"] || [];
|
|
21
|
+
images.push(...metaDataImages.map((img) => {
|
|
22
|
+
return {
|
|
23
|
+
sourceUrl: img.url,
|
|
24
|
+
altText: name || ""
|
|
25
|
+
};
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
18
28
|
const parentCategory = data.parent_category_id ? { key: data.parent_category?.external_id || "" } : void 0;
|
|
19
29
|
const result = {
|
|
20
30
|
identifier,
|
|
@@ -22,7 +32,7 @@ class MedusaCategoryFactory {
|
|
|
22
32
|
slug,
|
|
23
33
|
text,
|
|
24
34
|
parentCategory,
|
|
25
|
-
images
|
|
35
|
+
images
|
|
26
36
|
};
|
|
27
37
|
return this.categorySchema.parse(result);
|
|
28
38
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
const EMPTY_ADDRESS = {
|
|
4
|
+
identifier: { nickName: "" },
|
|
5
|
+
firstName: "",
|
|
6
|
+
lastName: "",
|
|
7
|
+
streetAddress: "",
|
|
8
|
+
streetNumber: "",
|
|
9
|
+
city: "",
|
|
10
|
+
region: "",
|
|
11
|
+
postalCode: "",
|
|
12
|
+
countryCode: ""
|
|
13
|
+
};
|
|
14
|
+
class MedusaCompanyFactory {
|
|
15
|
+
companySchema;
|
|
16
|
+
companyPaginatedListSchema;
|
|
17
|
+
constructor(companySchema, companyPaginatedListSchema) {
|
|
18
|
+
this.companySchema = companySchema;
|
|
19
|
+
this.companyPaginatedListSchema = companyPaginatedListSchema;
|
|
20
|
+
}
|
|
21
|
+
parseAddress(raw) {
|
|
22
|
+
return {
|
|
23
|
+
identifier: { nickName: raw.address_name ?? "" },
|
|
24
|
+
firstName: raw.first_name,
|
|
25
|
+
lastName: raw.last_name,
|
|
26
|
+
streetAddress: raw.street_address,
|
|
27
|
+
streetNumber: raw.street_number ?? "",
|
|
28
|
+
city: raw.city,
|
|
29
|
+
region: raw.region ?? "",
|
|
30
|
+
postalCode: raw.postal_code,
|
|
31
|
+
countryCode: raw.country_code
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
parseCompany(_context, data) {
|
|
35
|
+
const addresses = data.addresses ?? [];
|
|
36
|
+
const billing = addresses.find((a) => a.type === "billing" && a.is_default) ?? addresses.find((a) => a.type === "billing");
|
|
37
|
+
const shippingAddresses = addresses.filter((a) => a.type === "shipping");
|
|
38
|
+
const shipping = shippingAddresses.find((a) => a.is_default);
|
|
39
|
+
const alternateShippingAddresses = shippingAddresses.filter((a) => !a.is_default).map((a) => this.parseAddress(a));
|
|
40
|
+
const result = {
|
|
41
|
+
identifier: { taxIdentifier: data.tax_identifier },
|
|
42
|
+
dunsIdentifier: data.duns_identifier ?? void 0,
|
|
43
|
+
tinIdentifier: data.tin_identifier ?? void 0,
|
|
44
|
+
name: data.name,
|
|
45
|
+
logo: data.logo_url ? {
|
|
46
|
+
sourceUrl: data.logo_url,
|
|
47
|
+
altText: data.logo_alt_text ?? "",
|
|
48
|
+
width: data.logo_width ?? void 0,
|
|
49
|
+
height: data.logo_height ?? void 0
|
|
50
|
+
} : void 0,
|
|
51
|
+
// ponytail: core's CompanyStatus only has 2 values (active/blocked), but the backend has 3
|
|
52
|
+
// (active/pending_approval/blocked) - pending_approval collapses into blocked here. Use
|
|
53
|
+
// CompanyRegistrationRequest's status instead (see MedusaCompanyRegistrationFactory) when the
|
|
54
|
+
// pending/denied distinction matters, e.g. right after requestRegistration.
|
|
55
|
+
status: data.status === "active" ? "active" : "blocked",
|
|
56
|
+
pointOfContact: { email: data.email, phone: data.phone ?? void 0 },
|
|
57
|
+
// "Default shipping address if different from default billing address" (per CompanySchema) - so
|
|
58
|
+
// absent an explicit shipping default, ship-to-billing is the implied default.
|
|
59
|
+
shippingAddress: shipping ? this.parseAddress(shipping) : billing ? this.parseAddress(billing) : void 0,
|
|
60
|
+
billingAddress: billing ? this.parseAddress(billing) : EMPTY_ADDRESS,
|
|
61
|
+
alternateShippingAddresses,
|
|
62
|
+
isCustomAddressesAllowed: data.is_custom_addresses_allowed,
|
|
63
|
+
isSelfManagementOfShippingAddressesAllowed: data.is_self_management_of_shipping_addresses_allowed
|
|
64
|
+
};
|
|
65
|
+
return this.companySchema.parse(result);
|
|
66
|
+
}
|
|
67
|
+
parseCompanyPaginatedList(context, data, query) {
|
|
68
|
+
const items = data.items.map((item) => this.parseCompany(context, item));
|
|
69
|
+
const { pageNumber, pageSize } = query.search.paginationOptions;
|
|
70
|
+
const result = {
|
|
71
|
+
identifier: query.search,
|
|
72
|
+
pageNumber,
|
|
73
|
+
pageSize,
|
|
74
|
+
totalCount: data.totalCount,
|
|
75
|
+
totalPages: Math.ceil(data.totalCount / pageSize),
|
|
76
|
+
items
|
|
77
|
+
};
|
|
78
|
+
return this.companyPaginatedListSchema.parse(result);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
MedusaCompanyFactory
|
|
83
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
class MedusaCompanyRegistrationFactory {
|
|
4
|
+
companyRegistrationRequestSchema;
|
|
5
|
+
constructor(companyRegistrationRequestSchema) {
|
|
6
|
+
this.companyRegistrationRequestSchema = companyRegistrationRequestSchema;
|
|
7
|
+
}
|
|
8
|
+
parseCompanyRegistrationRequest(_context, data) {
|
|
9
|
+
const result = {
|
|
10
|
+
identifier: { key: data.id },
|
|
11
|
+
companyIdentifier: { taxIdentifier: data.tax_identifier },
|
|
12
|
+
name: data.name,
|
|
13
|
+
pointOfContact: { email: data.email, phone: data.phone ?? void 0 },
|
|
14
|
+
status: this.parseStatus(data.status)
|
|
15
|
+
};
|
|
16
|
+
return this.companyRegistrationRequestSchema.parse(result);
|
|
17
|
+
}
|
|
18
|
+
parseStatus(status) {
|
|
19
|
+
switch (status) {
|
|
20
|
+
case "active":
|
|
21
|
+
return "approved";
|
|
22
|
+
case "pending_approval":
|
|
23
|
+
return "pending";
|
|
24
|
+
default:
|
|
25
|
+
return "denied";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
MedusaCompanyRegistrationFactory
|
|
31
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
class MedusaEmployeeFactory {
|
|
4
|
+
employeeSchema;
|
|
5
|
+
employeePaginatedListSchema;
|
|
6
|
+
constructor(employeeSchema, employeePaginatedListSchema) {
|
|
7
|
+
this.employeeSchema = employeeSchema;
|
|
8
|
+
this.employeePaginatedListSchema = employeePaginatedListSchema;
|
|
9
|
+
}
|
|
10
|
+
parseEmployee(context, data) {
|
|
11
|
+
const customer = data.employee.customer;
|
|
12
|
+
const result = {
|
|
13
|
+
identifier: { userId: customer?.id ?? "" },
|
|
14
|
+
company: data.company,
|
|
15
|
+
firstName: customer?.first_name ?? void 0,
|
|
16
|
+
lastName: customer?.last_name ?? void 0,
|
|
17
|
+
email: customer?.email ?? "",
|
|
18
|
+
spendingLimit: data.employee.spending_limit === void 0 ? void 0 : {
|
|
19
|
+
value: data.employee.spending_limit,
|
|
20
|
+
currency: context.languageContext.currencyCode
|
|
21
|
+
},
|
|
22
|
+
role: this.parseRole(data.employee.role)
|
|
23
|
+
};
|
|
24
|
+
return this.employeeSchema.parse(result);
|
|
25
|
+
}
|
|
26
|
+
parseEmployeePaginatedList(context, data, query) {
|
|
27
|
+
const items = data.items.map((item) => this.parseEmployee(context, item));
|
|
28
|
+
const { pageNumber, pageSize } = query.search.paginationOptions;
|
|
29
|
+
const result = {
|
|
30
|
+
identifier: query.search,
|
|
31
|
+
pageNumber,
|
|
32
|
+
pageSize,
|
|
33
|
+
totalCount: data.totalCount,
|
|
34
|
+
totalPages: Math.ceil(data.totalCount / pageSize),
|
|
35
|
+
items
|
|
36
|
+
};
|
|
37
|
+
return this.employeePaginatedListSchema.parse(result);
|
|
38
|
+
}
|
|
39
|
+
mapRole(role) {
|
|
40
|
+
return role;
|
|
41
|
+
}
|
|
42
|
+
parseRole(role) {
|
|
43
|
+
return role;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
MedusaEmployeeFactory
|
|
48
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
} from "@reactionary/core";
|
|
3
|
+
function makeInvitationKey(companyId, invitationId) {
|
|
4
|
+
return `${companyId}:${invitationId}`;
|
|
5
|
+
}
|
|
6
|
+
function parseInvitationKey(key) {
|
|
7
|
+
const separatorIndex = key.indexOf(":");
|
|
8
|
+
return {
|
|
9
|
+
companyId: key.slice(0, separatorIndex),
|
|
10
|
+
invitationId: key.slice(separatorIndex + 1)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const NEVER_EXPIRES = (/* @__PURE__ */ new Date(864e13)).toISOString();
|
|
14
|
+
class MedusaEmployeeInvitationFactory {
|
|
15
|
+
employeeInvitationSchema;
|
|
16
|
+
employeeIssuedInvitationSchema;
|
|
17
|
+
employeeInvitationPaginatedListSchema;
|
|
18
|
+
constructor(employeeInvitationSchema, employeeIssuedInvitationSchema, employeeInvitationPaginatedListSchema) {
|
|
19
|
+
this.employeeInvitationSchema = employeeInvitationSchema;
|
|
20
|
+
this.employeeIssuedInvitationSchema = employeeIssuedInvitationSchema;
|
|
21
|
+
this.employeeInvitationPaginatedListSchema = employeeInvitationPaginatedListSchema;
|
|
22
|
+
}
|
|
23
|
+
parseEmployeeInvitation(_context, data, _payload) {
|
|
24
|
+
const result = {
|
|
25
|
+
identifier: { key: makeInvitationKey(data.company_id, data.id) },
|
|
26
|
+
company: { taxIdentifier: data.company?.tax_identifier ?? "" },
|
|
27
|
+
status: this.parseStatus(data.status),
|
|
28
|
+
email: data.email,
|
|
29
|
+
role: this.parseRole(data.role),
|
|
30
|
+
validUntil: data.validUntil ? new Date(data.validUntil).toISOString() : NEVER_EXPIRES
|
|
31
|
+
};
|
|
32
|
+
return this.employeeInvitationSchema.parse(result);
|
|
33
|
+
}
|
|
34
|
+
parseEmployeeIssuedInvitation(context, data, payload) {
|
|
35
|
+
const invitation = this.parseEmployeeInvitation(context, data, payload);
|
|
36
|
+
const result = {
|
|
37
|
+
...invitation,
|
|
38
|
+
// ponytail: only the invite-creation response carries this (see MedusaRawEmployeeInvitation);
|
|
39
|
+
// empty string here would mean this was called from a path that doesn't have one, which shouldn't
|
|
40
|
+
// happen - the capability only calls parseEmployeeIssuedInvitation right after a create response.
|
|
41
|
+
securityToken: data.securityToken ?? ""
|
|
42
|
+
};
|
|
43
|
+
return this.employeeIssuedInvitationSchema.parse(result);
|
|
44
|
+
}
|
|
45
|
+
parseEmployeeInvitationPaginatedList(context, data, query) {
|
|
46
|
+
const items = data.items.map((item) => this.parseEmployeeInvitation(context, item));
|
|
47
|
+
const { pageNumber, pageSize } = query.search.paginationOptions;
|
|
48
|
+
const result = {
|
|
49
|
+
identifier: query.search,
|
|
50
|
+
pageNumber,
|
|
51
|
+
pageSize,
|
|
52
|
+
totalCount: data.totalCount,
|
|
53
|
+
totalPages: Math.ceil(data.totalCount / pageSize),
|
|
54
|
+
items
|
|
55
|
+
};
|
|
56
|
+
return this.employeeInvitationPaginatedListSchema.parse(result);
|
|
57
|
+
}
|
|
58
|
+
mapRole(role) {
|
|
59
|
+
return role;
|
|
60
|
+
}
|
|
61
|
+
parseRole(role) {
|
|
62
|
+
return role;
|
|
63
|
+
}
|
|
64
|
+
parseStatus(status) {
|
|
65
|
+
switch (status) {
|
|
66
|
+
case "accepted":
|
|
67
|
+
return "accepted";
|
|
68
|
+
case "revoked":
|
|
69
|
+
return "revoked";
|
|
70
|
+
default:
|
|
71
|
+
return "invited";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
MedusaEmployeeInvitationFactory,
|
|
77
|
+
makeInvitationKey,
|
|
78
|
+
parseInvitationKey
|
|
79
|
+
};
|
package/factories/index.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export * from "./cart/cart.factory.js";
|
|
2
2
|
export * from "./category/category.factory.js";
|
|
3
3
|
export * from "./checkout/checkout.factory.js";
|
|
4
|
+
export * from "./company/company.factory.js";
|
|
5
|
+
export * from "./company-registration/company-registration.factory.js";
|
|
6
|
+
export * from "./employee/employee.factory.js";
|
|
7
|
+
export * from "./employee-invitation/employee-invitation.factory.js";
|
|
4
8
|
export * from "./identity/identity.factory.js";
|
|
5
9
|
export * from "./inventory/inventory.factory.js";
|
|
6
10
|
export * from "./order/order.factory.js";
|
package/index.js
CHANGED
|
@@ -6,6 +6,10 @@ export * from "./core/initialize.types.js";
|
|
|
6
6
|
export * from "./core/client.js";
|
|
7
7
|
export * from "./factories/index.js";
|
|
8
8
|
export * from "./capabilities/cart.capability.js";
|
|
9
|
+
export * from "./capabilities/company.capability.js";
|
|
10
|
+
export * from "./capabilities/company-registration.capability.js";
|
|
11
|
+
export * from "./capabilities/employee.capability.js";
|
|
12
|
+
export * from "./capabilities/employee-invitation.capability.js";
|
|
9
13
|
export * from "./capabilities/identity.capability.js";
|
|
10
14
|
export * from "./capabilities/inventory.capability.js";
|
|
11
15
|
export * from "./capabilities/order.capability.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reactionary/medusa",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./src/index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@medusajs/js-sdk": "^2.13.3",
|
|
13
|
-
"@reactionary/core": "0.10.
|
|
13
|
+
"@reactionary/core": "0.10.25",
|
|
14
14
|
"debug": "^4.4.3",
|
|
15
15
|
"@medusajs/types": "^2.13.3",
|
|
16
16
|
"zod": "4.1.9"
|