1 | |
2 | type Paypal = { |
3 | clientId: string; |
4 | clientSecret: string; |
5 | }; |
6 |
|
7 | async function getToken(auth: Paypal): Promise<string> { |
8 | const url = new URL(`https://api-m.paypal.com/v1/oauth2/token`); |
9 | const response = await fetch(url, { |
10 | method: "POST", |
11 | headers: { |
12 | Authorization: `Basic ${btoa(`${auth.clientId}:${auth.clientSecret}`)}`, |
13 | }, |
14 | body: new URLSearchParams({ |
15 | grant_type: "client_credentials", |
16 | }), |
17 | }); |
18 | if (!response.ok) { |
19 | const text = await response.text(); |
20 | throw new Error(`Could not get token: ${response.status} ${text}`); |
21 | } |
22 | const json = await response.json(); |
23 | return json.access_token; |
24 | } |
25 | |
26 | * Create template |
27 | * Creates an invoice template. You can use details from this template to create an invoice. You can create up to 50 templates.Note: Every merchant starts with three PayPal system templates that are optimized for the unit type billed. The template includes `Quantity`, `Hours`, and `Amount`. |
28 | */ |
29 | export async function main( |
30 | auth: Paypal, |
31 | body: { |
32 | id?: string; |
33 | name?: string; |
34 | default_template?: false | true; |
35 | template_info?: { |
36 | detail?: { |
37 | reference?: string; |
38 | currency_code: string; |
39 | note?: string; |
40 | terms_and_conditions?: string; |
41 | memo?: string; |
42 | attachments?: { |
43 | id?: string; |
44 | reference_url?: string; |
45 | content_type?: string; |
46 | create_time?: string; |
47 | size?: string; |
48 | }[]; |
49 | } & { |
50 | payment_term?: { |
51 | term_type?: |
52 | | "DUE_ON_RECEIPT" |
53 | | "DUE_ON_DATE_SPECIFIED" |
54 | | "NET_10" |
55 | | "NET_15" |
56 | | "NET_30" |
57 | | "NET_45" |
58 | | "NET_60" |
59 | | "NET_90" |
60 | | "NO_DUE_DATE"; |
61 | }; |
62 | metadata?: { |
63 | create_time?: string; |
64 | created_by?: string; |
65 | last_update_time?: string; |
66 | last_updated_by?: string; |
67 | }; |
68 | }; |
69 | invoicer?: { business_name?: string } & { |
70 | name?: { |
71 | prefix?: string; |
72 | given_name?: string; |
73 | surname?: string; |
74 | middle_name?: string; |
75 | suffix?: string; |
76 | alternate_full_name?: string; |
77 | full_name?: string; |
78 | }; |
79 | address?: { |
80 | address_line_1?: string; |
81 | address_line_2?: string; |
82 | address_line_3?: string; |
83 | admin_area_4?: string; |
84 | admin_area_3?: string; |
85 | admin_area_2?: string; |
86 | admin_area_1?: string; |
87 | postal_code?: string; |
88 | country_code: string; |
89 | address_details?: { |
90 | street_number?: string; |
91 | street_name?: string; |
92 | street_type?: string; |
93 | delivery_service?: string; |
94 | building_name?: string; |
95 | sub_building?: string; |
96 | }; |
97 | }; |
98 | } & { |
99 | email_address?: string; |
100 | phones?: { |
101 | country_code: string; |
102 | national_number: string; |
103 | extension_number?: string; |
104 | } & { phone_type?: "FAX" | "HOME" | "MOBILE" | "OTHER" | "PAGER" }[]; |
105 | website?: string; |
106 | tax_id?: string; |
107 | additional_notes?: string; |
108 | logo_url?: string; |
109 | }; |
110 | primary_recipients?: { |
111 | billing_info?: { business_name?: string } & { |
112 | name?: { |
113 | prefix?: string; |
114 | given_name?: string; |
115 | surname?: string; |
116 | middle_name?: string; |
117 | suffix?: string; |
118 | alternate_full_name?: string; |
119 | full_name?: string; |
120 | }; |
121 | address?: { |
122 | address_line_1?: string; |
123 | address_line_2?: string; |
124 | address_line_3?: string; |
125 | admin_area_4?: string; |
126 | admin_area_3?: string; |
127 | admin_area_2?: string; |
128 | admin_area_1?: string; |
129 | postal_code?: string; |
130 | country_code: string; |
131 | address_details?: { |
132 | street_number?: string; |
133 | street_name?: string; |
134 | street_type?: string; |
135 | delivery_service?: string; |
136 | building_name?: string; |
137 | sub_building?: string; |
138 | }; |
139 | }; |
140 | } & { |
141 | email_address?: string; |
142 | phones?: { |
143 | country_code: string; |
144 | national_number: string; |
145 | extension_number?: string; |
146 | } & { phone_type?: "FAX" | "HOME" | "MOBILE" | "OTHER" | "PAGER" }[]; |
147 | additional_info?: string; |
148 | language?: string; |
149 | }; |
150 | shipping_info?: { business_name?: string } & { |
151 | name?: { |
152 | prefix?: string; |
153 | given_name?: string; |
154 | surname?: string; |
155 | middle_name?: string; |
156 | suffix?: string; |
157 | alternate_full_name?: string; |
158 | full_name?: string; |
159 | }; |
160 | address?: { |
161 | address_line_1?: string; |
162 | address_line_2?: string; |
163 | address_line_3?: string; |
164 | admin_area_4?: string; |
165 | admin_area_3?: string; |
166 | admin_area_2?: string; |
167 | admin_area_1?: string; |
168 | postal_code?: string; |
169 | country_code: string; |
170 | address_details?: { |
171 | street_number?: string; |
172 | street_name?: string; |
173 | street_type?: string; |
174 | delivery_service?: string; |
175 | building_name?: string; |
176 | sub_building?: string; |
177 | }; |
178 | }; |
179 | }; |
180 | }[]; |
181 | additional_recipients?: string[]; |
182 | items?: { |
183 | id?: string; |
184 | name: string; |
185 | description?: string; |
186 | quantity: string; |
187 | unit_amount: { currency_code: string; value: string }; |
188 | tax?: { |
189 | name: string; |
190 | percent: string; |
191 | amount?: { currency_code: string; value: string }; |
192 | }; |
193 | item_date?: string; |
194 | discount?: { |
195 | percent?: string; |
196 | amount?: { currency_code: string; value: string }; |
197 | }; |
198 | unit_of_measure?: "QUANTITY" | "HOURS" | "AMOUNT"; |
199 | }[]; |
200 | configuration?: { |
201 | tax_calculated_after_discount?: false | true; |
202 | tax_inclusive?: false | true; |
203 | allow_tip?: false | true; |
204 | partial_payment?: { |
205 | allow_partial_payment?: false | true; |
206 | minimum_amount_due?: { currency_code: string; value: string }; |
207 | }; |
208 | }; |
209 | amount?: { |
210 | currency_code?: string; |
211 | value?: string; |
212 | breakdown?: { |
213 | item_total?: { currency_code: string; value: string }; |
214 | discount?: { |
215 | invoice_discount?: { |
216 | percent?: string; |
217 | amount?: { currency_code: string; value: string }; |
218 | }; |
219 | item_discount?: { currency_code: string; value: string }; |
220 | }; |
221 | tax_total?: { currency_code: string; value: string }; |
222 | shipping?: { |
223 | amount?: { currency_code: string; value: string }; |
224 | tax?: { |
225 | name: string; |
226 | percent: string; |
227 | amount?: { currency_code: string; value: string }; |
228 | }; |
229 | }; |
230 | custom?: { |
231 | label: string; |
232 | amount?: { currency_code: string; value: string }; |
233 | }; |
234 | }; |
235 | }; |
236 | due_amount?: { currency_code: string; value: string }; |
237 | }; |
238 | settings?: { |
239 | template_item_settings?: { |
240 | field_name?: |
241 | | "ITEMS_QUANTITY" |
242 | | "ITEMS_DESCRIPTION" |
243 | | "ITEMS_DATE" |
244 | | "ITEMS_DISCOUNT" |
245 | | "ITEMS_TAX"; |
246 | display_preference?: { hidden?: false | true }; |
247 | }[]; |
248 | template_subtotal_settings?: { |
249 | field_name?: "DISCOUNT" | "SHIPPING" | "CUSTOM"; |
250 | display_preference?: { hidden?: false | true }; |
251 | }[]; |
252 | }; |
253 | unit_of_measure?: "QUANTITY" | "HOURS" | "AMOUNT"; |
254 | standard_template?: false | true; |
255 | links?: { |
256 | href: string; |
257 | rel: string; |
258 | method?: |
259 | | "GET" |
260 | | "POST" |
261 | | "PUT" |
262 | | "DELETE" |
263 | | "HEAD" |
264 | | "CONNECT" |
265 | | "OPTIONS" |
266 | | "PATCH"; |
267 | }[]; |
268 | }, |
269 | ) { |
270 | const token = await getToken(auth); |
271 | const url = new URL(`https://api-m.paypal.com/v2/invoicing/templates`); |
272 |
|
273 | const response = await fetch(url, { |
274 | method: "POST", |
275 | headers: { |
276 | "Content-Type": "application/json", |
277 | Authorization: "Bearer " + token, |
278 | }, |
279 | body: JSON.stringify(body), |
280 | }); |
281 | if (!response.ok) { |
282 | const text = await response.text(); |
283 | throw new Error(`${response.status} ${text}`); |
284 | } |
285 | return await response.json(); |
286 | } |
287 |
|