InfernoDev
Member
can someone help me understand the purchasable system I couldn't find any docs online anywhere, here is my code
my purchase form
the form above should ideally link to this purchasable when I click purchase? I'm just trying to understand the flow I keep getting invalid purchase request
my purchase form
Code:
<xf:js src="xf/payment.js" min="1" />
<div class="block">
<div class="block-container">
<div class="block-body">
<xf:form action="{{link('purchase')}}" method="post">
<xf:formrow rowtype="" label="Thread Title">
{$thread.title}
</xf:formrow>
<xf:formrow rowtype="" label="Details">
details.
</xf:formrow>
<xf:formrow rowtype="" label="Cost">
${$order.cost_amount}
</xf:formrow>
<div class="inputGroup">
<xf:button type="submit" icon="purchase">{{ phrase('Purchase') }}</xf:button>
</div>
</xf:form>
</div>
</div>
</div>
the form above should ideally link to this purchasable when I click purchase? I'm just trying to understand the flow I keep getting invalid purchase request
Code:
<?php
namespace infdevspecialoffers\Purchasables;
use XF\Entity\PaymentProfile;
use XF\Entity\User;
use XF\Payment\CallbackState;
use XF\Purchasable\AbstractPurchasable;
use XF\Purchasable\Purchase;
use XF\Http\Request;
class ThreadBump extends AbstractPurchasable
{
public function __construct(\XF\App $app)
{
parent::__construct($app); // pass $app to AbstractPurchasable
// any additional setup here
}
public function getPurchasableTypeId()
{
return 'thread_bump';
}
public function getTitle()
{
return \XF::phrase('pay_to_post_thread');
}
public function getPurchaseFromRequest(Request $request, User $purchaser, &$error = null)
{
$profileId = $request->filter('payment_profile_id', 'uint');
$threadId = $request->filter('thread_id', 'uint');
$paymentProfile = \XF::app()->em()->find(PaymentProfile::class, $profileId);
// Create the purchase request object dynamically
$profileFinder = \XF::finder('XF:PaymentProfile');
$paymentProfile = $profileFinder->where('provider_id', 'paypalrest')->fetchOne();
return [
'title' => \XF::phrase('thread_bump'),
'description' => 'This is a thread bump',
'purchasableTypeId' => 'thread_bump',
'purchasable_id' => 117,
'cost' => 10,
'currency' => 'USD',
'recurring' => false,
'purchaser' => $purchaser,
'paymentProfile' => $paymentProfile
];
$threadFinder = \XF::finder('XF:Thread');
$thread = $threadFinder->where('thread_id', $threadId);
return $this->getPurchaseObject($paymentProfile, $thread, $purchaser);
}
public function completePurchase(CallbackState $state)
{
// ✅ this is called when PayPal confirms
if ($state->paymentResult->isCompleted()) {
// do your granting logic
\XF::logError("Purchase completed for user");
return true;
}
return false;
}
public function getPurchasableFromExtraData(array $extraData)
{
return null;
}
public function getPurchaseFromExtraData(array $extraData, PaymentProfile $paymentProfile, User $purchaser, &$error = null)
{
return null;
}
public function getPurchaseObject(PaymentProfile $paymentProfile, $purchasable, User $purchaser)
{
$purchase = new Purchase();
$purchase->title = \XF::phrase('thread_bump');
$purchase->description = 'fdgdfgdfgdsfgdfg';
$purchase->cost = 6;
$purchase->currency = 'USD';
$purchase->recurring = false;
$purchase->lengthAmount = $purchasable->length_amount;
$purchase->lengthUnit = $purchasable->length_unit;
$purchase->purchaser = $purchaser;
$purchase->paymentProfile = $paymentProfile;
$purchase->purchasableTypeId = $this->purchasableTypeId;
$purchase->purchasableId = $purchasable->user_upgrade_id;
$purchase->purchasableTitle = $purchasable->title;
$router = \XF::app()->router('public');
$purchase->returnUrl = $router->buildLink('canonical:account/upgrade-purchase');
$purchase->updateUrl = $router->buildLink('canonical:account/upgrade-updated');
$purchase->cancelUrl = $router->buildLink('canonical:account/upgrades');
return $purchase;
}
public function reversePurchase(CallbackState $state)
{
return null;
}
public function getPurchasablesByProfileId($profileId)
{
return null;
}
}