# Handle plan selection by yourself

The billing funnel can handle for you the plan selection, but sometimes you may prefer to present your plan by yourself to be more precise about your offer.

In such a case you should provide to the billing context the selected plan, and if applicable the quantity associated with.

Warning

When you handle the plan selection by yourself, we recommend you to retrieve the subscription in PHP to know if you must display the plan selection or the subscription during billing-cdc bootstrap.

# Add plan selection

You should add your plan presentation in the configuration page for your module in the back office (located by default at views/templates/admin/configure.tpl). In order to handle plan selection by yourself, you must use the subscription management component and the checkout modal instead of the window.psBilling.initialize method.

Note

window.psBilling.initialize is only a wrapper to simplify the implementation of your module.

This is a simple working example that is purposefully basic, you can make the code as complex as you need it to be to cover your needs as long as you follow the steps in this guide.

  1. Create a JS file in your module: views/js/configure.js and inject it into <module_name>.php file.






     




       public function getContent()
       {
         // ...
         $this->context->smarty->assign([
           // ...
           'urlConfigureJs' => $this->getPathUri() . 'views/js/configure.js',
         ]);
         // ...
       }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  2. Retrieve plan pricing from Billing API and inject it into your template

Billing will not provide the name of the plans and the list of features, you must provide it to manage your display in your module

Note

