Fixed Purchasables don't seem to support guests

Jake B.

Well-known member
Affected version
2.0.4
I'm using the XenForo purchasable system for our Donate add-on, but from what I can tell this doesn't support purchases from guests as it's checking for a valid user in \XF\Payment\AbstractProvider::validatePurchaser (assuming I'm not missing something obvious, which is also possible :P)
 
I guess what we need to do here is defer the purchaser validation to the purchasable item itself.

For now you could override the method in all of the default payment providers.
 
Yeah, I had thought about that -- but it wouldn't work on any custom payment providers from add-ons. I may do that temporarily until this is resolved and specify that it only works with the default payment providers for now (unless we manually extend any custom ones)
 
This is fixed for the next release.

There's a new validatePurchaser method in the AbstractPurchasable class with the same default behaviour as the current AbstractProvider class - ultimately it doesn't change anything for current payment providers or purchasables and payments from guests will be rejected as they are now, but you can now override that behaviour on a per-purchasable basis.
 
If you could test it does what you want it to do, that'd be great:
Diff:
Index: src/XF/Payment/AbstractProvider.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/XF/Payment/AbstractProvider.php    (revision 466e882018942ddd1f087a00d09bcb926cc3cb7c)
+++ src/XF/Payment/AbstractProvider.php    (date 1523436429000)
@@ -127,10 +127,12 @@
 
     public function validatePurchaser(CallbackState $state)
     {
-        if (!$state->getPurchaser())
+        $handler = $state->getPurchasableHandler();
+
+        if (!$handler->validatePurchaser($state, $error))
         {
             $state->logType = 'error';
-            $state->logMessage = 'Could not find user with user_id ' . $state->getPurchaseRequest()->user_id . '.';
+            $state->logMessage = $error;
             return false;
         }
         return true;
Index: src/XF/Purchasable/AbstractPurchasable.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/XF/Purchasable/AbstractPurchasable.php    (revision 466e882018942ddd1f087a00d09bcb926cc3cb7c)
+++ src/XF/Purchasable/AbstractPurchasable.php    (date 1523436515000)
@@ -72,6 +72,24 @@
      */
     abstract public function reversePurchase(CallbackState $state);
 
+    public function validatePurchaser(CallbackState $state, &$error = null)
+    {
+        if (!$state->getPurchaser())
+        {
+            if ($state->getPurchaseRequest()->user_id)
+            {
+                $error = 'Could not find user with user_id ' . $state->getPurchaseRequest()->user_id . '.';
+            }
+            else
+            {
+                $error = 'Purchasable type ' . $this->purchasableTypeId . ' does not support payments from guests.';
+            }
+
+            return false;
+        }
+        return true;
+    }
+
     /**
      * Given a payment profile ID, we can enumerate the purchasable items
      * which are used by these profiles. Useful to block accidental deletion
 
Yep, seems to work for the most part, only remaining change that may be needed is to only run sendPaymentReceipt if the purchaser is a user (or if the purchasable overwrites it to send to an inputted email, since the AbstractPurchasable is currently assuming it's a valid user) :)
 
Top Bottom