title: Trigger.IO in-app payments duplicate callbacks same orderid with different signature
body: <p>We have encountered a strange problem in the payment module of trigger.io. The flow works perfectly with ios payments but in android, some in-app payment callbacks are called twice in the same second. the receipt signatures are different but the orderid, notificationid, purchasetoken and developerPayload all stay the same. when we try to validate the receipt it turns out to be true and correct. But when we look at the financial report, we only see one payment instead of two (because its probably just one payment but why the different signatures?). </p>
  
  <p>why is trigger.io calling the callback twice which leads to the product being bought twice? why is android returning 2 different and confirmable receipts for one payment? is this a bug on andorid side or trigger.io side, cause i have no way of calling the callback using javascipt? or is this a known hack attempt?</p>
  
  <p>We also encountered a case where no callback was called at all, whereas the credit card was charged successfully. Is this a bug or are there any workarounds for this case?</p>
  
  <p>here is the code i'm initiating a purchase:</p>
  
  <pre><code>if(forge.is.android())
  forge.payments.purchaseProduct("someproductname", paymentSuccess, paymentError);
  </code></pre>
  
  <p>and here is the callback function:</p>
  
  <pre><code>function paymentCallback(data, confirm){
  
      forge.request.ajax({
          url: "someurl.php",
          dataType: "json",
          data:"function=logPayment&amp;action=PaymentCallbackStart",
          success: function (data) {
              hideLoader();
          },
          error: function (error) {
              hideLoader();
          }
      }); 
  
      var productId = data.productId;
      var orderId = data.orderId;
      var signed_data;
  
      if(forge.is.android())
      {
          var state = data.purchaseState;
          var receipt = encodeURIComponent(data.receipt.signature);
          signed_data = encodeURIComponent(data.receipt.data);
      }
      else if(forge.is.ios())
      {
          var state = data.PurchaseState;
          var receipt = data.receipt.data;
      }
  
      forge.request.ajax({
          url: "someurl.php",
          dataType: "json",
          data:"function=logPayment&amp;data=" +  encodeURIComponent("birthday=" +  gbirthday + "&amp;birthhour=" +  gbirthhour + "&amp;name=" +  gname + "&amp;gender=" + ggender + "&amp;birthday2=" + gbirthday2 + "&amp;birthhour2=" +  gbirthhour2 + "&amp;name2=" +  gname2 + "&amp;gender2=" + ggender2 + "&amp;content=" +  text + "&amp;ProductID=" + qs.ProductID + "&amp;userId=" + guserId + "&amp;data=" + JSON.stringify(data)) + "&amp;action=PaymentCallback",
          success: function (data) {
              hideLoader();
          },
          error: function (error) {
              hideLoader();
  
          }
      });     
  
      if(state == "PURCHASED")
      {
          if(typeof gbirthday != "undefined")
          {
              var text = $('#imessagem').val();
              forge.request.ajax({
                  url: "someurl.php",
                  dataType: "json",
                  data:"function=askQuestion&amp;birthday=" +  encodeURIComponent(gbirthday) + "&amp;birthhour=" +  encodeURIComponent(gbirthhour) + "&amp;name=" +  encodeURIComponent(gname) + "&amp;gender=" + ggender + "&amp;birthday2=" +  encodeURIComponent(gbirthday2) + "&amp;birthhour2=" +  encodeURIComponent(gbirthhour2) + "&amp;name2=" +  encodeURIComponent(gname2) + "&amp;gender2=" + ggender2 + "&amp;content=" +  encodeURIComponent(text) + "&amp;ProductID=" + qs.ProductID + "&amp;userId=" + guserId + "&amp;signed_data=" + signed_data + "&amp;receipt=" + receipt,
                  success: function (data) {
                      processPayment(productId,orderId)
                      hideLoader();
                  },
                  error: function (error) {
                      hideLoader();
  
                      forge.request.ajax({
                          url: "someurl.php",
                          dataType: "json",
                          data:"function=logPayment&amp;data=" + encodeURIComponent(JSON.stringify(error)) + "&amp;action=PaymentQuestionError",
                          success: function (data) {
                              hideLoader();
                          },
                          error: function (error) {
                              hideLoader();
  
                          }
                      });                     
  
                  }
              }); 
  
              forge.request.ajax({
                  url: "someurl.php",
                  dataType: "json",
                  data:"function=logPayment&amp;data=" +  encodeURIComponent(JSON.stringify(data)) + "&amp;action=Payment",
                  success: function (data) {
                      hideLoader();                   },
                  error: function (error) {
                      hideLoader();
  
                  }
              });             
          }
          if(forge.is.android())
          processPayment(productId,orderId);
      }
      else
      {
          if(forge.is.ios())
          processPayment(productId,orderId);
      }
      confirm();
  }   
  </code></pre>