is_knitpay_active = acadlix()->helper()->acadlix_get_option('acadlix_knit_pay_active') === 'yes';
$this->knitpay_title = acadlix()->helper()->acadlix_get_option('acadlix_knit_pay_title', 'Knit Pay');
$this->knitpay_configuration = acadlix()->helper()->acadlix_get_option('acadlix_knit_pay_configuration', '');
}
public function is_knitpay_active(): bool
{
if (
acadlix()->integrations()->knit_pay()->is_active() &&
$this->is_knitpay_active &&
$this->knitpay_configuration !== ''
) {
return true;
}
return false;
}
public function get_title(): string
{
return $this->knitpay_title ?: 'Knit Pay';
}
public function setAmount(float $amount): self
{
$this->amount = $amount;
return $this;
}
public function setCurrency(string $currency): self
{
$this->currency = $currency;
return $this;
}
public function setBillingInfo(array $billing_info): self
{
$this->billing_info = $billing_info;
return $this;
}
public function setOrderItems(array $order_items): self
{
$this->order_items = $order_items;
return $this;
}
public function setOrderId(string|int $order_id): self
{
$this->order_id = $order_id;
return $this;
}
protected function returnUrl()
{
$thankyou_page_id = acadlix()->helper()->acadlix_get_option('acadlix_thankyou_page_id');
$nonce = wp_create_nonce('acadlix_payment_nonce');
$url = add_query_arg("nonce", $nonce, get_permalink($thankyou_page_id));
return esc_url($url);
}
protected function notifyUrl()
{
return acadlix()->helper()->acadlix_get_webhook_url('knitpay');
}
protected function successOrder($order)
{
if (!$order) {
throw new Exception('Order not found');
}
$order->success_order();
$message = 'Order status updated to success';
$order->createActivityLog($message);
if ($order->order_items()->count() > 0) {
foreach ($order->order_items as $item) {
$cart = acadlix()
->model()
->courseCart()
->where('user_id', $order->user_id)
->where('item_id', $item->item_id)
->where('type', $item->type)
->first();
if ($cart) {
$cart->delete();
}
}
}
return ['success' => true, 'message' => 'Order captured successfully'];
}
public function failedOrder($order, $message = '')
{
if (!$order) {
throw new Exception('Order not found');
}
$order->failed_order();
if ($order->status != Order::STATUS_FAILED) {
$message = 'Order status updated to failed';
$order->createActivityLog($message);
}
$order->updateOrCreateMeta('failure_reason', $message);
return ['success' => true, 'message' => $message];
}
public function processOrder(): array|object|null
{
if (!$this->is_knitpay_active()) {
return new WP_Error('knitpay_inactive', __('Knitpay payment gateway is not active.', 'acadlix'), array('status' => 500));
}
$config_id = $this->knitpay_configuration; // TODO: configuration id should be passed here which was saved by user on configuration page.
$payment_method = 'knit_pay';
// Use default gateway if no configuration has been set.
if (empty($config_id)) {
$config_id = get_option('pronamic_pay_config_id');
}
$gateway = Plugin::get_gateway($config_id);
if (!$gateway) {
return new WP_Error('invalid_gateway', __('Invalid payment gateway configuration.', 'acadlix'), array('status' => 500));
}
$order_id = $this->order_id; // TODO: your order id here
$return_url = $this->returnUrl(); // TODO: your redirect url here
$notify_url = $this->notifyUrl(); // TODO: your notify url
/**
* Build payment.
*/
$payment = new Payment();
$payment->source = self::SLUG; //TODO: Change this with your plugin slug
$payment->source_id = $order_id;
$payment->order_id = $order_id;
$payment->set_description("Order " . $order_id); // TODO Payment Description
$payment->title = "Order " . $order_id;
$billing_info = $this->billing_info;
// Customer.
$customer_name = ContactNameHelper::from_array(
[
'first_name' => $billing_info['first_name'] ?? '', // TODO: customer first name here
'last_name' => $billing_info['last_name'] ?? '', // TODO: customer last name here
]
);
$payment->set_customer(CustomerHelper::from_array(
[
'name' => $customer_name,
'email' => $billing_info['email'] ?? '', // TODO: customer email here
'phone' => $billing_info['phone_number'] ?? '', // TODO: customer phone here
]
));
// Address.
$payment->set_billing_address(AddressHelper::from_array(
// address array, pass only those fields which are available
[
'name' => $customer_name,
'email' => $billing_info['email'] ?? '', // TODO: customer email here
'phone' => $billing_info['phone_number'] ?? '', // TODO: customer phone here
'line_1' => $billing_info['address'] ?? '', // TODO: customer address line 1 here
'line_2' => '', // TODO: customer address line 2 here
'postal_code' => $billing_info['zip_code'] ?? '', // TODO: customer postal code here
'city' => $billing_info['city'] ?? '', // TODO: customer city here
'region' => $billing_info['state'] ?? '', // TODO: customer state here
'country_code' => $billing_info['country_code'] ?? '', // TODO: customer country code here
]
));
// Currency.
$currency = Currency::get_instance($this->currency); // TODO: your currency here
// Amount.
$payment->set_total_amount(new Money($this->amount, $currency)); // TODO: your amount here. change 100.00 to your amount
// Method.
$payment->set_payment_method($payment_method);
// Configuration.
$payment->config_id = $config_id;
try {
$payment = Plugin::start_payment($payment);
$return_url = add_query_arg('kp_payment_id', $payment->get_id(), $return_url);
$payment->set_meta('rest_redirect_url', $return_url);
$payment->set_meta('rest_notify_url', $notify_url);
$payment->save();
// TODO: redirect customer to this url
$redirect_url = $payment->get_pay_redirect_url();
return (object) [
'id' => $payment->get_id(),
'redirect_url' => $redirect_url,
];
} catch (\Exception $e) {
return new WP_Error('payment_error', $e->getMessage(), array('status' => 500));
}
}
public function verifyWebhook(array $data): WP_Error|\WP_REST_Response
{
try {
if (!$this->is_knitpay_active()) {
throw new Exception(__('Knitpay payment gateway is not active.', 'acadlix'));
}
$payload = $data['stream'] ?? '';
if (empty($payload)) {
return new WP_Error('invalid_webhook', __('Webhook payload is missing.', 'acadlix'), array('status' => 400));
}
$stream_data = is_array($payload) ? $payload : json_decode((string) $payload, true);
if (!is_array($stream_data)) {
return new WP_Error('invalid_webhook', __('Invalid webhook payload format.', 'acadlix'), array('status' => 400));
}
$kp_payment_id = isset($stream_data['id']) ? absint($stream_data['id']) : 0;
if (!$kp_payment_id) {
return new WP_Error('invalid_webhook', __('Missing payment ID in webhook payload.', 'acadlix'), array('status' => 400));
}
// error_log('Received Knitpay webhook payment id: ' . $kp_payment_id);
$this->verifyOrder($kp_payment_id);
return new \WP_REST_Response([
'success' => true,
'kp_payment_id' => $kp_payment_id,
], 200);
} catch (Exception $e) {
return new WP_Error(
'webhook_error',
__('Knitpay webhook error: ', 'acadlix') . esc_html($e->getMessage()),
['status' => 500]
);
}
}
protected function getKpPayment($kp_payment_id)
{
if (function_exists('get_pronamic_payment')) {
return get_pronamic_payment($kp_payment_id);
}
return new WP_Error('function_not_exists', __('Required function get_pronamic_payment does not exist.', 'acadlix'), array('status' => 500));
}
public function getOrder($kp_order_id)
{
$payment = $this->getKpPayment($kp_order_id);
if (is_wp_error($payment)) {
return $payment;
}
if ($payment) {
$order = acadlix()->model()->order()->find($payment->get_order_id());
if (!$order) {
return new WP_Error('order_not_found', __('Order not found for the given payment ID.', 'acadlix'), array('status' => 500));
}
return $order;
}
return new WP_Error('order_not_found', __('Order not found for the given payment ID.', 'acadlix'), array('status' => 500));
}
public function getPaymentStatus($kp_order_id)
{
$payment = $this->getKpPayment($kp_order_id);
if (is_wp_error($payment)) {
return $payment;
}
if ($payment) {
switch ($payment->get_status()) {
case Core_Statuses::CANCELLED:
case Core_Statuses::EXPIRED:
case Core_Statuses::FAILURE:
return Order::STATUS_FAILED;
case Core_Statuses::SUCCESS:
return Order::STATUS_SUCCESS;
case Core_Statuses::OPEN:
return Order::STATUS_PENDING;
default:
return Order::STATUS_PENDING;
}
}
return Order::STATUS_PENDING;
}
public function verifyOrder($kp_order_id): void
{
try {
if (!$this->is_knitpay_active()) {
throw new Exception(__('Knitpay payment gateway is not active.', 'acadlix'));
}
if (!$kp_order_id) {
throw new Exception(__('Order ID is missing.', 'acadlix'));
}
$payment_status = $this->getPaymentStatus($kp_order_id);
if (is_wp_error($payment_status)) {
throw new Exception($payment_status->get_error_message());
}
$order = $this->getOrder($kp_order_id);
if (is_wp_error($order)) {
throw new Exception($order->get_error_message());
}
if ($payment_status == Order::STATUS_SUCCESS) {
$this->successOrder($order);
} else if ($payment_status == Order::STATUS_FAILED) {
$this->failedOrder($order, 'Payment failed via Knitpay');
} else {
$order->pending_order();
$message = "Order status updated to {$payment_status}";
$order->createActivityLog($message);
}
} catch (Exception $e) {
// Handle the error as needed, e.g., log it, notify admin, etc.
return;
}
}
public function get_order_link($order_id)
{
return admin_url('admin.php?page=acadlix_order#/edit/' . $order_id);
}
public function source_text($text, $payment)
{
$text = __('Acadlix', 'acadlix') . '
';
if (!empty($payment->source_id)) {
$text .= sprintf(
'%s',
$this->get_order_link($payment->source_id),
/* translators: %s: source id */
sprintf(__('Payment %s', 'acadlix'), $payment->source_id)
);
}
return $text;
}
public function source_description($description, $payment)
{
if ($payment->get_source() === self::SLUG) {
return __('Acadlix Order', 'acadlix');
}
return $description;
}
public function source_url($url, $payment)
{
if ($payment->get_source() === self::SLUG) {
return $this->get_order_link($payment->source_id);
}
return $url;
}
}