Skip to main content

shopify_client/admin/subscription/
remote.rs

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