1use crate::{
2 common::{
3 http::execute_graphql,
4 types::{APIError, RequestCallbacks},
5 },
6 types::subscription::{
7 ActiveSubscriptionsResp, AppPricingInterval, CancelSubscriptionResp,
8 CreateCombinedSubscriptionRequest, CreateRecurringSubscriptionRequest,
9 CreateSubscriptionResp, CreateUsageRecordRequest, CreateUsageRecordResp,
10 CreateUsageSubscriptionRequest, ExtendTrialResp, MoneyInput, UpdateCappedAmountResp,
11 },
12};
13use serde_json::json;
14
15pub async fn create_recurring_subscription(
16 shop_url: &String,
17 version: &String,
18 access_token: &String,
19 callbacks: &RequestCallbacks,
20 request: &CreateRecurringSubscriptionRequest,
21) -> Result<CreateSubscriptionResp, APIError> {
22 let interval = request.interval.unwrap_or(AppPricingInterval::Every30Days);
23 let test = request.test.unwrap_or(false);
24
25 let query = r#"
26 mutation appSubscriptionCreate($name: String!, $returnUrl: URL!, $lineItems: [AppSubscriptionLineItemInput!]!, $test: Boolean, $trialDays: Int) {
27 appSubscriptionCreate(name: $name, returnUrl: $returnUrl, lineItems: $lineItems, test: $test, trialDays: $trialDays) {
28 appSubscription {
29 id
30 name
31 status
32 lineItems {
33 id
34 plan {
35 pricingDetails {
36 __typename
37 ... on AppRecurringPricing {
38 price {
39 amount
40 currencyCode
41 }
42 interval
43 }
44 }
45 }
46 }
47 createdAt
48 currentPeriodEnd
49 returnUrl
50 trialDays
51 test
52 }
53 confirmationUrl
54 userErrors {
55 field
56 message
57 }
58 }
59 }
60 "#.to_string();
61
62 let mut line_item = json!({
63 "plan": {
64 "appRecurringPricingDetails": {
65 "price": {
66 "amount": request.price,
67 "currencyCode": request.currency_code
68 },
69 "interval": interval
70 }
71 }
72 });
73
74 if let Some(discount) = &request.discount {
76 line_item["plan"]["appRecurringPricingDetails"]["discount"] = json!(discount);
77 }
78
79 let variables = json!({
80 "name": request.name,
81 "returnUrl": request.return_url,
82 "lineItems": [line_item],
83 "test": test,
84 "trialDays": request.trial_days
85 });
86
87 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
88}
89
90pub async fn create_usage_subscription(
91 shop_url: &String,
92 version: &String,
93 access_token: &String,
94 callbacks: &RequestCallbacks,
95 request: &CreateUsageSubscriptionRequest,
96) -> Result<CreateSubscriptionResp, APIError> {
97 let test = request.test.unwrap_or(false);
98
99 let query = r#"
100 mutation appSubscriptionCreate($name: String!, $returnUrl: URL!, $lineItems: [AppSubscriptionLineItemInput!]!, $test: Boolean, $trialDays: Int) {
101 appSubscriptionCreate(name: $name, returnUrl: $returnUrl, lineItems: $lineItems, test: $test, trialDays: $trialDays) {
102 appSubscription {
103 id
104 name
105 status
106 lineItems {
107 id
108 plan {
109 pricingDetails {
110 __typename
111 ... on AppUsagePricing {
112 cappedAmount {
113 amount
114 currencyCode
115 }
116 terms
117 balanceUsed {
118 amount
119 currencyCode
120 }
121 interval
122 }
123 }
124 }
125 }
126 createdAt
127 currentPeriodEnd
128 returnUrl
129 trialDays
130 test
131 }
132 confirmationUrl
133 userErrors {
134 field
135 message
136 }
137 }
138 }
139 "#.to_string();
140
141 let variables = json!({
142 "name": request.name,
143 "returnUrl": request.return_url,
144 "lineItems": [{
145 "plan": {
146 "appUsagePricingDetails": {
147 "cappedAmount": {
148 "amount": request.capped_amount,
149 "currencyCode": request.currency_code
150 },
151 "terms": request.terms
152 }
153 }
154 }],
155 "test": test,
156 "trialDays": request.trial_days
157 });
158
159 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
160}
161
162pub async fn create_combined_subscription(
163 shop_url: &String,
164 version: &String,
165 access_token: &String,
166 callbacks: &RequestCallbacks,
167 request: &CreateCombinedSubscriptionRequest,
168) -> Result<CreateSubscriptionResp, APIError> {
169 let interval = request.interval.unwrap_or(AppPricingInterval::Every30Days);
170 let test = request.test.unwrap_or(false);
171
172 let query = r#"
173 mutation appSubscriptionCreate($name: String!, $returnUrl: URL!, $lineItems: [AppSubscriptionLineItemInput!]!, $test: Boolean, $trialDays: Int) {
174 appSubscriptionCreate(name: $name, returnUrl: $returnUrl, lineItems: $lineItems, test: $test, trialDays: $trialDays) {
175 appSubscription {
176 id
177 name
178 status
179 lineItems {
180 id
181 plan {
182 pricingDetails {
183 __typename
184 ... on AppRecurringPricing {
185 price {
186 amount
187 currencyCode
188 }
189 interval
190 }
191 ... on AppUsagePricing {
192 cappedAmount {
193 amount
194 currencyCode
195 }
196 terms
197 balanceUsed {
198 amount
199 currencyCode
200 }
201 interval
202 }
203 }
204 }
205 }
206 createdAt
207 currentPeriodEnd
208 returnUrl
209 trialDays
210 test
211 }
212 confirmationUrl
213 userErrors {
214 field
215 message
216 }
217 }
218 }
219 "#.to_string();
220
221 let mut recurring_line_item = json!({
222 "plan": {
223 "appRecurringPricingDetails": {
224 "price": {
225 "amount": request.recurring_price,
226 "currencyCode": request.recurring_currency_code
227 },
228 "interval": interval
229 }
230 }
231 });
232
233 if let Some(discount) = &request.discount {
235 recurring_line_item["plan"]["appRecurringPricingDetails"]["discount"] = json!(discount);
236 }
237
238 let usage_line_item = json!({
239 "plan": {
240 "appUsagePricingDetails": {
241 "cappedAmount": {
242 "amount": request.capped_amount,
243 "currencyCode": request.usage_currency_code
244 },
245 "terms": request.terms
246 }
247 }
248 });
249
250 let variables = json!({
251 "name": request.name,
252 "returnUrl": request.return_url,
253 "lineItems": [recurring_line_item, usage_line_item],
254 "test": test,
255 "trialDays": request.trial_days
256 });
257
258 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
259}
260
261pub async fn cancel_subscription(
262 shop_url: &String,
263 version: &String,
264 access_token: &String,
265 callbacks: &RequestCallbacks,
266 subscription_id: &String,
267 prorate: bool,
268) -> Result<CancelSubscriptionResp, APIError> {
269 let query = r#"
270 mutation appSubscriptionCancel($id: ID!, $prorate: Boolean) {
271 appSubscriptionCancel(id: $id, prorate: $prorate) {
272 appSubscription {
273 id
274 name
275 status
276 lineItems {
277 id
278 plan {
279 pricingDetails {
280 __typename
281 ... on AppRecurringPricing {
282 price {
283 amount
284 currencyCode
285 }
286 interval
287 }
288 ... on AppUsagePricing {
289 cappedAmount {
290 amount
291 currencyCode
292 }
293 terms
294 balanceUsed {
295 amount
296 currencyCode
297 }
298 interval
299 }
300 }
301 }
302 }
303 }
304 userErrors {
305 field
306 message
307 }
308 }
309 }
310 "#
311 .to_string();
312
313 let variables = json!({
314 "id": subscription_id,
315 "prorate": prorate
316 });
317
318 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
319}
320
321pub async fn extend_trial(
322 shop_url: &String,
323 version: &String,
324 access_token: &String,
325 callbacks: &RequestCallbacks,
326 subscription_id: &String,
327 days: i32,
328) -> Result<ExtendTrialResp, APIError> {
329 let query = r#"
330 mutation appSubscriptionTrialExtend($id: ID!, $days: Int!) {
331 appSubscriptionTrialExtend(id: $id, days: $days) {
332 appSubscription {
333 id
334 name
335 status
336 trialDays
337 }
338 userErrors {
339 field
340 message
341 }
342 }
343 }
344 "#
345 .to_string();
346
347 let variables = json!({
348 "id": subscription_id,
349 "days": days
350 });
351
352 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
353}
354
355pub async fn update_capped_amount(
356 shop_url: &String,
357 version: &String,
358 access_token: &String,
359 callbacks: &RequestCallbacks,
360 line_item_id: &String,
361 capped_amount: &MoneyInput,
362) -> Result<UpdateCappedAmountResp, APIError> {
363 let query = r#"
364 mutation appSubscriptionLineItemUpdate($id: ID!, $cappedAmount: MoneyInput!) {
365 appSubscriptionLineItemUpdate(id: $id, cappedAmount: $cappedAmount) {
366 appSubscription {
367 id
368 name
369 status
370 lineItems {
371 id
372 plan {
373 pricingDetails {
374 __typename
375 ... on AppUsagePricing {
376 cappedAmount {
377 amount
378 currencyCode
379 }
380 terms
381 balanceUsed {
382 amount
383 currencyCode
384 }
385 interval
386 }
387 }
388 }
389 }
390 }
391 userErrors {
392 field
393 message
394 }
395 }
396 }
397 "#
398 .to_string();
399
400 let variables = json!({
401 "id": line_item_id,
402 "cappedAmount": {
403 "amount": capped_amount.amount,
404 "currencyCode": capped_amount.currency_code
405 }
406 });
407
408 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
409}
410
411pub async fn create_usage_record(
412 shop_url: &String,
413 version: &String,
414 access_token: &String,
415 callbacks: &RequestCallbacks,
416 request: &CreateUsageRecordRequest,
417) -> Result<CreateUsageRecordResp, APIError> {
418 let query = r#"
419 mutation appUsageRecordCreate($subscriptionLineItemId: ID!, $price: MoneyInput!, $description: String!, $idempotencyKey: String) {
420 appUsageRecordCreate(subscriptionLineItemId: $subscriptionLineItemId, price: $price, description: $description, idempotencyKey: $idempotencyKey) {
421 appUsageRecord {
422 id
423 description
424 price {
425 amount
426 currencyCode
427 }
428 createdAt
429 }
430 userErrors {
431 field
432 message
433 }
434 }
435 }
436 "#.to_string();
437
438 let variables = json!({
439 "subscriptionLineItemId": request.subscription_line_item_id,
440 "price": {
441 "amount": request.price,
442 "currencyCode": request.currency_code
443 },
444 "description": request.description,
445 "idempotencyKey": request.idempotency_key
446 });
447
448 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
449}
450
451pub async fn get_active_subscriptions(
452 shop_url: &String,
453 version: &String,
454 access_token: &String,
455 callbacks: &RequestCallbacks,
456) -> Result<ActiveSubscriptionsResp, APIError> {
457 let query = r#"
458 query {
459 currentAppInstallation {
460 activeSubscriptions {
461 id
462 name
463 status
464 lineItems {
465 id
466 plan {
467 pricingDetails {
468 __typename
469 ... on AppRecurringPricing {
470 price {
471 amount
472 currencyCode
473 }
474 interval
475 }
476 ... on AppUsagePricing {
477 cappedAmount {
478 amount
479 currencyCode
480 }
481 terms
482 balanceUsed {
483 amount
484 currencyCode
485 }
486 interval
487 }
488 }
489 }
490 }
491 createdAt
492 currentPeriodEnd
493 returnUrl
494 trialDays
495 test
496 }
497 }
498 }
499 "#
500 .to_string();
501
502 let variables = json!({});
503
504 execute_graphql(shop_url, version, access_token, callbacks, query, variables).await
505}