payment-kit 1.20.11 → 1.20.13

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.
Files changed (92) hide show
  1. package/api/src/crons/index.ts +8 -0
  2. package/api/src/index.ts +2 -0
  3. package/api/src/integrations/stripe/handlers/invoice.ts +63 -5
  4. package/api/src/integrations/stripe/handlers/payment-intent.ts +1 -0
  5. package/api/src/integrations/stripe/resource.ts +253 -2
  6. package/api/src/libs/currency.ts +31 -0
  7. package/api/src/libs/discount/coupon.ts +1061 -0
  8. package/api/src/libs/discount/discount.ts +349 -0
  9. package/api/src/libs/discount/nft.ts +239 -0
  10. package/api/src/libs/discount/redemption.ts +636 -0
  11. package/api/src/libs/discount/vc.ts +73 -0
  12. package/api/src/libs/env.ts +1 -0
  13. package/api/src/libs/invoice.ts +44 -10
  14. package/api/src/libs/math-utils.ts +6 -0
  15. package/api/src/libs/price.ts +43 -0
  16. package/api/src/libs/session.ts +242 -57
  17. package/api/src/libs/subscription.ts +2 -6
  18. package/api/src/libs/vendor-util/adapters/launcher-adapter.ts +1 -1
  19. package/api/src/libs/vendor-util/adapters/types.ts +1 -0
  20. package/api/src/libs/vendor-util/fulfillment.ts +1 -1
  21. package/api/src/queues/auto-recharge.ts +1 -1
  22. package/api/src/queues/discount-status.ts +200 -0
  23. package/api/src/queues/subscription.ts +98 -5
  24. package/api/src/queues/usage-record.ts +1 -1
  25. package/api/src/queues/vendors/fulfillment-coordinator.ts +1 -29
  26. package/api/src/queues/vendors/return-processor.ts +184 -0
  27. package/api/src/queues/vendors/return-scanner.ts +119 -0
  28. package/api/src/queues/vendors/status-check.ts +1 -1
  29. package/api/src/routes/auto-recharge-configs.ts +5 -3
  30. package/api/src/routes/checkout-sessions.ts +755 -64
  31. package/api/src/routes/connect/change-payment.ts +6 -1
  32. package/api/src/routes/connect/change-plan.ts +6 -1
  33. package/api/src/routes/connect/setup.ts +6 -1
  34. package/api/src/routes/connect/shared.ts +80 -9
  35. package/api/src/routes/connect/subscribe.ts +12 -2
  36. package/api/src/routes/coupons.ts +518 -0
  37. package/api/src/routes/index.ts +4 -0
  38. package/api/src/routes/invoices.ts +44 -3
  39. package/api/src/routes/meter-events.ts +2 -1
  40. package/api/src/routes/payment-currencies.ts +1 -0
  41. package/api/src/routes/promotion-codes.ts +482 -0
  42. package/api/src/routes/subscriptions.ts +23 -2
  43. package/api/src/routes/vendor.ts +89 -2
  44. package/api/src/store/migrations/20250904-discount.ts +136 -0
  45. package/api/src/store/migrations/20250910-timestamp-fields.ts +116 -0
  46. package/api/src/store/migrations/20250916-add-description-fields.ts +30 -0
  47. package/api/src/store/migrations/20250918-add-vendor-extends.ts +20 -0
  48. package/api/src/store/models/checkout-session.ts +17 -2
  49. package/api/src/store/models/coupon.ts +144 -4
  50. package/api/src/store/models/discount.ts +23 -10
  51. package/api/src/store/models/index.ts +13 -2
  52. package/api/src/store/models/product-vendor.ts +6 -0
  53. package/api/src/store/models/promotion-code.ts +295 -18
  54. package/api/src/store/models/types.ts +30 -1
  55. package/api/tests/libs/session.spec.ts +48 -27
  56. package/blocklet.yml +1 -1
  57. package/package.json +20 -20
  58. package/src/app.tsx +2 -0
  59. package/src/components/customer/link.tsx +1 -1
  60. package/src/components/discount/discount-info.tsx +178 -0
  61. package/src/components/invoice/table.tsx +140 -48
  62. package/src/components/invoice-pdf/styles.ts +6 -0
  63. package/src/components/invoice-pdf/template.tsx +59 -33
  64. package/src/components/metadata/form.tsx +14 -5
  65. package/src/components/payment-link/actions.tsx +42 -0
  66. package/src/components/price/form.tsx +91 -65
  67. package/src/components/product/vendor-config.tsx +5 -3
  68. package/src/components/promotion/active-redemptions.tsx +534 -0
  69. package/src/components/promotion/currency-multi-select.tsx +350 -0
  70. package/src/components/promotion/currency-restrictions.tsx +117 -0
  71. package/src/components/promotion/product-select.tsx +292 -0
  72. package/src/components/promotion/promotion-code-form.tsx +534 -0
  73. package/src/components/subscription/portal/list.tsx +6 -1
  74. package/src/components/subscription/vendor-service-list.tsx +13 -2
  75. package/src/locales/en.tsx +227 -0
  76. package/src/locales/zh.tsx +222 -1
  77. package/src/pages/admin/billing/subscriptions/detail.tsx +5 -0
  78. package/src/pages/admin/products/coupons/applicable-products.tsx +166 -0
  79. package/src/pages/admin/products/coupons/create.tsx +612 -0
  80. package/src/pages/admin/products/coupons/detail.tsx +538 -0
  81. package/src/pages/admin/products/coupons/edit.tsx +127 -0
  82. package/src/pages/admin/products/coupons/index.tsx +210 -3
  83. package/src/pages/admin/products/index.tsx +22 -3
  84. package/src/pages/admin/products/products/detail.tsx +12 -2
  85. package/src/pages/admin/products/promotion-codes/actions.tsx +103 -0
  86. package/src/pages/admin/products/promotion-codes/create.tsx +235 -0
  87. package/src/pages/admin/products/promotion-codes/detail.tsx +416 -0
  88. package/src/pages/admin/products/promotion-codes/list.tsx +247 -0
  89. package/src/pages/admin/products/promotion-codes/verification-config.tsx +327 -0
  90. package/src/pages/admin/products/vendors/index.tsx +17 -5
  91. package/src/pages/customer/subscription/detail.tsx +5 -0
  92. package/vite.config.ts +4 -3