For component group id, please get in touch with your Solution Engineer at PrestaShop.













 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 






   public function getContent()
   {
     // ...

     /**********************
      * PrestaShop Billing *
      * *******************/
     // Billing Service

     // Load the service for PrestaShop Billing
     $billingService = $this->getService('<module_name>.ps_billings_service');

     // Retrieve plans and addons for your module
     $productComponents = $billingService->getProductComponents();

     $componentItems = [];
     if (!empty($productComponents['body']['items']))
     {
       $componentItemsTmp = $productComponents['body']['items'];
       // You need to retrieve plan information from your API or Class or Array like this
       // For plan id, please get in touch with your Solution Engineer at PrestaShop.
       // Values "moduleid-plana" and "moduleid-planb" must be replaced by the component id
       // returned by $billingService->getProductComponents();
       $planInfos = [
           [
             "component_group_id" => "moduleid-plana",
             "name" => "Plan A",
             "features" => [
               "Plan A Feature 1",
               "Plan A Feature 2",
               "Plan A Feature 3"
             ]
           ],
           [
               "component_group_id" => "moduleid-planb",
               "name" => "Ultimate",
               "features" => [
                 "All features from Plan A, plus...",
                 "Plan B Feature 1",
                 "Plan B Feature 2"
               ]
           ]
       ];

       foreach($componentItemsTmp as $componentItemTmp) {
         // Filter to retrieve only plans
         if($componentItemTmp['componentType'] == 'plan') {
           $planInfoIndex = array_search($componentItemTmp['componentGroupId'], array_column($planInfos, 'component_group_id'));
           $componentItemTmp['details'] = [
             "features" => $planInfos[$planInfoIndex]['features'],
             "name" => $planInfos[$planInfoIndex]['name'],
           ];
           array_push($componentItems, $componentItemTmp);
         }
       }
     }

     // Allow the use of $componentItems in your tpl file
     $this->context->smarty->assign([
       'componentItems' => $componentItems,
     ]);

     // ...
   }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  1. Inject views/js/configure.js as a script in views/templates/admin/configure.tpl







     

    <prestashop-accounts></prestashop-accounts>
    <div id="ps-billing"></div>
    <div id="ps-modal"></div>
    
    <script src="{$urlAccountsCdn|escape:'htmlall':'UTF-8'}" rel=preload></script>
    <script src="{$urlBilling|escape:'htmlall':'UTF-8'}" rel=preload></script>
    <script src="{$urlConfigureJs|escape:'htmlall':'UTF-8'}" rel=preload></script>
    
    1
    2
    3
    4
    5
    6
    7
  2. Implement views/js/configure.js to make billing works with the component instead of the initialize method








     
     
     
     
     
     
     



     
     
     

     
     
     
     
     
     
     
     
     
     
     
     

     
     
     
     
     
     
     
     





    window?.psaccountsVue?.init();
    
    let billingContext = { ...window.psBillingContext.context };
    let currentModal;
    let customer;
    
    if (window.psaccountsVue.isOnboardingCompleted() == true) {
      customer = new window.psBilling.CustomerComponent({
        context: billingContext,
        hideInvoiceList: true,
        onOpenModal,
        onEventHook,
      });
      customer.render("#ps-billing");
    }
    
    // Modal open / close management
    async function onCloseModal(data) {
      await Promise.all([currentModal.close(), updateCustomerProps(data)]);
    }
    
    function onOpenModal(type, data) {
      currentModal = new window.psBilling.ModalContainerComponent({
        type,
        context: {
          ...billingContext,
          ...data,
        },
        onCloseModal,
        onEventHook,
      });
      currentModal.render("#ps-modal");
    }
    
    function updateCustomerProps(data) {
      return customer.updateProps({
        context: {
          ...billingContext,
          ...data,
        },
      });
    }
    
    function onEventHook(type, data) {
      // Do anything
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
  3. Display your plan in your module and hide the subscription management in views/templates/admin/configure.tpl




     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     






       <prestashop-accounts></prestashop-accounts>
    
       <!-- You should use the billing plan library in order to display your plan -->
       <section id="billing-plan-selection" style="display:none">
         <h2>Select your plan</h2>
         <div style="width: 500px; display:flex">
           {foreach $componentItems as $item}
             <div style="border: 1px solid;padding: 2rem;text-align:center;margin-left:1rem;">
               <h3 style="font-weight: bold;margin-bottom: 1rem;">{$item['name']}</h3>
    
               <!-- Pricing information must be retrieved from billing API -->
               <p style="margin-bottom: 1rem;">{$item['price']/100}€/{$item['billingPeriodUnit']}</p>
               <!-- Pricing id must be retrieved from billing API -->
               <button onclick="openCheckout('{$item['id']}')"
                 style="background: black;color: white; padding: 0.5rem; font-weight: bold;margin-bottom: 1.5rem;">Select this
                 offer</button>
    
               {if !empty($item['features'])}
                 <div class="billing-plan__feature-group">
                   {foreach $item['features'] as $feature}
                     <div style="display: flex; flex-direction: row;">
                       <div style="display: flex; flex-direction: row; align-items: flex-start;">
                         <div class="puik-icon material-icons-round" style="font-size: 1.25rem;">check</div>
                         <div>{$feature}</div>
                       </div>
                     </div>
                   {/foreach}
                 </div>
               {/if}
           {/foreach}
         </div>
       </section>
    
       <div id="ps-billing-wrapper" style="display:none">
         <div id="ps-billing"></div>
       </div>
       <div id="ps-modal"></div>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
  4. Display the checkout modal when your user click on the plan selection button














     





































     


     




     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

     window?.psaccountsVue?.init();
    
     let billingContext = { ...window.psBillingContext.context }
     let currentModal;
     let customer;
    
     if(window.psaccountsVue.isOnboardingCompleted() == true) {
    
       showPlanSelection();
    
       customer = new window.psBilling.CustomerComponent({
         context: billingContext,
         hideInvoiceList: true,
         onOpenModal,
         onEventHook
       });
       customer.render('#ps-billing');
     }
    
     // Modal open / close management
     async function onCloseModal(data) {
       await Promise.all([currentModal.close(), updateCustomerProps(data)]);
     };
    
     function onOpenModal(type, data) {
       currentModal = new window.psBilling.ModalContainerComponent({
         type,
         context: {
           ...billingContext,
           ...data,
         },
         onCloseModal,
         onEventHook
       });
       currentModal.render('#ps-modal');
      };
    
     function updateCustomerProps(data) {
       return customer.updateProps({
         context: {
           ...billingContext,
           ...data,
         },
       });
     };
    
     // Event hook management
     function onEventHook(type, data) {
       // Event hook listener
       switch (type) {
         case window.psBilling.EVENT_HOOK_TYPE.SUBSCRIPTION_CREATED:
           showBillingWrapper();
           break;
         case window.psBilling.EVENT_HOOK_TYPE.SUBSCRIPTION_UPDATED:
           showBillingWrapper();
           break;
       }
     }
    
     function showPlanSelection() {
       document.getElementById('billing-plan-selection').style.display = 'block';
       document.getElementById('ps-billing-wrapper').style.display = 'none';
     }
    
     function showBillingWrapper() {
       document.getElementById('billing-plan-selection').style.display = 'none';
       document.getElementById('ps-billing-wrapper').style.display = 'block';
     }
    
     // Open the checkout full screen modal
     function openCheckout(pricingId) {
       const offerSelection = {offerSelection: {offerPricingId: pricingId }};
       onOpenModal(window.psBilling.MODAL_TYPE.SUBSCRIPTION_FUNNEL, offerSelection);
     };
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74

# Handle plan change / select button

When your customer click on the "Change Plan" button, it opens the default plan selection, provided by billing, within the funnel.

In case you handle the plan selection by yourself, you don't want the default plan selection to be displayed when your customer want to change their plan.

  1. Provide a onOpenFunnel function into the Customer context











     



     
     
     
     

     if(window.psaccountsVue.isOnboardingCompleted() == true) {
    
       // Then the plan selection should be displayed
       showPlanSelection();
    
       customer = new window.psBilling.CustomerComponent({
         context: billingContext,
         hideInvoiceList: true,
         onOpenModal,
         onEventHook,
         onOpenFunnel
       });
       customer.render('#ps-billing');
     }
     // Here is the method called when your customer hits the "Change Plan" button
     function onOpenFunnel({ subscription }) {
       showPlanSelection();
     }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18