LP1774892 stripe elements
authorJason Etheridge <jason@EquinoxInitiative.org>
Fri, 10 Jul 2020 16:08:30 +0000 (12:08 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Wed, 5 Aug 2020 21:40:13 +0000 (17:40 -0400)
This commit breaks some code out into separate files for easier understanding.

The Stripe form was then tweaked and repositioned to work with specific selected
transactions, invoke the last chance screen, and show the refund policy.

Signed-off-by: Jason Etheridge <jason@EquinoxInitiative.org>
Signed-off-by: John Amundson <jamundson@cwmars.org>
Signed-off-by: Dawn Dale <ddale@georgialibraries.org>
Signed-off-by: Jason Stephenson <jason@sigio.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

Open-ILS/src/templates/opac/myopac/generic_payment_form.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/myopac/last_chance_form.tt2 [new file with mode: 0644]
Open-ILS/src/templates/opac/myopac/main_payment_form.tt2
Open-ILS/src/templates/opac/myopac/stripe_payment_form.tt2 [new file with mode: 0644]

diff --git a/Open-ILS/src/templates/opac/myopac/generic_payment_form.tt2 b/Open-ILS/src/templates/opac/myopac/generic_payment_form.tt2
new file mode 100644 (file)
index 0000000..4a67062
--- /dev/null
@@ -0,0 +1,128 @@
+<form method="post" id="payment_form" action='#payment'>
+    <input type="hidden" name="last_chance" value="1" />
+    [% FOR xact IN CGI.param('xact') %]
+    <input type="hidden" name="xact" value="[% xact | html %]" />
+    [% END %]
+    [% FOR xact IN CGI.param('xact_misc') %]
+    <input type="hidden" name="xact_misc" value="[% xact | html %]" />
+    [% END %]
+
+     <table id="billing_info_table">
+      <tbody>
+          <tr>
+              <td colspan='2' class="cc_header"><strong>[% l('Billing Information') %]</strong></td>
+           </tr>
+           <tr> 
+            <td><label for="payment-first-name">[% l('First Name') %]</label></td>
+                <td><input type="text"  name="billing_first" id="payment-first-name" 
+                    value="[% ctx.user.first_given_name | html %]" /></td>
+            </tr>
+            <tr>
+                <td><label for="payment-last-name">[% l('Last Name') %]</label></td>
+                <td><input type="text" name="billing_last" id="payment-last-name" 
+                    value="[% ctx.user.family_name | html %]" /></td>
+            </tr>
+
+            <tr>
+                <td><label for="payment-email-addr">[% l('Email Address') %]</label></td>
+                <td>
+                    
+                    <input id="payment-email-addr" type="text" 
+                         value="[% ctx.user.email | html %]" disabled="disabled" 
+                        readonly="readonly" />   
+                    <a title="[% l('Update Email Address') %]"
+                        href="[% ctx.opac_root %]/myopac/update_email?return_to_referer=1">[% l("Update") %]</a>
+                </td
+            </tr>
+            <tr>
+                <td><label for="payment-billing-address">[% l('Street Address') %]</label></td>
+                <td><input type="text" name="billing_address" id="payment-billing-address" 
+                    value="[% ctx.user.billing_address.street1 _ ctx.user.billing_address.street2 | html %]" /></td>
+            </tr>
+            <tr>
+                <td><label for="payment-billing-city">[% l('City' )%]</label></td>
+                <td><input type="text" name="billing_city" id="payment-billing-city" 
+                    value="[% ctx.user.billing_address.city | html %]" /></td>
+            </tr>
+            <tr>
+                <td><label for="payment-billing-state">[% l('State or Province') %]</label></td>
+                <td><input type="text" name="billing_state" id="payment-billing-state"
+                    value="[% ctx.user.billing_address.state | html %]" /></td>
+            </tr>
+            <tr>
+                <td><label for="paymenet-billing-zip">[% l('ZIP or Postal Code') %]</label></td>
+                [% USE zip=String(ctx.user.billing_address.post_code) %]
+                <td><input type="tel" pattern="[0-9]*" maxlength="5" size="5" name="billing_zip" id="paymenet-billing-zip"
+                    value="[% zip.truncate(5)  %]" /></td>
+            </tr>
+           </tbody>
+           </table>
+           
+           <table id="credit_card_info_table">
+           <tbody>
+            <tr>
+              <td colspan='2' class="cc_header"><strong>[% l('Credit Card Information') %]</strong></td>
+            </tr>
+            <tr>
+                <td><label for="payment-credit-card">[% l('Credit Card #') %]</label></td>
+                
+                 <!-- Make type tel, which prompts for numbers in mobile -->
+                <td><input type="tel" pattern="[0-9]*" maxlength="16" id="payment-credit-card" required name="number"/></td>
+            </tr>
+            <tr>
+                <td><label for="payment-security-code">[% l('Security Code') %]</label></td>
+                <td>
+                     <!-- Make type tel, which prompts for numbers in mobile -->
+                    <input type="tel" pattern="[0-9]*" size="4" maxlength="5" id="payment-security-code" name="cvv2"/></td>
+            </tr>
+            <tr>
+                <td><label for="payment-expire-month">[% l('Expiration Month') %]</label></td>
+                <td>
+                    <select id="payment-expire-month" required name="expire_month">
+                        <option value="-1"></option>
+                        <option value="01">[% l("January (1)") %]</option>
+                        <option value="02">[% l("February (2)") %]</option>
+                        <option value="03">[% l("March (3)") %]</option>
+                        <option value="04">[% l("April (4)") %]</option>
+                        <option value="05">[% l("May (5)") %]</option>
+                        <option value="06">[% l("June (6)") %]</option>
+                        <option value="07">[% l("July (7)") %]</option>
+                        <option value="08">[% l("August (8)") %]</option>
+                        <option value="09">[% l("September (9)") %]</option>
+                        <option value="10">[% l("October (10)") %]</option>
+                        <option value="11">[% l("November (11)") %]</option>
+                        <option value="12">[% l("December (12)") %]</option>
+                    </select>
+                </td>
+            </tr>
+            <tr>
+                <td><label for="payment-expire-year">[% l('Expiration Year') %]</label></td>
+                <td>
+                    <select id="payment-expire-year" name="expire_year">
+                    [% year = date.format(date.now, '%Y');
+                    y = year;
+                    WHILE y < year + 10; # show ten years starting now %]
+                        <option value="[% y %]">[% y %]</option>
+                    [% y = y + 1; END %]
+                    </select>
+                </td>
+            </tr>
+            <tr>
+               <td colspan='2'>
+                   <div id="payment_actions">
+                      [% l('Total amount:') %]
+                       <strong>[% money(ctx.fines.balance_owed) %]</strong><br />
+      
+                     <input type="submit" id="payment_submit" value="[% l('Next') %]" class="opac-button" />
+                     <a href="[% mkurl(ctx.opac_root _ '/myopac/main', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a> 
+                     <br/>
+                     
+                      
+                   </div>
+               </td>
+            </tr>
+            
+      </tbody>
+    </table>
+     [% INCLUDE "opac/parts/myopac/main_refund_policy.tt2" %]
+</form>
diff --git a/Open-ILS/src/templates/opac/myopac/last_chance_form.tt2 b/Open-ILS/src/templates/opac/myopac/last_chance_form.tt2
new file mode 100644 (file)
index 0000000..150ffb6
--- /dev/null
@@ -0,0 +1,55 @@
+<p><big>[% l("Are you sure you are ready to charge ") %]
+     <strong> [% l("[_1] ", money(ctx.fines.balance_owed))%]</strong>
+    [% l("to your credit card?") %]</big></p>
+<form action="[% ctx.opac_root %]/myopac/main_pay_init" method="post">
+    [% FOR k IN CGI.Vars;
+        NEXT UNLESS k;
+        FOR val IN CGI.param(k) %]
+    <input type="hidden" name="[% k | html %]" value="[% val | html %]" />
+    [% END; END %]
+    
+    <input type="submit" value="[% l('Submit') %]" class="opac-button"/>
+    <a href="[% mkurl(ctx.opac_root _ '/myopac/main#selected_fines', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a>
+
+ <table title="[% l('List of Transactions') %]" id="acct_fines_confirm_header"
+    class="table_no_border_space table_no_cell_pad" style="padding-top:1em;">
+<thead>
+  <tr>
+    <th>[% l('Charge/Fee') %]</th>
+    <th>[% l('Amount') %]</th>
+ </tr>
+</thead>
+<tbody>
+  [%
+   FOR f IN ctx.fines.circulation;
+     NEXT IF CGI.param('xact').size &&
+        !CGI.param('xact').grep(f.xact.id).size;
+     attrs = {marc_xml => f.marc_xml};
+     IF f.marc_xml;
+         PROCESS get_marc_attrs args=attrs;
+     ELSIF f.xact.reservation;
+          attrs.title = f.xact.reservation.target_resource_type.name;
+     END %]
+     <tr>
+        <td>[% attrs.title | html %]</td>
+        <td class="text-right">[% money(f.xact.balance_owed) %]</td>
+     </tr>
+      [%
+      END;
+      FOR f IN ctx.fines.grocery;
+          NEXT IF CGI.param('xact_misc').size &&
+              !CGI.param('xact_misc').grep(f.xact.id).size %]
+          <tr>
+             <td>[% f.xact.last_billing_type | html %]</td>
+             <td class="text-right">[% money(f.xact.balance_owed) %]</td>
+        </tr>
+    [% END %]
+ </tbody>
+</table> 
+<p style="padding-top: 2em;">
+<big>[% l("Are you sure you are ready to charge ") %]
+     <strong> [% l("[_1] ", money(ctx.fines.balance_owed))%]</strong>
+    [% l("to your credit card?") %]</big></p>        
+    <input type="submit" value="[% l('Submit') %]" class="opac-button"/>
+    <a href="[% mkurl(ctx.opac_root _ '/myopac/main#selected_fines', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a>
index 6c40229..2d60ce6 100644 (file)
     [% l("The minimum amount you can pay is \$0.01.") %]
 </div>
 [% ELSE %]
-[% IF ctx.use_stripe %]
-<noscript>
-    [% l("Your browser does not have Javascript enabled, and we cannot " _
-        "process credit card payments without it.  Please change your " _
-        "browser settings and try again.") %]
-</noscript>
-<script type="text/javascript">
-function build_stripe_form() {
-    var elements = stripe.elements();
-
-    var style = {
-        base: {
-            color: '#32325d',
-            fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
-            fontSmoothing: 'antialiased',
-            fontSize: '16px',
-            '::placeholder': {
-                color: '#aab7c4'
-            }
-        },
-        invalid: {
-            color: '#fa755a',
-            iconColor: '#fa755a'
-        }
-    };
-
-    var card = elements.create('card', {style: style});
-    card.mount('#card-element');
-
-    // real-time validation
-    card.on('change', function(event) {
-      var displayError = document.getElementById('card-errors');
-      if (event.error) {
-        displayError.textContent = event.error.message;
-      } else {
-        displayError.textContent = '';
-      }
-    });
-
-    // let's try some auto-focus
-    card.on('ready', function(event) {
-        try { card.focus(); } catch(E) { console.log('failed to focus card element',E); }
-    });
-
-    var form = document.getElementById('payment-form');
-    form.addEventListener('submit', function(event) {
-      event.preventDefault();
-
-      stripe.createToken(card).then(function(result) {
-        if (result.error) {
-          // Inform the user if there was an error.
-          var errorElement = document.getElementById('card-errors');
-          errorElement.textContent = result.error.message;
-        } else {
-          // Send the token to your server.
-          stripeTokenHandler(result.token);
-        }
-      });
-    });
-
-    function stripeTokenHandler(token) {
-      var form = document.getElementById('payment-form');
-      var hiddenInput = document.createElement('input');
-      hiddenInput.setAttribute('type', 'hidden');
-      hiddenInput.setAttribute('name', 'stripe_token');
-      hiddenInput.setAttribute('value', token.id);
-      form.appendChild(hiddenInput);
-
-      form.submit();
-    }
-}
-[% IF ctx.want_jquery %]
-    // jquery won't actually load until after this execution thread
-    setTimeout(function() { $(document).ready(build_stripe_form) }, 0);
-[% ELSE %]
-    // but jquery is preferable to doing this
-    setTimeout(build_stripe_form,0);
-[% END %]
-</script>
-<form action="[% ctx.opac_root %]/myopac/main_pay_init" method="post" id="payment-form">
-  <div class="form-row">
-    <label for="card-element">
-      <h1>Credit Card Information</h1>
-    </label>
-    <div id="card-element">
-      <!-- A Stripe Element will be inserted here. -->
-    </div>
-
-    <!-- Used to display form errors. -->
-    <div id="card-errors" role="alert"></div>
-  </div>
-
-  <button class="opac-button">Submit Payment</button>
-</form>
-[% ELSE %]
 <div id="pay_fines_now">
     [% IF last_chance %]
-    
-    <p><big>[% l("Are you sure you are ready to charge ") %]
-         <strong> [% l("[_1] ", money(ctx.fines.balance_owed))%]</strong>
-        [% l("to your credit card?") %]</big></p>
-    <form action="[% ctx.opac_root %]/myopac/main_pay_init" method="post">
-        [% FOR k IN CGI.Vars;
-            NEXT UNLESS k;
-            FOR val IN CGI.param(k) %]
-        <input type="hidden" name="[% k | html %]" value="[% val | html %]" />
-        [% END; END %]
-        
-        <input type="submit" value="[% l('Submit') %]" class="opac-button"/>
-        <a href="[% mkurl(ctx.opac_root _ '/myopac/main#selected_fines', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a>
-
-     <table title="[% l('List of Transactions') %]" id="acct_fines_confirm_header"
-        class="table_no_border_space table_no_cell_pad" style="padding-top:1em;">
-   <thead>
-      <tr>
-        <th>[% l('Charge/Fee') %]</th>
-        <th>[% l('Amount') %]</th>
-     </tr>
-   </thead>
-   <tbody>
-      [%
-       FOR f IN ctx.fines.circulation;
-         NEXT IF CGI.param('xact').size &&
-            !CGI.param('xact').grep(f.xact.id).size;
-         attrs = {marc_xml => f.marc_xml};
-         IF f.marc_xml;
-             PROCESS get_marc_attrs args=attrs;
-         ELSIF f.xact.reservation;
-              attrs.title = f.xact.reservation.target_resource_type.name;
-         END %]
-         <tr>
-            <td>[% attrs.title | html %]</td>
-            <td class="text-right">[% money(f.xact.balance_owed) %]</td>
-         </tr>
-          [%
-          END;
-          FOR f IN ctx.fines.grocery;
-              NEXT IF CGI.param('xact_misc').size &&
-                  !CGI.param('xact_misc').grep(f.xact.id).size %]
-              <tr>
-                 <td>[% f.xact.last_billing_type | html %]</td>
-                 <td class="text-right">[% money(f.xact.balance_owed) %]</td>
-            </tr>
-        [% END %]
-     </tbody>
-   </table> 
-     
-    <p style="padding-top: 2em;">
-    <big>[% l("Are you sure you are ready to charge ") %]
-         <strong> [% l("[_1] ", money(ctx.fines.balance_owed))%]</strong>
-        [% l("to your credit card?") %]</big></p>        
-        <input type="submit" value="[% l('Submit') %]" class="opac-button"/>
-        <a href="[% mkurl(ctx.opac_root _ '/myopac/main#selected_fines', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a>
+        [% PROCESS "opac/myopac/last_chance_form.tt2"; %]
     [% ELSE %]
-    
-    <form method="post" id="payment_form" action='#payment'>
-        <input type="hidden" name="last_chance" value="1" />
-        [% FOR xact IN CGI.param('xact') %]
-        <input type="hidden" name="xact" value="[% xact | html %]" />
-        [% END %]
-        [% FOR xact IN CGI.param('xact_misc') %]
-        <input type="hidden" name="xact_misc" value="[% xact | html %]" />
-        [% END %]
-
-         <table id="billing_info_table">
-          <tbody>
-              <tr>
-                  <td colspan='2' class="cc_header"><strong>[% l('Billing Information') %]</strong></td>
-               </tr>
-               <tr> 
-                <td><label for="payment-first-name">[% l('First Name') %]</label></td>
-                    <td><input type="text"  name="billing_first" id="payment-first-name" 
-                        value="[% ctx.user.first_given_name | html %]" /></td>
-                </tr>
-                <tr>
-                    <td><label for="payment-last-name">[% l('Last Name') %]</label></td>
-                    <td><input type="text" name="billing_last" id="payment-last-name" 
-                        value="[% ctx.user.family_name | html %]" /></td>
-                </tr>
-
-                <tr>
-                    <td><label for="payment-email-addr">[% l('Email Address') %]</label></td>
-                    <td>
-                        
-                        <input id="payment-email-addr" type="text" 
-                             value="[% ctx.user.email | html %]" disabled="disabled" 
-                            readonly="readonly" />   
-                        <a title="[% l('Update Email Address') %]"
-                            href="[% ctx.opac_root %]/myopac/update_email?return_to_referer=1">[% l("Update") %]</a>
-                    </td
-                </tr>
-                <tr>
-                    <td><label for="payment-billing-address">[% l('Street Address') %]</label></td>
-                    <td><input type="text" name="billing_address" id="payment-billing-address" 
-                        value="[% ctx.user.billing_address.street1 _ ctx.user.billing_address.street2 | html %]" /></td>
-                </tr>
-                <tr>
-                    <td><label for="payment-billing-city">[% l('City' )%]</label></td>
-                    <td><input type="text" name="billing_city" id="payment-billing-city" 
-                        value="[% ctx.user.billing_address.city | html %]" /></td>
-                </tr>
-                <tr>
-                    <td><label for="payment-billing-state">[% l('State or Province') %]</label></td>
-                    <td><input type="text" name="billing_state" id="payment-billing-state"
-                        value="[% ctx.user.billing_address.state | html %]" /></td>
-                </tr>
-                <tr>
-                    <td><label for="paymenet-billing-zip">[% l('ZIP or Postal Code') %]</label></td>
-                    [% USE zip=String(ctx.user.billing_address.post_code) %]
-                    <td><input type="tel" pattern="[0-9]*" maxlength="5" size="5" name="billing_zip" id="paymenet-billing-zip"
-                        value="[% zip.truncate(5)  %]" /></td>
-                </tr>
-               </tbody>
-               </table>
-               
-               <table id="credit_card_info_table">
-               <tbody>
-                <tr>
-                  <td colspan='2' class="cc_header"><strong>[% l('Credit Card Information') %]</strong></td>
-                </tr>
-                <tr>
-                    <td><label for="payment-credit-card">[% l('Credit Card #') %]</label></td>
-                    
-                     <!-- Make type tel, which prompts for numbers in mobile -->
-                    <td><input type="tel" pattern="[0-9]*" maxlength="16" id="payment-credit-card" required name="number"/></td>
-                </tr>
-                <tr>
-                    <td><label for="payment-security-code">[% l('Security Code') %]</label></td>
-                    <td>
-                         <!-- Make type tel, which prompts for numbers in mobile -->
-                        <input type="tel" pattern="[0-9]*" size="4" maxlength="5" id="payment-security-code" name="cvv2"/></td>
-                </tr>
-                <tr>
-                    <td><label for="payment-expire-month">[% l('Expiration Month') %]</label></td>
-                    <td>
-                        <select id="payment-expire-month" required name="expire_month">
-                            <option value="-1"></option>
-                            <option value="01">[% l("January (1)") %]</option>
-                            <option value="02">[% l("February (2)") %]</option>
-                            <option value="03">[% l("March (3)") %]</option>
-                            <option value="04">[% l("April (4)") %]</option>
-                            <option value="05">[% l("May (5)") %]</option>
-                            <option value="06">[% l("June (6)") %]</option>
-                            <option value="07">[% l("July (7)") %]</option>
-                            <option value="08">[% l("August (8)") %]</option>
-                            <option value="09">[% l("September (9)") %]</option>
-                            <option value="10">[% l("October (10)") %]</option>
-                            <option value="11">[% l("November (11)") %]</option>
-                            <option value="12">[% l("December (12)") %]</option>
-                        </select>
-                    </td>
-                </tr>
-                <tr>
-                    <td><label for="payment-expire-year">[% l('Expiration Year') %]</label></td>
-                    <td>
-                        <select id="payment-expire-year" name="expire_year">
-                        [% year = date.format(date.now, '%Y');
-                        y = year;
-                        WHILE y < year + 10; # show ten years starting now %]
-                            <option value="[% y %]">[% y %]</option>
-                        [% y = y + 1; END %]
-                        </select>
-                    </td>
-                </tr>
-                <tr>
-                   <td colspan='2'>
-                       <div id="payment_actions">
-                          [% l('Total amount:') %]
-                           <strong>[% money(ctx.fines.balance_owed) %]</strong><br />
-          
-                         <input type="submit" id="payment_submit" value="[% l('Next') %]" class="opac-button" />
-                         <a href="[% mkurl(ctx.opac_root _ '/myopac/main', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a> 
-                         <br/>
-                         
-                          
-                       </div>
-                   </td>
-                </tr>
-                
-          </tbody>
-        </table>
-         [% INCLUDE "opac/parts/myopac/main_refund_policy.tt2" %]
-        
+        [% IF ctx.use_stripe %]
+            [% PROCESS "opac/myopac/stripe_payment_form.tt2"; %]
+        [% ELSE %]
+            [% PROCESS "opac/myopac/generic_payment_form.tt2"; %]
+        [% END %] <!-- of IF ctx.use_stripe -->
     [% END %]
-    </form>
 </div>
-[% END %]
-[% END %]
-[% END %]
+[% END %] <!-- of IF ctx.fines.balance_owed <= 0 -->
+[% END %] <!-- of.. something in one of the PROCESS or WRAPPER blocks? -->
diff --git a/Open-ILS/src/templates/opac/myopac/stripe_payment_form.tt2 b/Open-ILS/src/templates/opac/myopac/stripe_payment_form.tt2
new file mode 100644 (file)
index 0000000..b282e9c
--- /dev/null
@@ -0,0 +1,102 @@
+<noscript>
+    [% l("Your browser does not have Javascript enabled, and we cannot " _
+        "process credit card payments without it.  Please change your " _
+        "browser settings and try again.") %]
+</noscript>
+<script type="text/javascript">
+function build_stripe_form() {
+    var elements = stripe.elements();
+
+    var style = {
+        base: {
+            color: '#32325d',
+            fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
+            fontSmoothing: 'antialiased',
+            fontSize: '16px',
+            '::placeholder': {
+                color: '#aab7c4'
+            }
+        },
+        invalid: {
+            color: '#fa755a',
+            iconColor: '#fa755a'
+        }
+    };
+
+    var card = elements.create('card', {style: style});
+    card.mount('#card-element');
+
+    // real-time validation
+    card.on('change', function(event) {
+      var displayError = document.getElementById('card-errors');
+      if (event.error) {
+        displayError.textContent = event.error.message;
+      } else {
+        displayError.textContent = '';
+      }
+    });
+
+    // let's try some auto-focus
+    card.on('ready', function(event) {
+        try { card.focus(); } catch(E) { console.log('failed to focus card element',E); }
+    });
+
+    var form = document.getElementById('payment-form');
+    form.addEventListener('submit', function(event) {
+      event.preventDefault();
+
+      stripe.createToken(card).then(function(result) {
+        if (result.error) {
+          // Inform the user if there was an error.
+          var errorElement = document.getElementById('card-errors');
+          errorElement.textContent = result.error.message;
+        } else {
+          // Send the token to your server.
+          stripeTokenHandler(result.token);
+        }
+      });
+    });
+
+    function stripeTokenHandler(token) {
+      var form = document.getElementById('payment-form');
+      var hiddenInput = document.createElement('input');
+      hiddenInput.setAttribute('type', 'hidden');
+      hiddenInput.setAttribute('name', 'stripe_token');
+      hiddenInput.setAttribute('value', token.id);
+      form.appendChild(hiddenInput);
+
+      form.submit();
+    }
+}
+[% IF ctx.want_jquery %]
+    // jquery won't actually load until after this execution thread
+    setTimeout(function() { $(document).ready(build_stripe_form) }, 0);
+[% ELSE %]
+    // but jquery is preferable to doing this
+    setTimeout(build_stripe_form,0);
+[% END %]
+</script>
+<form action="#payment" method="post" id="payment-form">
+  <input type="hidden" name="last_chance" value="1" />
+  [% FOR xact IN CGI.param('xact') %]
+  <input type="hidden" name="xact" value="[% xact | html %]" />
+  [% END %]
+  [% FOR xact IN CGI.param('xact_misc') %]
+  <input type="hidden" name="xact_misc" value="[% xact | html %]" />
+  [% END %]
+  <div class="form-row">
+    <label for="card-element">
+      <h1>Credit Card Information</h1>
+    </label>
+    <div id="card-element">
+      <!-- A Stripe Element will be inserted here. -->
+    </div>
+
+    <!-- Used to display form errors. -->
+    <div id="card-errors" role="alert"></div>
+  </div>
+
+  <button class="opac-button">Next</button>
+  <a href="[% mkurl(ctx.opac_root _ '/myopac/main', {}, 1) %]" class="opac-button">[% l('Cancel') %]</a> 
+</form>
+<table>[% INCLUDE "opac/parts/myopac/main_refund_policy.tt2" %]</table>