@lodashventure/medusa-quotation 1.4.20 → 1.4.23
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/.medusa/server/src/admin/index.js +299 -68
- package/.medusa/server/src/admin/index.mjs +300 -69
- package/.medusa/server/src/api/admin/quotes/[id]/approve/route.js +22 -0
- package/.medusa/server/src/api/admin/quotes/[id]/route.js +13 -2
- package/.medusa/server/src/api/admin/quotes/[id]/void/route.js +22 -0
- package/.medusa/server/src/modules/quote/migrations/Migration20251028120000.js +18 -0
- package/.medusa/server/src/modules/quote/types/quote-status.enum.js +3 -1
- package/.medusa/server/src/workflows/merchant-approve-quote.js +30 -0
- package/.medusa/server/src/workflows/merchant-delete-quote.js +24 -0
- package/.medusa/server/src/workflows/merchant-void-quote.js +30 -0
- package/.medusa/server/src/workflows/steps/delete-quotes.js +13 -0
- package/.medusa/server/src/workflows/steps/validate-quote-can-approve.js +17 -0
- package/.medusa/server/src/workflows/steps/validate-quote-can-delete.js +17 -0
- package/.medusa/server/src/workflows/steps/validate-quote-can-void.js +12 -0
- package/.medusa/server/src/workflows/steps/validate-quote-not-accepted.js +7 -1
- package/package.json +1 -1
|
@@ -4,7 +4,7 @@ import { DocumentText, CheckCircleSolid, Plus, Trash } from "@medusajs/icons";
|
|
|
4
4
|
import { clx, FocusModal, Heading, Text, Button, Table, Badge, Label, DatePicker, Input, toast, Container, Select, Textarea, createDataTableColumnHelper, useDataTable, DataTable, Toaster, usePrompt, IconButton, Hint, CurrencyInput } from "@medusajs/ui";
|
|
5
5
|
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
6
6
|
import { useNavigate, useParams, Link } from "react-router-dom";
|
|
7
|
-
import { XCircle,
|
|
7
|
+
import { XCircle, CheckCircle, Clock } from "lucide-react";
|
|
8
8
|
import Medusa from "@medusajs/js-sdk";
|
|
9
9
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
10
10
|
import { useForm, Controller } from "react-hook-form";
|
|
@@ -13,20 +13,26 @@ import pdfMake from "pdfmake/build/pdfmake";
|
|
|
13
13
|
import { debounce } from "lodash";
|
|
14
14
|
import "@medusajs/admin-shared";
|
|
15
15
|
const StatusTitles = {
|
|
16
|
+
approved: "Approved",
|
|
16
17
|
accepted: "Accepted",
|
|
17
18
|
customer_rejected: "Customer Rejected",
|
|
18
19
|
merchant_rejected: "Merchant Rejected",
|
|
19
20
|
pending_merchant: "Pending Merchant",
|
|
20
|
-
pending_customer: "Pending Customer"
|
|
21
|
+
pending_customer: "Pending Customer",
|
|
22
|
+
voided: "Voided"
|
|
21
23
|
};
|
|
22
24
|
const getStatusColor = (statusKey) => {
|
|
23
25
|
switch (statusKey) {
|
|
24
26
|
case "accepted":
|
|
25
27
|
return "bg-green-100 text-green-800";
|
|
28
|
+
case "approved":
|
|
29
|
+
return "bg-emerald-100 text-emerald-800";
|
|
26
30
|
case "pending_merchant":
|
|
27
31
|
return "bg-blue-100 text-blue-800";
|
|
28
32
|
case "customer_rejected":
|
|
29
33
|
return "bg-red-100 text-red-800";
|
|
34
|
+
case "voided":
|
|
35
|
+
return "bg-gray-100 text-gray-800";
|
|
30
36
|
default:
|
|
31
37
|
return "bg-gray-100 text-gray-800";
|
|
32
38
|
}
|
|
@@ -43,6 +49,10 @@ const getStatusIcon = (statusKey) => {
|
|
|
43
49
|
return /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-red-600" });
|
|
44
50
|
case "customer_rejected":
|
|
45
51
|
return /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-red-600" });
|
|
52
|
+
case "approved":
|
|
53
|
+
return /* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 text-emerald-600" });
|
|
54
|
+
case "voided":
|
|
55
|
+
return /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-gray-600" });
|
|
46
56
|
default:
|
|
47
57
|
return null;
|
|
48
58
|
}
|
|
@@ -147,7 +157,7 @@ const useAddQuoteItem = (id, options) => {
|
|
|
147
157
|
setIsPending(false);
|
|
148
158
|
}
|
|
149
159
|
};
|
|
150
|
-
return { mutate, isPending, error };
|
|
160
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
151
161
|
};
|
|
152
162
|
const useUpdateQuoteItem = (id, options) => {
|
|
153
163
|
const [isPending, setIsPending] = useState(false);
|
|
@@ -171,7 +181,7 @@ const useUpdateQuoteItem = (id, options) => {
|
|
|
171
181
|
setIsPending(false);
|
|
172
182
|
}
|
|
173
183
|
};
|
|
174
|
-
return { mutate, isPending, error };
|
|
184
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
175
185
|
};
|
|
176
186
|
const useRemoveQuoteItem = (id, options) => {
|
|
177
187
|
const [isPending, setIsPending] = useState(false);
|
|
@@ -191,7 +201,7 @@ const useRemoveQuoteItem = (id, options) => {
|
|
|
191
201
|
setIsPending(false);
|
|
192
202
|
}
|
|
193
203
|
};
|
|
194
|
-
return { mutate, isPending, error };
|
|
204
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
195
205
|
};
|
|
196
206
|
const useConfirmQuote = (id, options) => {
|
|
197
207
|
const [isPending, setIsPending] = useState(false);
|
|
@@ -211,7 +221,7 @@ const useConfirmQuote = (id, options) => {
|
|
|
211
221
|
setIsPending(false);
|
|
212
222
|
}
|
|
213
223
|
};
|
|
214
|
-
return { mutate, isPending, error };
|
|
224
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
215
225
|
};
|
|
216
226
|
const useSendQuote = (id, options) => {
|
|
217
227
|
const [isPending, setIsPending] = useState(false);
|
|
@@ -219,22 +229,49 @@ const useSendQuote = (id, options) => {
|
|
|
219
229
|
const sendQuote = async (id2) => sdk.client.fetch(`/admin/quotes/${id2}/send`, {
|
|
220
230
|
method: "POST"
|
|
221
231
|
});
|
|
222
|
-
const mutate = async () => {
|
|
223
|
-
var _a;
|
|
232
|
+
const mutate = async (_, mutateOptions) => {
|
|
233
|
+
var _a, _b, _c;
|
|
224
234
|
try {
|
|
225
235
|
setIsPending(true);
|
|
226
236
|
setError(null);
|
|
227
237
|
const data = await sendQuote(id);
|
|
228
238
|
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
239
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
229
240
|
return data;
|
|
230
241
|
} catch (err) {
|
|
231
242
|
setError(err);
|
|
243
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
232
244
|
throw err;
|
|
233
245
|
} finally {
|
|
234
246
|
setIsPending(false);
|
|
235
247
|
}
|
|
236
248
|
};
|
|
237
|
-
return { mutate, isPending, error };
|
|
249
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
250
|
+
};
|
|
251
|
+
const useApproveQuote = (id, options) => {
|
|
252
|
+
const [isPending, setIsPending] = useState(false);
|
|
253
|
+
const [error, setError] = useState(null);
|
|
254
|
+
const approveQuote = async (quoteId) => sdk.client.fetch(`/admin/quotes/${quoteId}/approve`, {
|
|
255
|
+
method: "POST"
|
|
256
|
+
});
|
|
257
|
+
const mutate = async (_, mutateOptions) => {
|
|
258
|
+
var _a, _b, _c;
|
|
259
|
+
try {
|
|
260
|
+
setIsPending(true);
|
|
261
|
+
setError(null);
|
|
262
|
+
const data = await approveQuote(id);
|
|
263
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
264
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
265
|
+
return data;
|
|
266
|
+
} catch (err) {
|
|
267
|
+
setError(err);
|
|
268
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
269
|
+
throw err;
|
|
270
|
+
} finally {
|
|
271
|
+
setIsPending(false);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
238
275
|
};
|
|
239
276
|
const useRejectQuote = (id, options) => {
|
|
240
277
|
const [isPending, setIsPending] = useState(false);
|
|
@@ -242,22 +279,96 @@ const useRejectQuote = (id, options) => {
|
|
|
242
279
|
const rejectQuote = async (id2) => sdk.client.fetch(`/admin/quotes/${id2}/reject`, {
|
|
243
280
|
method: "POST"
|
|
244
281
|
});
|
|
245
|
-
const mutate = async () => {
|
|
246
|
-
var _a;
|
|
282
|
+
const mutate = async (_, mutateOptions) => {
|
|
283
|
+
var _a, _b, _c;
|
|
247
284
|
try {
|
|
248
285
|
setIsPending(true);
|
|
249
286
|
setError(null);
|
|
250
287
|
const data = await rejectQuote(id);
|
|
251
288
|
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
289
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
252
290
|
return data;
|
|
253
291
|
} catch (err) {
|
|
254
292
|
setError(err);
|
|
293
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
255
294
|
throw err;
|
|
256
295
|
} finally {
|
|
257
296
|
setIsPending(false);
|
|
258
297
|
}
|
|
259
298
|
};
|
|
260
|
-
return { mutate, isPending, error };
|
|
299
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
300
|
+
};
|
|
301
|
+
const useVoidQuote = (id, options) => {
|
|
302
|
+
const [isPending, setIsPending] = useState(false);
|
|
303
|
+
const [error, setError] = useState(null);
|
|
304
|
+
const voidQuote = async (quoteId) => sdk.client.fetch(`/admin/quotes/${quoteId}/void`, {
|
|
305
|
+
method: "POST"
|
|
306
|
+
});
|
|
307
|
+
const mutate = async (_, mutateOptions) => {
|
|
308
|
+
var _a, _b, _c;
|
|
309
|
+
try {
|
|
310
|
+
setIsPending(true);
|
|
311
|
+
setError(null);
|
|
312
|
+
const data = await voidQuote(id);
|
|
313
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options, data);
|
|
314
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions, data);
|
|
315
|
+
return data;
|
|
316
|
+
} catch (err) {
|
|
317
|
+
setError(err);
|
|
318
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
319
|
+
throw err;
|
|
320
|
+
} finally {
|
|
321
|
+
setIsPending(false);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
325
|
+
};
|
|
326
|
+
const useDeleteQuote = (id, options) => {
|
|
327
|
+
const [isPending, setIsPending] = useState(false);
|
|
328
|
+
const [error, setError] = useState(null);
|
|
329
|
+
const deleteQuote = async () => {
|
|
330
|
+
const response = await fetch(`/admin/quotes/${id}`, {
|
|
331
|
+
method: "DELETE",
|
|
332
|
+
headers: {
|
|
333
|
+
"Content-Type": "application/json"
|
|
334
|
+
},
|
|
335
|
+
credentials: "include"
|
|
336
|
+
});
|
|
337
|
+
if (!response.ok) {
|
|
338
|
+
const errorText = await response.text();
|
|
339
|
+
let errorMessage = errorText;
|
|
340
|
+
try {
|
|
341
|
+
const errorJson = JSON.parse(errorText);
|
|
342
|
+
errorMessage = errorJson.message || errorText;
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
throw new Error(errorMessage || `HTTP ${response.status}`);
|
|
346
|
+
}
|
|
347
|
+
if (response.status === 204) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const contentType = response.headers.get("content-type");
|
|
351
|
+
if (contentType && contentType.includes("application/json")) {
|
|
352
|
+
return response.json();
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
const mutate = async (_, mutateOptions) => {
|
|
356
|
+
var _a, _b, _c;
|
|
357
|
+
try {
|
|
358
|
+
setIsPending(true);
|
|
359
|
+
setError(null);
|
|
360
|
+
await deleteQuote();
|
|
361
|
+
(_a = options == null ? void 0 : options.onSuccess) == null ? void 0 : _a.call(options);
|
|
362
|
+
(_b = mutateOptions == null ? void 0 : mutateOptions.onSuccess) == null ? void 0 : _b.call(mutateOptions);
|
|
363
|
+
} catch (err) {
|
|
364
|
+
setError(err);
|
|
365
|
+
(_c = mutateOptions == null ? void 0 : mutateOptions.onError) == null ? void 0 : _c.call(mutateOptions, err);
|
|
366
|
+
throw err;
|
|
367
|
+
} finally {
|
|
368
|
+
setIsPending(false);
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
return { mutate, mutateAsync: mutate, isPending, error };
|
|
261
372
|
};
|
|
262
373
|
const useQuoteStore = () => {
|
|
263
374
|
const [data, setData] = useState(void 0);
|
|
@@ -1674,11 +1785,15 @@ const TotalsBreakdown = ({ order }) => {
|
|
|
1674
1785
|
})
|
|
1675
1786
|
] });
|
|
1676
1787
|
};
|
|
1677
|
-
const useOrderPreview = (id, query) => {
|
|
1788
|
+
const useOrderPreview = (id, query, options) => {
|
|
1678
1789
|
const [data, setData] = useState(void 0);
|
|
1679
1790
|
const [isLoading, setIsLoading] = useState(true);
|
|
1680
1791
|
const [error, setError] = useState(null);
|
|
1792
|
+
const enabled = (options == null ? void 0 : options.enabled) ?? true;
|
|
1681
1793
|
const fetchOrderPreview = useCallback(async () => {
|
|
1794
|
+
if (!id || !enabled) {
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1682
1797
|
try {
|
|
1683
1798
|
setIsLoading(true);
|
|
1684
1799
|
setError(null);
|
|
@@ -1689,10 +1804,14 @@ const useOrderPreview = (id, query) => {
|
|
|
1689
1804
|
} finally {
|
|
1690
1805
|
setIsLoading(false);
|
|
1691
1806
|
}
|
|
1692
|
-
}, [id, JSON.stringify(query)]);
|
|
1807
|
+
}, [id, enabled, JSON.stringify(query)]);
|
|
1693
1808
|
useEffect(() => {
|
|
1809
|
+
if (!id || !enabled) {
|
|
1810
|
+
setIsLoading(false);
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1694
1813
|
fetchOrderPreview();
|
|
1695
|
-
}, [fetchOrderPreview]);
|
|
1814
|
+
}, [fetchOrderPreview, id, enabled]);
|
|
1696
1815
|
return {
|
|
1697
1816
|
...data,
|
|
1698
1817
|
isLoading,
|
|
@@ -1752,13 +1871,17 @@ const DEFAULT_RELATIONS = [
|
|
|
1752
1871
|
const DEFAULT_ORDER_FIELDS = `${DEFAULT_PROPERTIES.join(
|
|
1753
1872
|
","
|
|
1754
1873
|
)},${DEFAULT_RELATIONS.join(",")}`;
|
|
1755
|
-
const useOrder = (id, query) => {
|
|
1874
|
+
const useOrder = (id, query, options) => {
|
|
1756
1875
|
const [data, setData] = useState(
|
|
1757
1876
|
void 0
|
|
1758
1877
|
);
|
|
1759
1878
|
const [isLoading, setIsLoading] = useState(true);
|
|
1760
1879
|
const [error, setError] = useState(null);
|
|
1880
|
+
const enabled = (options == null ? void 0 : options.enabled) ?? true;
|
|
1761
1881
|
const fetchOrder = useCallback(async () => {
|
|
1882
|
+
if (!id || !enabled) {
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1762
1885
|
try {
|
|
1763
1886
|
setIsLoading(true);
|
|
1764
1887
|
setError(null);
|
|
@@ -1769,10 +1892,14 @@ const useOrder = (id, query) => {
|
|
|
1769
1892
|
} finally {
|
|
1770
1893
|
setIsLoading(false);
|
|
1771
1894
|
}
|
|
1772
|
-
}, [id, JSON.stringify(query)]);
|
|
1895
|
+
}, [id, enabled, JSON.stringify(query)]);
|
|
1773
1896
|
useEffect(() => {
|
|
1897
|
+
if (!id || !enabled) {
|
|
1898
|
+
setIsLoading(false);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1774
1901
|
fetchOrder();
|
|
1775
|
-
}, [fetchOrder]);
|
|
1902
|
+
}, [fetchOrder, id, enabled]);
|
|
1776
1903
|
return {
|
|
1777
1904
|
...data,
|
|
1778
1905
|
isLoading,
|
|
@@ -2144,77 +2271,150 @@ const QuoteDetails = () => {
|
|
|
2144
2271
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2145
2272
|
const { id } = useParams();
|
|
2146
2273
|
const navigate = useNavigate();
|
|
2147
|
-
const { quote, isLoading } = useQuote(id, {
|
|
2274
|
+
const { quote, isLoading, refetch: refetchQuote } = useQuote(id, {
|
|
2148
2275
|
fields: "*draft_order,*draft_order.customer,*draft_order.shipping_address,*draft_order.billing_address"
|
|
2149
2276
|
});
|
|
2150
2277
|
const { generatePdf, downloadPdf, pdfUrl } = useQuotePdf();
|
|
2151
2278
|
const { store } = useQuoteStore();
|
|
2279
|
+
const draftOrderId = quote == null ? void 0 : quote.draft_order_id;
|
|
2152
2280
|
const { order: preview, isLoading: isPreviewLoading } = useOrderPreview(
|
|
2153
|
-
|
|
2281
|
+
draftOrderId,
|
|
2154
2282
|
{
|
|
2155
2283
|
fields: DEFAULT_ORDER_FIELDS
|
|
2156
2284
|
},
|
|
2157
|
-
{ enabled: !!
|
|
2285
|
+
{ enabled: !!draftOrderId }
|
|
2286
|
+
);
|
|
2287
|
+
useOrder(
|
|
2288
|
+
draftOrderId,
|
|
2289
|
+
{
|
|
2290
|
+
fields: DEFAULT_ORDER_FIELDS
|
|
2291
|
+
},
|
|
2292
|
+
{ enabled: !!draftOrderId }
|
|
2158
2293
|
);
|
|
2159
|
-
const { order } = useOrder(quote == null ? void 0 : quote.draft_order_id, {
|
|
2160
|
-
fields: DEFAULT_ORDER_FIELDS
|
|
2161
|
-
});
|
|
2162
|
-
console.log(order);
|
|
2163
2294
|
const prompt = usePrompt();
|
|
2164
2295
|
const { mutateAsync: rejectQuote, isPending: isRejectingQuote } = useRejectQuote(id);
|
|
2165
|
-
const [showRejectQuote, setShowRejectQuote] = useState(false);
|
|
2166
2296
|
const { mutateAsync: sendQuote, isPending: isSendingQuote } = useSendQuote(
|
|
2167
2297
|
id
|
|
2168
2298
|
);
|
|
2169
|
-
const
|
|
2170
|
-
const
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2299
|
+
const { mutateAsync: approveQuote, isPending: isApprovingQuote } = useApproveQuote(id);
|
|
2300
|
+
const { mutateAsync: voidQuote, isPending: isVoidingQuote } = useVoidQuote(
|
|
2301
|
+
id
|
|
2302
|
+
);
|
|
2303
|
+
const { mutateAsync: deleteQuote, isPending: isDeletingQuote } = useDeleteQuote(id);
|
|
2304
|
+
const quoteStatus = (quote == null ? void 0 : quote.status) ?? "";
|
|
2305
|
+
const canApproveQuote = [
|
|
2306
|
+
"pending_merchant",
|
|
2307
|
+
"pending_customer",
|
|
2308
|
+
"customer_rejected"
|
|
2309
|
+
].includes(quoteStatus);
|
|
2310
|
+
const canRejectQuote = ["pending_merchant", "pending_customer"].includes(
|
|
2311
|
+
quoteStatus
|
|
2312
|
+
);
|
|
2313
|
+
const canSendQuote = ["pending_merchant", "customer_rejected"].includes(
|
|
2314
|
+
quoteStatus
|
|
2315
|
+
);
|
|
2316
|
+
const canManageQuote = ["pending_merchant", "customer_rejected"].includes(
|
|
2317
|
+
quoteStatus
|
|
2318
|
+
);
|
|
2319
|
+
const canDeleteQuote = !["accepted", "approved", "converted"].includes(
|
|
2320
|
+
quoteStatus
|
|
2321
|
+
);
|
|
2322
|
+
const canVoidQuote = quoteStatus === "approved";
|
|
2323
|
+
const isMutatingQuote = isRejectingQuote || isSendingQuote || isApprovingQuote || isVoidingQuote || isDeletingQuote;
|
|
2324
|
+
const getErrorMessage = (error) => error instanceof Error ? error.message : "Something went wrong";
|
|
2190
2325
|
const handleRejectQuote = async () => {
|
|
2191
|
-
const
|
|
2326
|
+
const confirmed = await prompt({
|
|
2192
2327
|
title: "Reject quote?",
|
|
2193
2328
|
description: "You are about to reject this customer's quote. Do you want to continue?",
|
|
2194
|
-
confirmText: "
|
|
2329
|
+
confirmText: "Reject",
|
|
2195
2330
|
cancelText: "Cancel",
|
|
2196
2331
|
variant: "confirmation"
|
|
2197
2332
|
});
|
|
2198
|
-
if (
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2333
|
+
if (!confirmed) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
try {
|
|
2337
|
+
await rejectQuote();
|
|
2338
|
+
await refetchQuote();
|
|
2339
|
+
toast.success("Successfully rejected customer's quote");
|
|
2340
|
+
} catch (error) {
|
|
2341
|
+
toast.error(getErrorMessage(error));
|
|
2203
2342
|
}
|
|
2204
2343
|
};
|
|
2205
2344
|
const handleSendQuote = async () => {
|
|
2206
|
-
const
|
|
2345
|
+
const confirmed = await prompt({
|
|
2207
2346
|
title: "Send quote?",
|
|
2208
2347
|
description: "You are about to send this quote to the customer. Do you want to continue?",
|
|
2209
|
-
confirmText: "
|
|
2348
|
+
confirmText: "Send",
|
|
2210
2349
|
cancelText: "Cancel",
|
|
2211
2350
|
variant: "confirmation"
|
|
2212
2351
|
});
|
|
2213
|
-
if (
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2352
|
+
if (!confirmed) {
|
|
2353
|
+
return;
|
|
2354
|
+
}
|
|
2355
|
+
try {
|
|
2356
|
+
await sendQuote();
|
|
2357
|
+
await refetchQuote();
|
|
2358
|
+
toast.success("Successfully sent quote to customer");
|
|
2359
|
+
} catch (error) {
|
|
2360
|
+
toast.error(getErrorMessage(error));
|
|
2361
|
+
}
|
|
2362
|
+
};
|
|
2363
|
+
const handleApproveQuote = async () => {
|
|
2364
|
+
const confirmed = await prompt({
|
|
2365
|
+
title: "Approve quote?",
|
|
2366
|
+
description: "Approving the quote makes it ready for processing. Continue?",
|
|
2367
|
+
confirmText: "Approve",
|
|
2368
|
+
cancelText: "Cancel",
|
|
2369
|
+
variant: "confirmation"
|
|
2370
|
+
});
|
|
2371
|
+
if (!confirmed) {
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
try {
|
|
2375
|
+
await approveQuote();
|
|
2376
|
+
await refetchQuote();
|
|
2377
|
+
toast.success("Quote approved");
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
toast.error(getErrorMessage(error));
|
|
2380
|
+
}
|
|
2381
|
+
};
|
|
2382
|
+
const handleVoidQuote = async () => {
|
|
2383
|
+
const confirmed = await prompt({
|
|
2384
|
+
title: "Void approved quote?",
|
|
2385
|
+
description: "Voiding will move the quote out of the approved state. Continue?",
|
|
2386
|
+
confirmText: "Void",
|
|
2387
|
+
cancelText: "Cancel",
|
|
2388
|
+
variant: "confirmation"
|
|
2389
|
+
});
|
|
2390
|
+
if (!confirmed) {
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
try {
|
|
2394
|
+
await voidQuote();
|
|
2395
|
+
await refetchQuote();
|
|
2396
|
+
toast.success("Quote voided");
|
|
2397
|
+
} catch (error) {
|
|
2398
|
+
toast.error(getErrorMessage(error));
|
|
2399
|
+
}
|
|
2400
|
+
};
|
|
2401
|
+
const handleDeleteQuote = async () => {
|
|
2402
|
+
const confirmed = await prompt({
|
|
2403
|
+
title: "Delete quote?",
|
|
2404
|
+
description: "This will remove the quote permanently. This action cannot be undone.",
|
|
2405
|
+
confirmText: "Delete",
|
|
2406
|
+
cancelText: "Cancel",
|
|
2407
|
+
variant: "danger"
|
|
2408
|
+
});
|
|
2409
|
+
if (!confirmed) {
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
try {
|
|
2413
|
+
await deleteQuote();
|
|
2414
|
+
toast.success("Quote deleted");
|
|
2415
|
+
navigate("/quotes");
|
|
2416
|
+
} catch (error) {
|
|
2417
|
+
toast.error(getErrorMessage(error));
|
|
2218
2418
|
}
|
|
2219
2419
|
};
|
|
2220
2420
|
const parseToPdfData = () => {
|
|
@@ -2353,33 +2553,64 @@ const QuoteDetails = () => {
|
|
|
2353
2553
|
)
|
|
2354
2554
|
] })
|
|
2355
2555
|
] }),
|
|
2356
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-end gap-
|
|
2357
|
-
|
|
2556
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex flex-wrap items-center justify-end gap-2 rounded-b-xl px-4 py-4", children: [
|
|
2557
|
+
canDeleteQuote && /* @__PURE__ */ jsx(
|
|
2558
|
+
Button,
|
|
2559
|
+
{
|
|
2560
|
+
size: "small",
|
|
2561
|
+
variant: "danger",
|
|
2562
|
+
onClick: handleDeleteQuote,
|
|
2563
|
+
disabled: isMutatingQuote,
|
|
2564
|
+
children: "Delete Quote"
|
|
2565
|
+
}
|
|
2566
|
+
),
|
|
2567
|
+
canVoidQuote && /* @__PURE__ */ jsx(
|
|
2568
|
+
Button,
|
|
2569
|
+
{
|
|
2570
|
+
size: "small",
|
|
2571
|
+
variant: "secondary",
|
|
2572
|
+
onClick: handleVoidQuote,
|
|
2573
|
+
disabled: isMutatingQuote,
|
|
2574
|
+
children: "Void Quote"
|
|
2575
|
+
}
|
|
2576
|
+
),
|
|
2577
|
+
canRejectQuote && /* @__PURE__ */ jsx(
|
|
2358
2578
|
Button,
|
|
2359
2579
|
{
|
|
2360
2580
|
size: "small",
|
|
2361
2581
|
variant: "secondary",
|
|
2362
|
-
onClick:
|
|
2363
|
-
disabled:
|
|
2582
|
+
onClick: handleRejectQuote,
|
|
2583
|
+
disabled: isMutatingQuote,
|
|
2364
2584
|
children: "Reject Quote"
|
|
2365
2585
|
}
|
|
2366
2586
|
),
|
|
2367
|
-
|
|
2587
|
+
canApproveQuote && /* @__PURE__ */ jsx(
|
|
2588
|
+
Button,
|
|
2589
|
+
{
|
|
2590
|
+
size: "small",
|
|
2591
|
+
variant: "primary",
|
|
2592
|
+
onClick: handleApproveQuote,
|
|
2593
|
+
disabled: isMutatingQuote,
|
|
2594
|
+
children: "Approve Quote"
|
|
2595
|
+
}
|
|
2596
|
+
),
|
|
2597
|
+
canSendQuote && /* @__PURE__ */ jsx(
|
|
2368
2598
|
Button,
|
|
2369
2599
|
{
|
|
2370
2600
|
size: "small",
|
|
2371
2601
|
variant: "secondary",
|
|
2372
|
-
onClick:
|
|
2373
|
-
disabled:
|
|
2602
|
+
onClick: handleSendQuote,
|
|
2603
|
+
disabled: isMutatingQuote,
|
|
2374
2604
|
children: "Send Quote"
|
|
2375
2605
|
}
|
|
2376
2606
|
),
|
|
2377
|
-
|
|
2607
|
+
canManageQuote && /* @__PURE__ */ jsx(
|
|
2378
2608
|
Button,
|
|
2379
2609
|
{
|
|
2380
2610
|
size: "small",
|
|
2381
2611
|
variant: "secondary",
|
|
2382
2612
|
onClick: () => navigate(`/quotes/${quote.id}/manage`),
|
|
2613
|
+
disabled: isMutatingQuote,
|
|
2383
2614
|
children: "Manage Quote"
|
|
2384
2615
|
}
|
|
2385
2616
|
)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POST = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const merchant_approve_quote_1 = require("../../../../../workflows/merchant-approve-quote");
|
|
6
|
+
const POST = async (req, res) => {
|
|
7
|
+
const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
8
|
+
const { id } = req.params;
|
|
9
|
+
await (0, merchant_approve_quote_1.merchantApproveQuoteWorkflow)(req.scope).run({
|
|
10
|
+
input: {
|
|
11
|
+
quote_id: id,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
const { data: [quote], } = await query.graph({
|
|
15
|
+
entity: "quote",
|
|
16
|
+
filters: { id },
|
|
17
|
+
fields: req.queryConfig.fields,
|
|
18
|
+
}, { throwIfKeyNotFound: true });
|
|
19
|
+
res.json({ quote });
|
|
20
|
+
};
|
|
21
|
+
exports.POST = POST;
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3F1b3Rlcy9baWRdL2FwcHJvdmUvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEscURBQXNFO0FBQ3RFLDRGQUErRjtBQUV4RixNQUFNLElBQUksR0FBRyxLQUFLLEVBQ3ZCLEdBQStCLEVBQy9CLEdBQW1CLEVBQ25CLEVBQUU7SUFDRixNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRSxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUUxQixNQUFNLElBQUEscURBQTRCLEVBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUNoRCxLQUFLLEVBQUU7WUFDTCxRQUFRLEVBQUUsRUFBRTtTQUNiO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsTUFBTSxFQUNKLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUNkLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUNuQjtRQUNFLE1BQU0sRUFBRSxPQUFPO1FBQ2YsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFO1FBQ2YsTUFBTSxFQUFFLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTTtLQUMvQixFQUNELEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLENBQzdCLENBQUM7SUFFRixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUN0QixDQUFDLENBQUM7QUF6QlcsUUFBQSxJQUFJLFFBeUJmIn0=
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GET = void 0;
|
|
3
|
+
exports.DELETE = exports.GET = void 0;
|
|
4
4
|
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const merchant_delete_quote_1 = require("../../../../workflows/merchant-delete-quote");
|
|
5
6
|
const GET = async (req, res) => {
|
|
6
7
|
const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
7
8
|
const { id } = req.params;
|
|
@@ -13,4 +14,14 @@ const GET = async (req, res) => {
|
|
|
13
14
|
res.json({ quote });
|
|
14
15
|
};
|
|
15
16
|
exports.GET = GET;
|
|
16
|
-
|
|
17
|
+
const DELETE = async (req, res) => {
|
|
18
|
+
const { id } = req.params;
|
|
19
|
+
await (0, merchant_delete_quote_1.merchantDeleteQuoteWorkflow)(req.scope).run({
|
|
20
|
+
input: {
|
|
21
|
+
quote_id: id,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
res.status(204).send();
|
|
25
|
+
};
|
|
26
|
+
exports.DELETE = DELETE;
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3F1b3Rlcy9baWRdL3JvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUlBLHFEQUFzRTtBQUN0RSx1RkFBMEY7QUFFbkYsTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUN0QixHQUErQixFQUMvQixHQUFtQixFQUNuQixFQUFFO0lBQ0YsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsaUNBQXlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDakUsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFFMUIsTUFBTSxFQUNKLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUNkLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUNuQjtRQUNFLE1BQU0sRUFBRSxPQUFPO1FBQ2YsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFO1FBQ2YsTUFBTSxFQUFFLENBQUMsR0FBRyxHQUFHLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSw4QkFBOEIsQ0FBQztLQUNwRSxFQUNELEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLENBQzdCLENBQUM7SUFFRixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUN0QixDQUFDLENBQUM7QUFuQlcsUUFBQSxHQUFHLE9BbUJkO0FBRUssTUFBTSxNQUFNLEdBQUcsS0FBSyxFQUN6QixHQUErQixFQUMvQixHQUFtQixFQUNuQixFQUFFO0lBQ0YsTUFBTSxFQUFFLEVBQUUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFFMUIsTUFBTSxJQUFBLG1EQUEyQixFQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7UUFDL0MsS0FBSyxFQUFFO1lBQ0wsUUFBUSxFQUFFLEVBQUU7U0FDYjtLQUNGLENBQUMsQ0FBQztJQUVILEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDekIsQ0FBQyxDQUFDO0FBYlcsUUFBQSxNQUFNLFVBYWpCIn0=
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.POST = void 0;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const merchant_void_quote_1 = require("../../../../../workflows/merchant-void-quote");
|
|
6
|
+
const POST = async (req, res) => {
|
|
7
|
+
const query = req.scope.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
8
|
+
const { id } = req.params;
|
|
9
|
+
await (0, merchant_void_quote_1.merchantVoidQuoteWorkflow)(req.scope).run({
|
|
10
|
+
input: {
|
|
11
|
+
quote_id: id,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
const { data: [quote], } = await query.graph({
|
|
15
|
+
entity: "quote",
|
|
16
|
+
filters: { id },
|
|
17
|
+
fields: req.queryConfig.fields,
|
|
18
|
+
}, { throwIfKeyNotFound: true });
|
|
19
|
+
res.json({ quote });
|
|
20
|
+
};
|
|
21
|
+
exports.POST = POST;
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9zcmMvYXBpL2FkbWluL3F1b3Rlcy9baWRdL3ZvaWQvcm91dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBSUEscURBQXNFO0FBQ3RFLHNGQUF5RjtBQUVsRixNQUFNLElBQUksR0FBRyxLQUFLLEVBQ3ZCLEdBQStCLEVBQy9CLEdBQW1CLEVBQ25CLEVBQUU7SUFDRixNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRSxNQUFNLEVBQUUsRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztJQUUxQixNQUFNLElBQUEsK0NBQXlCLEVBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUM3QyxLQUFLLEVBQUU7WUFDTCxRQUFRLEVBQUUsRUFBRTtTQUNiO0tBQ0YsQ0FBQyxDQUFDO0lBRUgsTUFBTSxFQUNKLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUNkLEdBQUcsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUNuQjtRQUNFLE1BQU0sRUFBRSxPQUFPO1FBQ2YsT0FBTyxFQUFFLEVBQUUsRUFBRSxFQUFFO1FBQ2YsTUFBTSxFQUFFLEdBQUcsQ0FBQyxXQUFXLENBQUMsTUFBTTtLQUMvQixFQUNELEVBQUUsa0JBQWtCLEVBQUUsSUFBSSxFQUFFLENBQzdCLENBQUM7SUFFRixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUN0QixDQUFDLENBQUM7QUF6QlcsUUFBQSxJQUFJLFFBeUJmIn0=
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Migration20251028120000 = void 0;
|
|
4
|
+
const migrations_1 = require("@medusajs/framework/mikro-orm/migrations");
|
|
5
|
+
const QUOTE_STATUS_CONSTRAINT = "'draft', 'pending_merchant', 'pending_customer', 'approved', 'accepted', 'customer_rejected', 'merchant_rejected', 'voided', 'expired', 'converted'";
|
|
6
|
+
const PREVIOUS_QUOTE_STATUS_CONSTRAINT = "'draft', 'pending_merchant', 'pending_customer', 'accepted', 'customer_rejected', 'merchant_rejected', 'expired', 'converted'";
|
|
7
|
+
class Migration20251028120000 extends migrations_1.Migration {
|
|
8
|
+
async up() {
|
|
9
|
+
this.addSql(`alter table if exists "quote" drop constraint if exists "quote_status_check";`);
|
|
10
|
+
this.addSql(`alter table if exists "quote" add constraint "quote_status_check" check("status" in (${QUOTE_STATUS_CONSTRAINT}));`);
|
|
11
|
+
}
|
|
12
|
+
async down() {
|
|
13
|
+
this.addSql(`alter table if exists "quote" drop constraint if exists "quote_status_check";`);
|
|
14
|
+
this.addSql(`alter table if exists "quote" add constraint "quote_status_check" check("status" in (${PREVIOUS_QUOTE_STATUS_CONSTRAINT}));`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.Migration20251028120000 = Migration20251028120000;
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uMjAyNTEwMjgxMjAwMDAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbW9kdWxlcy9xdW90ZS9taWdyYXRpb25zL01pZ3JhdGlvbjIwMjUxMDI4MTIwMDAwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlFQUFxRTtBQUVyRSxNQUFNLHVCQUF1QixHQUMzQixxSkFBcUosQ0FBQztBQUV4SixNQUFNLGdDQUFnQyxHQUNwQywrSEFBK0gsQ0FBQztBQUVsSSxNQUFhLHVCQUF3QixTQUFRLHNCQUFTO0lBQzNDLEtBQUssQ0FBQyxFQUFFO1FBQ2YsSUFBSSxDQUFDLE1BQU0sQ0FDVCwrRUFBK0UsQ0FDaEYsQ0FBQztRQUVGLElBQUksQ0FBQyxNQUFNLENBQ1Qsd0ZBQXdGLHVCQUF1QixLQUFLLENBQ3JILENBQUM7SUFDSixDQUFDO0lBRVEsS0FBSyxDQUFDLElBQUk7UUFDakIsSUFBSSxDQUFDLE1BQU0sQ0FDVCwrRUFBK0UsQ0FDaEYsQ0FBQztRQUVGLElBQUksQ0FBQyxNQUFNLENBQ1Qsd0ZBQXdGLGdDQUFnQyxLQUFLLENBQzlILENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFwQkQsMERBb0JDIn0=
|