@@ -0,0 +1,166 @@
1
+ /* eslint-disable react/no-unstable-nested-components */
2
+ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
3
+ import {
4
+ findCurrency,
5
+ formatPrice,
6
+ formatTime,
7
+ Table,
8
+ TruncatedText,
9
+ useMobile,
10
+ usePaymentContext,
11
+ } from '@blocklet/payment-react';
12
+ import type { TProductExpanded } from '@blocklet/payment-types';
13
+ import { Avatar, Stack, Typography, Box } from '@mui/material';
14
+ import { styled } from '@mui/system';
15
+ import { Link } from 'react-router-dom';
16
+
17
+ interface Props {
18
+ products: any[];
19
+ }
20
+
21
+ export default function ApplicableProductsList({ products }: Props) {
22
+ const { t } = useLocaleContext();
23
+ const { isMobile } = useMobile();
24
+ const { settings } = usePaymentContext();
25
+
26
+ const getPriceDisplay = (product: TProductExpanded) => {
27
+ if (!product.prices || product.prices.length === 0) {
28
+ return null;
29
+ }
30
+
31
+ if (product.prices.length === 1) {
32
+ const price = product.prices[0];
33
+ if (price) {
34
+ const currency = findCurrency(settings.paymentMethods, price.currency_id ?? '') || settings.baseCurrency;
35
+ return formatPrice(price, currency!);
36
+ }
37
+ }
38
+
39
+ return t('admin.price.count', { count: product.prices.length });
40
+ };
41
+
42
+ const size = isMobile ? { width: 24, height: 24 } : { width: 48, height: 48 };
43
+
44
+ const columns = [
45
+ {
46
+ label: t('admin.subscription.product'),
47
+ name: 'name',
48
+ options: {
49
+ customBodyRenderLite: (_: string, index: number) => {
50
+ const product = products[index];
51
+ return (
52
+ <Stack
53
+ sx={{
54
+ flexDirection: 'row',
55
+ flexWrap: 'wrap',
56
+ alignItems: 'center',
57
+ gap: {
58
+ xs: 1,
59
+ sm: 2,
60
+ },
61
+ }}>
62
+ <Box>
63
+ {product.images && product.images.length > 0 ? (
64
+ <Avatar key={product.id} src={product.images[0]} alt={product.name} variant="rounded" sx={size} />
65
+ ) : (
66
+ <Avatar key={product.id} variant="rounded" sx={size}>
67
+ {product.name.slice(0, 1)}
68
+ </Avatar>
69
+ )}
70
+ </Box>
71
+ <Box>
72
+ <Typography
73
+ sx={{
74
+ color: 'text.primary',
75
+ fontWeight: 600,
76
+ }}>
77
+ <Link to={`/admin/products/${product.id}`}>
78
+ <TruncatedText text={product.name} maxLength={isMobile ? 20 : 50} useWidth />
79
+ </Link>
80
+ </Typography>
81
+ {!isMobile && (
82
+ <Typography
83
+ sx={{
84
+ color: 'text.secondary',
85
+ whiteSpace: 'nowrap',
86
+ }}>
87
+ {getPriceDisplay(product)}
88
+ </Typography>
89
+ )}
90
+ </Box>
91
+ </Stack>
92
+ );
93
+ },
94
+ },
95
+ },
96
+ isMobile && {
97
+ label: t('admin.product.pricing'),
98
+ name: 'prices',
99
+ options: {
100
+ customBodyRenderLite: (_: string, index: number) => {
101
+ const product = products[index];
102
+ return <Link to={`/admin/products/${product.id}`}>{getPriceDisplay(product)}</Link>;
103
+ },
104
+ },
105
+ },
106
+ {
107
+ label: t('admin.product.type.label'),
108
+ name: 'type',
109
+ options: {
110
+ customBodyRenderLite: (_: string, index: number) => {
111
+ const product = products[index];
112
+ return t(`admin.product.type.${product.type}`);
113
+ },
114
+ },
115
+ },
116
+ {
117
+ label: t('common.created'),
118
+ name: 'created_at',
119
+ options: {
120
+ customBodyRenderLite: (_: string, index: number) => {
121
+ const product = products[index];
122
+ return formatTime(product.created_at);
123
+ },
124
+ },
125
+ },
126
+ ].filter(Boolean);
127
+
128
+ return (
129
+ <ApplicableProductsTableRoot>
130
+ <Table
131
+ data={products}
132
+ columns={columns}
133
+ loading={false}
134
+ footer={false}
135
+ toolbar={false}
136
+ components={{
137
+ TableToolbar: () => null,
138
+ TableFooter: () => null,
139
+ }}
140
+ mobileTDFlexDirection="row"
141
+ options={{
142
+ count: products.length,
143
+ page: 0,
144
+ rowsPerPage: 100,
145
+ selectableRows: 'none',
146
+ pagination: false,
147
+ }}
148
+ emptyNodeText={t('admin.coupon.noApplicableProducts')}
149
+ />
150
+ </ApplicableProductsTableRoot>
151
+ );
152
+ }
153
+
154
+ const ApplicableProductsTableRoot = styled(Box)`
155
+ @media (max-width: ${({ theme }) => theme.breakpoints.values.md}px) {
156
+ .MuiTable-root > .MuiTableBody-root > .MuiTableRow-root > td.MuiTableCell-root {
157
+ align-items: center;
158
+ padding: 4px 0;
159
+ > div {
160
+ width: fit-content;
161
+ flex: inherit;
162
+ font-size: 14px;
163
+ }
164
+ }
165
+ }
166
+ `;