payment-kit 1.13.216 → 1.13.217
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/blocklet.yml +1 -1
- package/package.json +5 -4
- package/public/fonts/noto-sans-sc-chinese-simplified-500-normal.ttf +0 -0
- package/src/components/invoice/action.tsx +0 -6
- package/src/components/invoice-pdf/compose.ts +172 -0
- package/src/components/invoice-pdf/pdf.tsx +222 -0
- package/src/components/progress-bar.tsx +0 -1
- package/src/locales/en.tsx +1 -1
- package/src/locales/zh.tsx +1 -1
- package/src/pages/admin/billing/invoices/detail.tsx +6 -2
- package/src/pages/customer/invoice/detail.tsx +3 -14
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.217",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "cross-env COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev --open",
|
|
6
6
|
"eject": "vite eject",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@arcblock/ux": "^2.9.66",
|
|
52
52
|
"@arcblock/validator": "^1.18.115",
|
|
53
53
|
"@blocklet/logger": "1.16.25",
|
|
54
|
-
"@blocklet/payment-react": "1.13.
|
|
54
|
+
"@blocklet/payment-react": "1.13.217",
|
|
55
55
|
"@blocklet/sdk": "1.16.25",
|
|
56
56
|
"@blocklet/ui-react": "^2.9.66",
|
|
57
57
|
"@blocklet/uploader": "^0.0.76",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@ocap/mcrypto": "^1.18.115",
|
|
66
66
|
"@ocap/util": "^1.18.115",
|
|
67
67
|
"@ocap/wallet": "^1.18.115",
|
|
68
|
+
"@react-pdf/renderer": "^3.4.2",
|
|
68
69
|
"@stripe/react-stripe-js": "^2.4.0",
|
|
69
70
|
"@stripe/stripe-js": "^2.4.0",
|
|
70
71
|
"ahooks": "^3.7.10",
|
|
@@ -114,7 +115,7 @@
|
|
|
114
115
|
"devDependencies": {
|
|
115
116
|
"@abtnode/types": "1.16.25",
|
|
116
117
|
"@arcblock/eslint-config-ts": "^0.3.0",
|
|
117
|
-
"@blocklet/payment-types": "1.13.
|
|
118
|
+
"@blocklet/payment-types": "1.13.217",
|
|
118
119
|
"@types/cookie-parser": "^1.4.6",
|
|
119
120
|
"@types/cors": "^2.8.17",
|
|
120
121
|
"@types/dotenv-flow": "^3.3.3",
|
|
@@ -153,5 +154,5 @@
|
|
|
153
154
|
"parser": "typescript"
|
|
154
155
|
}
|
|
155
156
|
},
|
|
156
|
-
"gitHead": "
|
|
157
|
+
"gitHead": "3ce8954d7c26c881e0a7a46925447318954adca9"
|
|
157
158
|
}
|
|
Binary file
|
|
@@ -48,12 +48,6 @@ export default function InvoiceActions({ data, variant, onChange, mode }: Props)
|
|
|
48
48
|
const isAdmin = mode === 'admin';
|
|
49
49
|
|
|
50
50
|
const actions = [
|
|
51
|
-
{
|
|
52
|
-
label: t('admin.invoice.download'),
|
|
53
|
-
handler: () => setState({ action: 'download' }),
|
|
54
|
-
color: 'primary',
|
|
55
|
-
disabled: data.status !== 'paid',
|
|
56
|
-
},
|
|
57
51
|
isAdmin && {
|
|
58
52
|
label: t('admin.invoice.edit'),
|
|
59
53
|
handler: () => setState({ action: 'edit' }),
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
const compose = (classes: string) => {
|
|
2
|
+
const css = {};
|
|
3
|
+
|
|
4
|
+
const classesArray: string[] = classes.replace(/\s+/g, ' ').split(' ');
|
|
5
|
+
|
|
6
|
+
classesArray.forEach((className) => {
|
|
7
|
+
if (typeof styles[className] !== undefined) {
|
|
8
|
+
Object.assign(css, styles[className]);
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return css;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const colorDark = '#222';
|
|
16
|
+
const colorDark2 = '#888';
|
|
17
|
+
const colorGray = '#e3e3e3';
|
|
18
|
+
const colorWhite = '#fff';
|
|
19
|
+
|
|
20
|
+
const styles: any = {
|
|
21
|
+
dark: {
|
|
22
|
+
color: colorDark,
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
white: {
|
|
26
|
+
color: colorWhite,
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
gray: {
|
|
30
|
+
color: colorDark2,
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
'bg-dark': {
|
|
34
|
+
backgroundColor: colorDark2,
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
'bg-gray': {
|
|
38
|
+
backgroundColor: colorGray,
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
flex: {
|
|
42
|
+
display: 'flex',
|
|
43
|
+
flexDirection: 'row',
|
|
44
|
+
flexWrap: 'nowrap',
|
|
45
|
+
alignItems: 'start',
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
bold: {
|
|
49
|
+
fontWeight: 'bold',
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
'w-auto': {
|
|
53
|
+
flex: 1,
|
|
54
|
+
paddingRight: '8px',
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
'flex-1': {
|
|
58
|
+
flex: 1,
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
'w-100': {
|
|
62
|
+
width: '100%',
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
'w-50': {
|
|
66
|
+
width: '50%',
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
'w-55': {
|
|
70
|
+
width: '55%',
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
'w-45': {
|
|
74
|
+
width: '45%',
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
'w-60': {
|
|
78
|
+
width: '60%',
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
'w-40': {
|
|
82
|
+
width: '30%',
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
'w-48': {
|
|
86
|
+
width: '48%',
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
'w-17': {
|
|
90
|
+
width: '17%',
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
'w-18': {
|
|
94
|
+
width: '18%',
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
row: {
|
|
98
|
+
borderBottom: `1px solid ${colorGray}`,
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
'mt-40': {
|
|
102
|
+
marginTop: '40px',
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
'mt-30': {
|
|
106
|
+
marginTop: '30px',
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
'mt-20': {
|
|
110
|
+
marginTop: '20px',
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
'mt-10': {
|
|
114
|
+
marginTop: '10px',
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
'mb-5': {
|
|
118
|
+
marginBottom: '5px',
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
'p-4-8': {
|
|
122
|
+
padding: '4px 8px',
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
'p-5': {
|
|
126
|
+
padding: '5px',
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
'pb-10': {
|
|
130
|
+
paddingBottom: '10px',
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
right: {
|
|
134
|
+
textAlign: 'right',
|
|
135
|
+
},
|
|
136
|
+
center: {
|
|
137
|
+
textAlign: 'right',
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
'fs-20': {
|
|
141
|
+
fontSize: '20px',
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
'fs-30': {
|
|
145
|
+
fontSize: '30px',
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
'fs-12': {
|
|
149
|
+
fontSize: '11px',
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
page: {
|
|
153
|
+
fontFamily: 'Noto Sans SC',
|
|
154
|
+
fontSize: '11px',
|
|
155
|
+
color: '#555',
|
|
156
|
+
padding: '40px 35px',
|
|
157
|
+
fontWeight: 'bold',
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
span: {
|
|
161
|
+
padding: '4px 12px 4px 0',
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
logo: {
|
|
165
|
+
display: 'block',
|
|
166
|
+
borderRadius: '10px',
|
|
167
|
+
width: '60px',
|
|
168
|
+
height: '60px',
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export default compose;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
|
|
2
|
+
import { formatAmount, formatTime, getPrefix, getPriceUintAmountByCurrency } from '@blocklet/payment-react';
|
|
3
|
+
import { Button } from '@mui/material';
|
|
4
|
+
import {
|
|
5
|
+
Font,
|
|
6
|
+
PDFDownloadLink,
|
|
7
|
+
Document as PdfDocument,
|
|
8
|
+
Image as PdfImage,
|
|
9
|
+
Page as PdfPage,
|
|
10
|
+
Text as PdfText,
|
|
11
|
+
View as PdfView,
|
|
12
|
+
} from '@react-pdf/renderer';
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
import { joinURL } from 'ufo';
|
|
15
|
+
|
|
16
|
+
import compose from './compose';
|
|
17
|
+
|
|
18
|
+
Font.register({
|
|
19
|
+
family: 'Noto Sans SC',
|
|
20
|
+
src: joinURL(getPrefix(), '/fonts/noto-sans-sc-chinese-simplified-500-normal.ttf'),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function Document({ children }: any) {
|
|
24
|
+
return <PdfDocument>{children}</PdfDocument>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function Text2({ className, value }: any) {
|
|
28
|
+
return <PdfText style={compose(`span ${className || ''}`)}>{value}</PdfText>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Text({ className, children }: any) {
|
|
32
|
+
return <PdfText style={compose(`span ${className || ''}`)}>{children}</PdfText>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function View({ className, children }: any) {
|
|
36
|
+
return <PdfView style={compose(`view ${className || ''}`)}>{children}</PdfView>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function Page({ className, children }: any) {
|
|
40
|
+
return (
|
|
41
|
+
<PdfPage size="A4" style={compose(`page ${className || ''}`)}>
|
|
42
|
+
{children}
|
|
43
|
+
</PdfPage>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function Download({ data }: any) {
|
|
48
|
+
const { t } = useLocaleContext();
|
|
49
|
+
const title = data.number;
|
|
50
|
+
return (
|
|
51
|
+
<div className="download-pdf ">
|
|
52
|
+
<PDFDownloadLink
|
|
53
|
+
key="pdf"
|
|
54
|
+
document={<InvoicePage data={data} t={t} />}
|
|
55
|
+
fileName={`${title}.pdf`}
|
|
56
|
+
aria-label="Save PDF"
|
|
57
|
+
title="Save PDF"
|
|
58
|
+
className="download-pdf__pdf">
|
|
59
|
+
<Button variant="contained" color="primary" size="small">
|
|
60
|
+
{t('payment.customer.invoice.download')}
|
|
61
|
+
</Button>
|
|
62
|
+
</PDFDownloadLink>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function InvoicePage({ data, t }: any) {
|
|
68
|
+
const [subTotal, setSubTotal] = useState(0);
|
|
69
|
+
|
|
70
|
+
const calculateAmount = (quantity: string, rate: string) => {
|
|
71
|
+
const quantityNumber = parseFloat(quantity);
|
|
72
|
+
const rateNumber = parseFloat(rate);
|
|
73
|
+
const amount = quantityNumber && rateNumber ? quantityNumber * rateNumber : 0;
|
|
74
|
+
return amount.toFixed(2);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
let temp = 0;
|
|
79
|
+
|
|
80
|
+
data.productLines.forEach((productLine: any) => {
|
|
81
|
+
const quantityNumber = parseFloat(productLine.quantity);
|
|
82
|
+
const rateNumber = parseFloat(productLine.rate);
|
|
83
|
+
const amount = quantityNumber && rateNumber ? quantityNumber * rateNumber : 0;
|
|
84
|
+
|
|
85
|
+
temp += amount;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
setSubTotal(temp);
|
|
89
|
+
}, [data.productLines]);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Document>
|
|
93
|
+
<Page className="invoice-wrapper">
|
|
94
|
+
<View className="flex">
|
|
95
|
+
<View className="w-50 flex-1">
|
|
96
|
+
<Text2 className="fs-20 bold" value={t('admin.invoice.name')} />
|
|
97
|
+
</View>
|
|
98
|
+
<View className="right">
|
|
99
|
+
<PdfImage
|
|
100
|
+
style={{
|
|
101
|
+
...compose('image logo center'),
|
|
102
|
+
}}
|
|
103
|
+
src={window.blocklet.appLogo}
|
|
104
|
+
/>
|
|
105
|
+
<Text2 value={window.blocklet.appName} className="center p-10" />
|
|
106
|
+
</View>
|
|
107
|
+
</View>
|
|
108
|
+
|
|
109
|
+
<View className="flex mt-40">
|
|
110
|
+
<View className="w-60">
|
|
111
|
+
<Text2 className="bold dark mb-5" value={t('admin.invoice.billTo')} />
|
|
112
|
+
<Text2 value={data.customer.name} />
|
|
113
|
+
<Text2 className="blod fs-12" value={`DID:ABT: ${data.customer.did}`} />
|
|
114
|
+
</View>
|
|
115
|
+
<View className="w-45">
|
|
116
|
+
<View className="flex mb-5">
|
|
117
|
+
<View className="w-45">
|
|
118
|
+
<Text2 className="bold" value={t('admin.invoice.number')} />
|
|
119
|
+
</View>
|
|
120
|
+
<View className="w-60">
|
|
121
|
+
<Text2 value={data.number} className="gray" />
|
|
122
|
+
</View>
|
|
123
|
+
</View>
|
|
124
|
+
<View className="flex mb-5">
|
|
125
|
+
<View className="w-45">
|
|
126
|
+
<Text2 className="bold" value={t('admin.invoice.paidAt')} />
|
|
127
|
+
</View>
|
|
128
|
+
<View className="w-60">
|
|
129
|
+
<Text2 value={formatTime(data.period_start * 1000)} className="gray" />
|
|
130
|
+
</View>
|
|
131
|
+
</View>
|
|
132
|
+
<View className="flex mb-5">
|
|
133
|
+
<View className="w-45">
|
|
134
|
+
<Text2 className="bold" value={t('admin.invoice.dueDate')} />
|
|
135
|
+
</View>
|
|
136
|
+
<View className="w-60">
|
|
137
|
+
<Text2 value={formatTime(data.period_end * 1000)} className="gray" />
|
|
138
|
+
</View>
|
|
139
|
+
</View>
|
|
140
|
+
</View>
|
|
141
|
+
</View>
|
|
142
|
+
|
|
143
|
+
<View className="mt-30 row flex">
|
|
144
|
+
<View className="w-48 p-4-8">
|
|
145
|
+
<Text2 className="bold" value={t('admin.subscription.product')} />
|
|
146
|
+
</View>
|
|
147
|
+
<View className="w-17 p-4-8">
|
|
148
|
+
<Text2 className="bold right" value={t('common.quantity')} />
|
|
149
|
+
</View>
|
|
150
|
+
<View className="w-17 p-4-8">
|
|
151
|
+
<Text2 className="bold right" value={t('payment.customer.invoice.unitPrice')} />
|
|
152
|
+
</View>
|
|
153
|
+
<View className="w-18 p-4-8">
|
|
154
|
+
<Text2 className="bold right" value={t('common.amount')} />
|
|
155
|
+
</View>
|
|
156
|
+
</View>
|
|
157
|
+
|
|
158
|
+
{data.lines
|
|
159
|
+
.map((line: any) => {
|
|
160
|
+
return {
|
|
161
|
+
description:
|
|
162
|
+
line.description + (line.price.product.unit_label ? ` (per ${line.price.product.unit_label})` : ''),
|
|
163
|
+
quantity: line.quantity,
|
|
164
|
+
rate: !line.proration
|
|
165
|
+
? formatAmount(getPriceUintAmountByCurrency(line.price, data.paymentCurrency) || line.amount, data.paymentCurrency.decimal) // prettier-ignore
|
|
166
|
+
: '',
|
|
167
|
+
};
|
|
168
|
+
})
|
|
169
|
+
.map((productLine: any) => {
|
|
170
|
+
return (
|
|
171
|
+
<View key={productLine.description} className="row flex">
|
|
172
|
+
<View className="w-48 p-4-8 pb-10">
|
|
173
|
+
<Text2 className="dark" value={productLine.description} />
|
|
174
|
+
</View>
|
|
175
|
+
<View className="w-17 p-4-8 pb-10">
|
|
176
|
+
<Text2 className="dark right" value={productLine.quantity} />
|
|
177
|
+
</View>
|
|
178
|
+
<View className="w-17 p-4-8 pb-10">
|
|
179
|
+
<Text className="dark right">
|
|
180
|
+
{productLine.rate} {data.paymentCurrency.symbol}
|
|
181
|
+
</Text>
|
|
182
|
+
</View>
|
|
183
|
+
<View className="w-18 p-4-8 pb-10">
|
|
184
|
+
<Text className="dark right">
|
|
185
|
+
{calculateAmount(productLine.quantity, productLine.rate)} {data.paymentCurrency.symbol}
|
|
186
|
+
</Text>
|
|
187
|
+
</View>
|
|
188
|
+
</View>
|
|
189
|
+
);
|
|
190
|
+
})}
|
|
191
|
+
|
|
192
|
+
<View className="flex">
|
|
193
|
+
<View className="w-50 mt-10" />
|
|
194
|
+
<View className="w-50 mt-20">
|
|
195
|
+
<View className="flex">
|
|
196
|
+
<View className="w-50 p-5">
|
|
197
|
+
<Text2 value={t('common.subtotal')} className="bold" />
|
|
198
|
+
</View>
|
|
199
|
+
<View className="w-50 p-5">
|
|
200
|
+
<Text className="right bold dark">
|
|
201
|
+
{subTotal?.toFixed(2)} {data.paymentCurrency.symbol}
|
|
202
|
+
</Text>
|
|
203
|
+
</View>
|
|
204
|
+
</View>
|
|
205
|
+
<View className="flex">
|
|
206
|
+
<View className="w-50 p-5">
|
|
207
|
+
<Text2 className="bold" value={t('common.total')} />
|
|
208
|
+
</View>
|
|
209
|
+
<View className="w-50 p-5">
|
|
210
|
+
<Text className="right bold dark">
|
|
211
|
+
{(typeof subTotal !== 'undefined' ? subTotal : 0).toFixed(2)} {data.paymentCurrency.symbol}
|
|
212
|
+
</Text>
|
|
213
|
+
</View>
|
|
214
|
+
</View>
|
|
215
|
+
</View>
|
|
216
|
+
</View>
|
|
217
|
+
</Page>
|
|
218
|
+
</Document>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export default InvoicePage;
|
|
@@ -44,7 +44,6 @@ const Transition = React.createContext({} as any);
|
|
|
44
44
|
|
|
45
45
|
export function TransitionProvider({ children }: { children: React.ReactNode }) {
|
|
46
46
|
const [isPending, startTransition] = React.useTransition();
|
|
47
|
-
|
|
48
47
|
const memoObj = React.useMemo(() => ({ isPending, startTransition }), [isPending]);
|
|
49
48
|
return <Transition.Provider value={memoObj}>{children}</Transition.Provider>;
|
|
50
49
|
}
|
package/src/locales/en.tsx
CHANGED
package/src/locales/zh.tsx
CHANGED
|
@@ -22,6 +22,7 @@ import Currency from '../../../../components/currency';
|
|
|
22
22
|
import CustomerLink from '../../../../components/customer/link';
|
|
23
23
|
import EventList from '../../../../components/event/list';
|
|
24
24
|
import InfoRow from '../../../../components/info-row';
|
|
25
|
+
import { Download } from '../../../../components/invoice-pdf/pdf';
|
|
25
26
|
import InvoiceActions from '../../../../components/invoice/action';
|
|
26
27
|
import InvoiceTable from '../../../../components/invoice/table';
|
|
27
28
|
import MetadataEditor from '../../../../components/metadata/editor';
|
|
@@ -103,7 +104,10 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
103
104
|
</Typography>
|
|
104
105
|
<Status label={data.status} color={getInvoiceStatusColor(data.status)} sx={{ ml: 1 }} />
|
|
105
106
|
</Stack>
|
|
106
|
-
<
|
|
107
|
+
<Box style={{ display: 'flex', gap: '10px' }}>
|
|
108
|
+
<Download data={data} />
|
|
109
|
+
<InvoiceActions data={data} onChange={runAsync} variant="normal" />
|
|
110
|
+
</Box>
|
|
107
111
|
</Stack>
|
|
108
112
|
</Box>
|
|
109
113
|
</Box>
|
|
@@ -111,7 +115,7 @@ export default function InvoiceDetail(props: { id: string }) {
|
|
|
111
115
|
<SectionHeader title={t('admin.details')} />
|
|
112
116
|
<Stack>
|
|
113
117
|
<InfoRow label={t('admin.invoice.number')} value={data.number} />
|
|
114
|
-
<InfoRow label={t('admin.invoice.
|
|
118
|
+
<InfoRow label={t('admin.invoice.billTo')} value={<CustomerLink customer={data.customer} />} />
|
|
115
119
|
<InfoRow
|
|
116
120
|
label={t('admin.subscription.currentPeriod')}
|
|
117
121
|
value={
|
|
@@ -13,6 +13,7 @@ import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
|
|
13
13
|
import Currency from '../../../components/currency';
|
|
14
14
|
import CustomerLink from '../../../components/customer/link';
|
|
15
15
|
import InfoRow from '../../../components/info-row';
|
|
16
|
+
import { Download } from '../../../components/invoice-pdf/pdf';
|
|
16
17
|
import InvoiceTable from '../../../components/invoice/table';
|
|
17
18
|
import SectionHeader from '../../../components/section/header';
|
|
18
19
|
import { useSessionContext } from '../../../contexts/session';
|
|
@@ -114,16 +115,7 @@ export default function CustomerInvoiceDetail() {
|
|
|
114
115
|
</Typography>
|
|
115
116
|
</Stack>
|
|
116
117
|
<Stack direction="row" spacing={1} justifyContent="flex-end" alignItems="center">
|
|
117
|
-
{['open', 'paid', 'uncollectible'].includes(data.status) &&
|
|
118
|
-
<Button
|
|
119
|
-
variant="contained"
|
|
120
|
-
color="secondary"
|
|
121
|
-
size="small"
|
|
122
|
-
disabled={state.downloading}
|
|
123
|
-
onClick={() => setState({ downloading: true })}>
|
|
124
|
-
{t('payment.customer.invoice.download')}
|
|
125
|
-
</Button>
|
|
126
|
-
)}
|
|
118
|
+
{['open', 'paid', 'uncollectible'].includes(data.status) && <Download data={data} />}
|
|
127
119
|
{['open', 'uncollectible'].includes(data.status) && (
|
|
128
120
|
<Button variant="contained" color="primary" size="small" disabled={state.paying} onClick={onPay}>
|
|
129
121
|
{t('payment.customer.invoice.pay')}
|
|
@@ -171,10 +163,7 @@ export default function CustomerInvoiceDetail() {
|
|
|
171
163
|
}
|
|
172
164
|
/>
|
|
173
165
|
)}
|
|
174
|
-
<InfoRow
|
|
175
|
-
label={t('admin.invoice.customer')}
|
|
176
|
-
value={<CustomerLink customer={data.customer} linked={false} />}
|
|
177
|
-
/>
|
|
166
|
+
<InfoRow label={t('admin.invoice.billTo')} value={<CustomerLink customer={data.customer} linked={false} />} />
|
|
178
167
|
</Stack>
|
|
179
168
|
</Root>
|
|
180
169
|
<Box>
|