mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-03 09:49:28 +02:00
Add Authorize.Net subscription management functionality
- Implemented cancelSubscription.json.php for handling subscription cancellations via JSON API. - Created cancelSubscription.php for managing subscription views and cancellation in the UI. - Developed getAcceptHostedToken.json.php to generate payment tokens for Authorize.Net. - Added getProfileManager.json.php for managing user profiles with Authorize.Net. - Implemented getSubscriptionStatus.json.php to check the status of subscriptions. - Created getSubscriptions.json.php to retrieve all subscriptions for the logged-in user. - Added SQL installation script for webhook logging. - Implemented processPayment.json.php for processing payments through Authorize.Net. - Developed webhook.php to handle incoming webhooks from Authorize.Net. - Integrated YPTWallet with Authorize.Net for wallet funding and subscription management. - Added confirmButton.php and confirmRecurrentButton.php for payment confirmation buttons in YPTWallet.
This commit is contained in:
parent
4ea653e8af
commit
e63ea73beb
21 changed files with 3312 additions and 0 deletions
1589
plugin/AuthorizeNet/AuthorizeNet.php
Normal file
1589
plugin/AuthorizeNet/AuthorizeNet.php
Normal file
File diff suppressed because it is too large
Load diff
156
plugin/AuthorizeNet/Objects/Anet_webhook_log.php
Normal file
156
plugin/AuthorizeNet/Objects/Anet_webhook_log.php
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once dirname(__FILE__) . '/../../../videos/configuration.php';
|
||||||
|
|
||||||
|
class Anet_webhook_log extends ObjectYPT
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $id, $uniq_key, $event_type, $trans_id, $payload_json, $processed, $error_text, $status, $created_php_time, $modified_php_time, $users_id;
|
||||||
|
|
||||||
|
static function getSearchFieldsNames()
|
||||||
|
{
|
||||||
|
return array('uniq_key', 'event_type', 'trans_id', 'error_text', 'status');
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getTableName()
|
||||||
|
{
|
||||||
|
return 'anet_webhook_log';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setId($id)
|
||||||
|
{
|
||||||
|
$this->id = intval($id);
|
||||||
|
}
|
||||||
|
function setUniq_key($uniq_key)
|
||||||
|
{
|
||||||
|
$this->uniq_key = $uniq_key;
|
||||||
|
}
|
||||||
|
function setEvent_type($event_type)
|
||||||
|
{
|
||||||
|
$this->event_type = $event_type;
|
||||||
|
}
|
||||||
|
function setTrans_id($trans_id)
|
||||||
|
{
|
||||||
|
$this->trans_id = $trans_id;
|
||||||
|
}
|
||||||
|
function setPayload_json($payload_json)
|
||||||
|
{
|
||||||
|
$this->payload_json = $payload_json;
|
||||||
|
}
|
||||||
|
function setProcessed($processed)
|
||||||
|
{
|
||||||
|
$this->processed = intval($processed);
|
||||||
|
}
|
||||||
|
function setError_text($error_text)
|
||||||
|
{
|
||||||
|
$this->error_text = $error_text;
|
||||||
|
}
|
||||||
|
function setStatus($status)
|
||||||
|
{
|
||||||
|
$this->status = $status;
|
||||||
|
}
|
||||||
|
function setCreated_php_time($created_php_time)
|
||||||
|
{
|
||||||
|
$this->created_php_time = $created_php_time;
|
||||||
|
}
|
||||||
|
function setModified_php_time($modified_php_time)
|
||||||
|
{
|
||||||
|
$this->modified_php_time = $modified_php_time;
|
||||||
|
}
|
||||||
|
function setUsers_id($users_id)
|
||||||
|
{
|
||||||
|
$this->users_id = intval($users_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId()
|
||||||
|
{
|
||||||
|
return intval($this->id);
|
||||||
|
}
|
||||||
|
function getUniq_key()
|
||||||
|
{
|
||||||
|
return $this->uniq_key;
|
||||||
|
}
|
||||||
|
function getEvent_type()
|
||||||
|
{
|
||||||
|
return $this->event_type;
|
||||||
|
}
|
||||||
|
function getTrans_id()
|
||||||
|
{
|
||||||
|
return $this->trans_id;
|
||||||
|
}
|
||||||
|
function getPayload_json()
|
||||||
|
{
|
||||||
|
return $this->payload_json;
|
||||||
|
}
|
||||||
|
function getProcessed()
|
||||||
|
{
|
||||||
|
return intval($this->processed);
|
||||||
|
}
|
||||||
|
function getError_text()
|
||||||
|
{
|
||||||
|
return $this->error_text;
|
||||||
|
}
|
||||||
|
function getStatus()
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
function getCreated_php_time()
|
||||||
|
{
|
||||||
|
return $this->created_php_time;
|
||||||
|
}
|
||||||
|
function getModified_php_time()
|
||||||
|
{
|
||||||
|
return $this->modified_php_time;
|
||||||
|
}
|
||||||
|
function getUsers_id()
|
||||||
|
{
|
||||||
|
return intval($this->users_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function alreadyProcessed($uniq_key)
|
||||||
|
{
|
||||||
|
if (empty($uniq_key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$obj = self::getFromUniqKey($uniq_key);
|
||||||
|
if (!empty($obj) && !empty($obj['processed'])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getFromUniqKey($uniq_key)
|
||||||
|
{
|
||||||
|
global $global;
|
||||||
|
$sql = "SELECT * FROM " . static::getTableName() . " WHERE uniq_key = ? LIMIT 1";
|
||||||
|
$res = sqlDAL::readSql($sql, "s", [$uniq_key]);
|
||||||
|
$data = sqlDAL::fetchAssoc($res);
|
||||||
|
sqlDAL::close($res);
|
||||||
|
if ($res) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createIfNotExists($uniq_key, $event_type, $payload_json, $users_id = 0)
|
||||||
|
{
|
||||||
|
if (self::alreadyProcessed($uniq_key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($users_id)){
|
||||||
|
$users_id = User::getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
$obj = new self();
|
||||||
|
$obj->setUniq_key($uniq_key);
|
||||||
|
$obj->setEvent_type($event_type);
|
||||||
|
$obj->setPayload_json(_json_encode($payload_json));
|
||||||
|
$obj->setUsers_id($users_id);
|
||||||
|
$obj->setProcessed(0);
|
||||||
|
$obj->setCreated_php_time(time());
|
||||||
|
$obj->setModified_php_time(time());
|
||||||
|
|
||||||
|
return $obj->save();
|
||||||
|
}
|
||||||
|
}
|
33
plugin/AuthorizeNet/View/Anet_webhook_log/add.json.php
Normal file
33
plugin/AuthorizeNet/View/Anet_webhook_log/add.json.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once '../../../../videos/configuration.php';
|
||||||
|
require_once $global['systemRootPath'] . 'plugin/AuthorizeNet/Objects/Anet_webhook_log.php';
|
||||||
|
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->error = true;
|
||||||
|
$obj->msg = "";
|
||||||
|
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
|
||||||
|
if(!User::isAdmin()){
|
||||||
|
$obj->msg = "You cant do this";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
$o = new Anet_webhook_log(@$_POST['id']);
|
||||||
|
$o->setUniq_key($_POST['uniq_key']);
|
||||||
|
$o->setEvent_type($_POST['event_type']);
|
||||||
|
$o->setTrans_id($_POST['trans_id']);
|
||||||
|
$o->setPayload_json($_POST['payload_json']);
|
||||||
|
$o->setProcessed($_POST['processed']);
|
||||||
|
$o->setError_text($_POST['error_text']);
|
||||||
|
$o->setStatus($_POST['status']);
|
||||||
|
$o->setCreated_php_time($_POST['created_php_time']);
|
||||||
|
$o->setModified_php_time($_POST['modified_php_time']);
|
||||||
|
$o->setUsers_id($_POST['users_id']);
|
||||||
|
|
||||||
|
if($id = $o->save()){
|
||||||
|
$obj->error = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($obj);
|
20
plugin/AuthorizeNet/View/Anet_webhook_log/delete.json.php
Normal file
20
plugin/AuthorizeNet/View/Anet_webhook_log/delete.json.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
require_once '../../../../videos/configuration.php';
|
||||||
|
require_once $global['systemRootPath'] . 'plugin/AuthorizeNet/Objects/Anet_webhook_log.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->error = true;
|
||||||
|
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
|
||||||
|
if(!User::isAdmin()){
|
||||||
|
$obj->msg = "You cant do this";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = intval($_POST['id']);
|
||||||
|
$row = new Anet_webhook_log($id);
|
||||||
|
$obj->error = !$row->delete();
|
||||||
|
die(json_encode($obj));
|
||||||
|
?>
|
19
plugin/AuthorizeNet/View/Anet_webhook_log/index.php
Normal file
19
plugin/AuthorizeNet/View/Anet_webhook_log/index.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
global $global, $config;
|
||||||
|
if (!isset($global['systemRootPath'])) {
|
||||||
|
require_once __DIR__.'/../../../../videos/configuration.php';
|
||||||
|
}
|
||||||
|
if (!User::isAdmin()) {
|
||||||
|
forbiddenPage('You can not do this');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
if(empty($plugin)){
|
||||||
|
forbiddenPage('Plugin AuthorizeNet is disabled');
|
||||||
|
}
|
||||||
|
$_page = new Page(array('AuthorizeNet'));
|
||||||
|
$_page->setExtraStyles(array('view/css/DataTables/datatables.min.css', 'view/js/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css'));
|
||||||
|
$_page->setExtraScripts(array('view/css/DataTables/datatables.min.js'));
|
||||||
|
include $global['systemRootPath'] . 'plugin/AuthorizeNet/View/Anet_webhook_log/index_body.php';
|
||||||
|
$_page->print();
|
||||||
|
?>
|
169
plugin/AuthorizeNet/View/Anet_webhook_log/index_body.php
Normal file
169
plugin/AuthorizeNet/View/Anet_webhook_log/index_body.php
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
<?php
|
||||||
|
global $global, $config;
|
||||||
|
if (!isset($global['systemRootPath'])) {
|
||||||
|
require_once '../../videos/configuration.php';
|
||||||
|
}
|
||||||
|
if (!User::isAdmin()) {
|
||||||
|
forbiddenPage('Admins only');
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<i class="fas fa-cog"></i> <?php echo __("Configurations"); ?>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="panel panel-default ">
|
||||||
|
<div class="panel-heading"><i class="far fa-plus-square"></i> <?php echo __("Create"); ?></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form id="panelAnet_webhook_logForm">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="form-group col-sm-12">
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<span class="btn btn-success" id="newAnet_webhook_logLink" onclick="clearAnet_webhook_logForm()"><i class="fas fa-plus"></i> <?php echo __("New"); ?></span>
|
||||||
|
<button class="btn btn-primary" type="submit"><i class="fas fa-save"></i> <?php echo __("Save"); ?></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="panel panel-default ">
|
||||||
|
<div class="panel-heading"><i class="fas fa-edit"></i> <?php echo __("Edit"); ?></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table id="Anet_webhook_logTable" class="display table table-bordered table-responsive table-striped table-hover table-condensed" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="Anet_webhook_logbtnModelLinks" style="display: none;">
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<button href="" class="edit_Anet_webhook_log btn btn-default btn-xs">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
</button>
|
||||||
|
<button href="" class="delete_Anet_webhook_log btn btn-danger btn-xs">
|
||||||
|
<i class="fa fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
function clearAnet_webhook_logForm() {
|
||||||
|
|
||||||
|
}
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('#addAnet_webhook_logBtn').click(function () {
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL+'plugin/AuthorizeNet/View/addAnet_webhook_logVideo.php',
|
||||||
|
data: $('#panelAnet_webhook_logForm').serialize(),
|
||||||
|
type: 'post',
|
||||||
|
success: function (response) {
|
||||||
|
if (response.error) {
|
||||||
|
avideoAlertError(response.msg);
|
||||||
|
} else {
|
||||||
|
avideoToast("<?php echo __("Your register has been saved!"); ?>");
|
||||||
|
$("#panelAnet_webhook_logForm").trigger("reset");
|
||||||
|
}
|
||||||
|
clearAnet_webhook_logForm();
|
||||||
|
tableVideos.ajax.reload();
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var Anet_webhook_logtableVar = $('#Anet_webhook_logTable').DataTable({
|
||||||
|
serverSide: true,
|
||||||
|
"ajax": webSiteRootURL+"plugin/AuthorizeNet/View/Anet_webhook_log/list.json.php",
|
||||||
|
"columns": [
|
||||||
|
,
|
||||||
|
{
|
||||||
|
sortable: false,
|
||||||
|
data: null,
|
||||||
|
defaultContent: $('#Anet_webhook_logbtnModelLinks').html()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
select: true,
|
||||||
|
});
|
||||||
|
$('#newAnet_webhook_log').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#panelAnet_webhook_logForm').trigger("reset");
|
||||||
|
$('#Anet_webhook_logid').val('');
|
||||||
|
});
|
||||||
|
$('#panelAnet_webhook_logForm').on('submit', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
modal.showPleaseWait();
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL+'plugin/AuthorizeNet/View/Anet_webhook_log/add.json.php',
|
||||||
|
data: $('#panelAnet_webhook_logForm').serialize(),
|
||||||
|
type: 'post',
|
||||||
|
success: function (response) {
|
||||||
|
if (response.error) {
|
||||||
|
avideoAlertError(response.msg);
|
||||||
|
} else {
|
||||||
|
avideoToast(__("Your register has been saved!"));
|
||||||
|
$("#panelAnet_webhook_logForm").trigger("reset");
|
||||||
|
}
|
||||||
|
Anet_webhook_logtableVar.ajax.reload();
|
||||||
|
$('#Anet_webhook_logid').val('');
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$('#Anet_webhook_logTable').on('click', 'button.delete_Anet_webhook_log', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var tr = $(this).closest('tr')[0];
|
||||||
|
var data = Anet_webhook_logtableVar.row(tr).data();
|
||||||
|
swal({
|
||||||
|
title: __("Are you sure?"),
|
||||||
|
text: __("You will not be able to recover this action!"),
|
||||||
|
icon: "warning",
|
||||||
|
buttons: true,
|
||||||
|
dangerMode: true,
|
||||||
|
})
|
||||||
|
.then(function (willDelete) {
|
||||||
|
if (willDelete) {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: webSiteRootURL+"plugin/AuthorizeNet/View/Anet_webhook_log/delete.json.php",
|
||||||
|
data: data
|
||||||
|
|
||||||
|
}).done(function (resposta) {
|
||||||
|
if (resposta.error) {
|
||||||
|
avideoAlertError(resposta.msg);
|
||||||
|
}
|
||||||
|
Anet_webhook_logtableVar.ajax.reload();
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$('#Anet_webhook_logTable').on('click', 'button.edit_Anet_webhook_log', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var tr = $(this).closest('tr')[0];
|
||||||
|
var data = Anet_webhook_logtableVar.row(tr).data();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
16
plugin/AuthorizeNet/View/Anet_webhook_log/list.json.php
Normal file
16
plugin/AuthorizeNet/View/Anet_webhook_log/list.json.php
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
require_once '../../../../videos/configuration.php';
|
||||||
|
require_once $global['systemRootPath'] . 'plugin/AuthorizeNet/Objects/Anet_webhook_log.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$rows = Anet_webhook_log::getAll();
|
||||||
|
$total = Anet_webhook_log::getTotal();
|
||||||
|
|
||||||
|
$response = array(
|
||||||
|
'data' => $rows,
|
||||||
|
'draw' => intval(@$_REQUEST['draw']),
|
||||||
|
'recordsTotal' => $total,
|
||||||
|
'recordsFiltered' => $total,
|
||||||
|
);
|
||||||
|
echo _json_encode($response);
|
||||||
|
?>
|
29
plugin/AuthorizeNet/View/editor.php
Normal file
29
plugin/AuthorizeNet/View/editor.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
require_once '../../../videos/configuration.php';
|
||||||
|
AVideoPlugin::loadPlugin("AuthorizeNet");
|
||||||
|
$_page = new Page(array('AuthorizeNet'));
|
||||||
|
$_page->setExtraStyles(array('view/css/DataTables/datatables.min.css', 'view/js/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css'));
|
||||||
|
$_page->setExtraScripts(array('view/css/DataTables/datatables.min.js', 'view/js/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js'));
|
||||||
|
?>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><?php echo __('AuthorizeNet') ?>
|
||||||
|
<div class="pull-right">
|
||||||
|
<?php echo AVideoPlugin::getSwitchButton("AuthorizeNet"); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="active"><a data-toggle="tab" href="#Anet_webhook_log"><?php echo __("anet_webhook_log"); ?></a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div id="Anet_webhook_log" class="tab-pane fade in active" style="padding: 10px;">
|
||||||
|
<?php include $global['systemRootPath'] . 'plugin/AuthorizeNet/View/Anet_webhook_log/index_body.php'; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
$_page->print();
|
||||||
|
?>
|
90
plugin/AuthorizeNet/acceptHostedReturn.php
Normal file
90
plugin/AuthorizeNet/acceptHostedReturn.php
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
|
||||||
|
$isCanceled = !empty($_GET['cancel']);
|
||||||
|
$type = $isCanceled ? 'cancel' : 'success';
|
||||||
|
|
||||||
|
$messages = [
|
||||||
|
'success' => [
|
||||||
|
'title' => 'Payment Successful',
|
||||||
|
'icon' => 'fa-check-circle',
|
||||||
|
'alert' => 'alert-success',
|
||||||
|
'button' => 'btn-success',
|
||||||
|
'progress' => 'progress-bar-success',
|
||||||
|
'text' => 'Your payment has been processed successfully. This window will close automatically.'
|
||||||
|
],
|
||||||
|
'cancel' => [
|
||||||
|
'title' => 'Payment Cancelled',
|
||||||
|
'icon' => 'fa-times-circle',
|
||||||
|
'alert' => 'alert-warning',
|
||||||
|
'button' => 'btn-warning',
|
||||||
|
'progress' => 'progress-bar-warning',
|
||||||
|
'text' => 'Your payment was not completed. You can try again or contact support if needed.'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$_page = new Page([$messages[$type]['title']]);
|
||||||
|
$_page->setIncludeNavbar(false);
|
||||||
|
$_page->setIncludeFooter(false);
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.countdown {
|
||||||
|
font-size: 16px;
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.btn-close-now {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
.progress {
|
||||||
|
margin-top: 15px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="container" style="margin-top: 50px;">
|
||||||
|
<div class="alert text-center <?php echo $messages[$type]['alert']; ?>">
|
||||||
|
<h3>
|
||||||
|
<i class="fa <?php echo $messages[$type]['icon']; ?>"></i>
|
||||||
|
<?php echo $messages[$type]['title']; ?>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p><?php echo $messages[$type]['text']; ?></p>
|
||||||
|
|
||||||
|
<p class="countdown">
|
||||||
|
<i class="fa fa-clock-o"></i> Closing in <span id="countdown">10</span> seconds...
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="progress">
|
||||||
|
<div id="progressBar" class="progress-bar <?php echo $messages[$type]['progress']; ?>" role="progressbar" style="width: 100%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn <?php echo $messages[$type]['button']; ?> btn-close-now" onclick="window.close();">
|
||||||
|
<i class="fa fa-sign-out"></i> Close Now
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var seconds = 10;
|
||||||
|
var total = seconds;
|
||||||
|
|
||||||
|
function updateCountdown() {
|
||||||
|
document.getElementById('countdown').innerText = seconds;
|
||||||
|
var percent = (seconds / total) * 100;
|
||||||
|
document.getElementById('progressBar').style.width = percent + '%';
|
||||||
|
|
||||||
|
if (seconds <= 0) {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
seconds--;
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(updateCountdown, 1000);
|
||||||
|
window.onload = updateCountdown;
|
||||||
|
</script>
|
||||||
|
<?php
|
||||||
|
$_page->print();
|
86
plugin/AuthorizeNet/cancelSubscription.json.php
Normal file
86
plugin/AuthorizeNet/cancelSubscription.json.php
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->error = true;
|
||||||
|
$obj->msg = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if user is logged in
|
||||||
|
if (!User::isLogged()) {
|
||||||
|
$obj->msg = "You must be logged in to cancel subscriptions";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if AuthorizeNet plugin is enabled
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
if (empty($plugin)) {
|
||||||
|
$obj->msg = "AuthorizeNet plugin is disabled";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get subscription ID from POST data
|
||||||
|
$subscriptionId = $_POST['subscriptionId'] ?? '';
|
||||||
|
|
||||||
|
if (empty($subscriptionId)) {
|
||||||
|
$obj->msg = "Missing subscription ID";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that this subscription belongs to the current user
|
||||||
|
$users_id = User::getId();
|
||||||
|
$customerProfileId = AuthorizeNet::getOrCreateCustomerProfile($users_id);
|
||||||
|
|
||||||
|
if (empty($customerProfileId)) {
|
||||||
|
$obj->msg = "Customer profile not found";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get subscription details to verify ownership
|
||||||
|
$subscriptionResult = AuthorizeNet::getSubscriptionWithCurrentStatus($subscriptionId);
|
||||||
|
|
||||||
|
if ($subscriptionResult['error']) {
|
||||||
|
$obj->msg = "Failed to verify subscription: " . $subscriptionResult['msg'];
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional security check: verify the subscription belongs to this customer
|
||||||
|
$userSubscriptions = AuthorizeNet::getUserActiveSubscriptions($users_id);
|
||||||
|
$subscriptionFound = false;
|
||||||
|
|
||||||
|
if (!$userSubscriptions['error']) {
|
||||||
|
foreach ($userSubscriptions['subscriptions'] as $sub) {
|
||||||
|
if ($sub['subscriptionId'] === $subscriptionId) {
|
||||||
|
$subscriptionFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$subscriptionFound) {
|
||||||
|
$obj->msg = "Subscription not found or does not belong to current user";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel the subscription
|
||||||
|
$cancelResult = AuthorizeNet::cancelSubscription($subscriptionId);
|
||||||
|
|
||||||
|
if ($cancelResult['error']) {
|
||||||
|
$obj->msg = $cancelResult['msg'];
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success response
|
||||||
|
$obj->error = false;
|
||||||
|
$obj->msg = "Subscription canceled successfully";
|
||||||
|
$obj->subscriptionId = $subscriptionId;
|
||||||
|
$obj->status = $cancelResult['status'];
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$obj->msg = "An error occurred: " . $e->getMessage();
|
||||||
|
_error_log("[AuthorizeNet] Error in cancelSubscription.json.php: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($obj);
|
||||||
|
?>
|
496
plugin/AuthorizeNet/cancelSubscription.php
Normal file
496
plugin/AuthorizeNet/cancelSubscription.php
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
|
||||||
|
// Check if user is logged in
|
||||||
|
if (!User::isLogged()) {
|
||||||
|
forbiddenPage('You must be logged in to access this page');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if AuthorizeNet plugin is enabled
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
if (empty($plugin)) {
|
||||||
|
forbiddenPage('AuthorizeNet plugin is disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
$users_id = User::getId();
|
||||||
|
$subscriptionId = $_GET['subscription_id'] ?? '';
|
||||||
|
|
||||||
|
// If specific subscription ID is provided, get that subscription
|
||||||
|
$subscription = null;
|
||||||
|
if (!empty($subscriptionId)) {
|
||||||
|
$result = AuthorizeNet::getSubscriptionWithCurrentStatus($subscriptionId);
|
||||||
|
if (!$result['error'] && !empty($result['subscription'])) {
|
||||||
|
$subscription = $result['subscription'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$_page = new Page(['Manage Subscription']);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h4>
|
||||||
|
<i class="fa fa-credit-card"></i>
|
||||||
|
<?php echo __('Manage Subscriptions'); ?>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<?php if (!empty($subscription)): ?>
|
||||||
|
<!-- Single Subscription View -->
|
||||||
|
<div class="well">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h4 class="media-heading">
|
||||||
|
<i class="fa fa-file-text-o"></i>
|
||||||
|
<?php echo htmlspecialchars($subscription['name'] ?? 'Subscription'); ?>
|
||||||
|
<?php
|
||||||
|
$status = strtolower($subscription['currentStatus'] ?? $subscription['status']);
|
||||||
|
$badgeClass = '';
|
||||||
|
switch($status) {
|
||||||
|
case 'active':
|
||||||
|
$badgeClass = 'label-success';
|
||||||
|
break;
|
||||||
|
case 'suspended':
|
||||||
|
$badgeClass = 'label-warning';
|
||||||
|
break;
|
||||||
|
case 'canceled':
|
||||||
|
case 'expired':
|
||||||
|
$badgeClass = 'label-danger';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$badgeClass = 'label-default';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<span class="label <?php echo $badgeClass; ?>">
|
||||||
|
<?php echo htmlspecialchars($subscription['currentStatus'] ?? $subscription['status']); ?>
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="row" style="margin-top: 15px;">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-tag"></i> <?php echo __('Subscription ID'); ?>:</strong><br>
|
||||||
|
<?php echo htmlspecialchars($subscription['subscriptionId']); ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-dollar"></i> <?php echo __('Amount'); ?>:</strong><br>
|
||||||
|
$<?php echo number_format($subscription['amount'], 2); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-clock-o"></i> <?php echo __('Billing Cycle'); ?>:</strong><br>
|
||||||
|
Every <?php echo $subscription['interval']['length']; ?>
|
||||||
|
<?php echo $subscription['interval']['unit']; ?></p>
|
||||||
|
</div>
|
||||||
|
<?php if (!empty($subscription['startDate'])): ?>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-calendar"></i> <?php echo __('Start Date'); ?>:</strong><br>
|
||||||
|
<?php echo htmlspecialchars($subscription['startDate']); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!empty($subscription['totalOccurrences']) || !empty($subscription['plans_id'])): ?>
|
||||||
|
<div class="row">
|
||||||
|
<?php if (!empty($subscription['totalOccurrences'])): ?>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-repeat"></i> <?php echo __('Total Occurrences'); ?>:</strong><br>
|
||||||
|
<?php echo htmlspecialchars($subscription['totalOccurrences']); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($subscription['plans_id'])): ?>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-list-alt"></i> <?php echo __('Plan ID'); ?>:</strong><br>
|
||||||
|
<?php echo htmlspecialchars($subscription['plans_id']); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 text-right">
|
||||||
|
<?php if ($subscription['isActive'] ?? false): ?>
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-danger btn-lg btn-block"
|
||||||
|
onclick="cancelSubscription('<?php echo htmlspecialchars($subscription['subscriptionId']); ?>')">
|
||||||
|
<i class="fa fa-times"></i> <?php echo __('Cancel Subscription'); ?>
|
||||||
|
</button>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<?php echo __('This subscription is no longer active'); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-default btn-block"
|
||||||
|
onclick="refreshSubscriptionStatus('<?php echo htmlspecialchars($subscription['subscriptionId']); ?>')">
|
||||||
|
<i class="fa fa-refresh"></i> <?php echo __('Refresh Status'); ?>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center">
|
||||||
|
<a href="<?php echo $global['webSiteRootURL']; ?>plugin/AuthorizeNet/cancelSubscription.php" class="btn btn-primary">
|
||||||
|
<i class="fa fa-arrow-left"></i> <?php echo __('Back to All Subscriptions'); ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
<!-- All Subscriptions View -->
|
||||||
|
<div id="subscriptionsContainer">
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="fa fa-spinner fa-spin fa-2x"></i>
|
||||||
|
<p><?php echo __('Loading your subscriptions...'); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-center" style="margin-top: 20px;">
|
||||||
|
<button type="button" class="btn btn-primary" onclick="loadSubscriptions()">
|
||||||
|
<i class="fa fa-refresh"></i> <?php echo __('Refresh Subscriptions'); ?>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
<?php if (empty($subscription)): ?>
|
||||||
|
loadSubscriptions();
|
||||||
|
<?php endif; ?>
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadSubscriptions() {
|
||||||
|
$('#subscriptionsContainer').html(`
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="fa fa-spinner fa-spin fa-2x"></i>
|
||||||
|
<p><?php echo __('Loading your subscriptions...'); ?></p>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL + 'plugin/AuthorizeNet/getSubscriptions.json.php',
|
||||||
|
type: 'GET',
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
if (response.error) {
|
||||||
|
$('#subscriptionsContainer').html(`
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
|
<strong><?php echo __('Error'); ?>:</strong> ${response.msg}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.subscriptions.length === 0) {
|
||||||
|
$('#subscriptionsContainer').html(`
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
|
<strong><?php echo __('No subscriptions found'); ?></strong>
|
||||||
|
<p><?php echo __('You don\'t have any active subscriptions at the moment.'); ?></p>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = '';
|
||||||
|
response.subscriptions.forEach(function(subscription) {
|
||||||
|
html += renderSubscriptionCard(subscription);
|
||||||
|
});
|
||||||
|
$('#subscriptionsContainer').html(html);
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
$('#subscriptionsContainer').html(`
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
|
<strong><?php echo __('Error'); ?>:</strong> <?php echo __('Failed to load subscriptions'); ?>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSubscriptionCard(subscription) {
|
||||||
|
const status = subscription.currentStatus ? subscription.currentStatus.toLowerCase() : subscription.status.toLowerCase();
|
||||||
|
const displayStatus = subscription.currentStatus || subscription.status;
|
||||||
|
const isActive = subscription.isActive || (subscription.status && subscription.status.toLowerCase() === 'active');
|
||||||
|
|
||||||
|
let badgeClass = '';
|
||||||
|
switch(status) {
|
||||||
|
case 'active':
|
||||||
|
badgeClass = 'label-success';
|
||||||
|
break;
|
||||||
|
case 'suspended':
|
||||||
|
badgeClass = 'label-warning';
|
||||||
|
break;
|
||||||
|
case 'canceled':
|
||||||
|
case 'expired':
|
||||||
|
badgeClass = 'label-danger';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
badgeClass = 'label-default';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="well">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h4 class="media-heading">
|
||||||
|
<i class="fa fa-file-text-o"></i>
|
||||||
|
${subscription.name || 'Subscription'}
|
||||||
|
<span class="label ${badgeClass}">
|
||||||
|
${displayStatus}
|
||||||
|
</span>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="row" style="margin-top: 15px;">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-tag"></i> <?php echo __('Subscription ID'); ?>:</strong><br>
|
||||||
|
${subscription.subscriptionId}</p>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-dollar"></i> <?php echo __('Amount'); ?>:</strong><br>
|
||||||
|
$${parseFloat(subscription.amount).toFixed(2)}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-clock-o"></i> <?php echo __('Billing Cycle'); ?>:</strong><br>
|
||||||
|
Every ${subscription.interval.length} ${subscription.interval.unit}</p>
|
||||||
|
</div>
|
||||||
|
${subscription.startDate ? `
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-calendar"></i> <?php echo __('Start Date'); ?>:</strong><br>
|
||||||
|
${subscription.startDate}</p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${subscription.plans_id ? `
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<p><strong><i class="fa fa-list-alt"></i> <?php echo __('Plan ID'); ?>:</strong><br>
|
||||||
|
${subscription.plans_id}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-4 text-right">
|
||||||
|
${isActive ? `
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-danger btn-block"
|
||||||
|
onclick="cancelSubscription('${subscription.subscriptionId}')">
|
||||||
|
<i class="fa fa-times"></i> <?php echo __('Cancel'); ?>
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelSubscription(subscriptionId) {
|
||||||
|
swal({
|
||||||
|
title: "<?php echo __('Are you sure?'); ?>",
|
||||||
|
text: "<?php echo __('This will cancel your subscription permanently. You will not be able to recover this action!'); ?>",
|
||||||
|
icon: "warning",
|
||||||
|
buttons: [
|
||||||
|
"<?php echo __('Cancel'); ?>",
|
||||||
|
"<?php echo __('Yes, cancel subscription'); ?>"
|
||||||
|
],
|
||||||
|
dangerMode: true,
|
||||||
|
}).then(function(willCancel) {
|
||||||
|
if (willCancel) {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL + 'plugin/AuthorizeNet/cancelSubscription.json.php',
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
subscriptionId: subscriptionId
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
swal("<?php echo __('Error'); ?>", response.msg, "error");
|
||||||
|
} else {
|
||||||
|
swal("<?php echo __('Success'); ?>", "<?php echo __('Subscription canceled successfully'); ?>", "success")
|
||||||
|
.then(function() {
|
||||||
|
<?php if (!empty($subscription)): ?>
|
||||||
|
location.reload();
|
||||||
|
<?php else: ?>
|
||||||
|
loadSubscriptions();
|
||||||
|
<?php endif; ?>
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
swal("<?php echo __('Error'); ?>", "<?php echo __('Failed to cancel subscription'); ?>", "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshSubscriptionStatus(subscriptionId) {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL + 'plugin/AuthorizeNet/getSubscriptionStatus.json.php',
|
||||||
|
type: 'GET',
|
||||||
|
data: {
|
||||||
|
subscriptionId: subscriptionId
|
||||||
|
},
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
avideoAlert("<?php echo __('Error'); ?>", response.msg, "error");
|
||||||
|
} else {
|
||||||
|
avideoToast("<?php echo __('Status refreshed successfully'); ?>");
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
avideoAlert("<?php echo __('Error'); ?>", "<?php echo __('Failed to refresh status'); ?>", "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewSubscriptionDetails(subscriptionId) {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL + 'plugin/AuthorizeNet/getSubscriptionDetails.json.php',
|
||||||
|
type: 'GET',
|
||||||
|
data: { subscriptionId: subscriptionId },
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(response) {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
avideoAlert("<?php echo __('Error'); ?>", response.msg, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subscription = response.subscription;
|
||||||
|
const modalContent = `
|
||||||
|
<div class="modal fade" id="subscriptionDetailsModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
|
<h4 class="modal-title">
|
||||||
|
<i class="fa fa-file-text-o"></i> <?php echo __('Subscription Details'); ?>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h5><i class="fa fa-info-circle"></i> <?php echo __('Basic Information'); ?></h5>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr><td><strong><?php echo __('Subscription ID'); ?>:</strong></td><td>${subscription.subscriptionId}</td></tr>
|
||||||
|
<tr><td><strong><?php echo __('Name'); ?>:</strong></td><td>${subscription.name || 'N/A'}</td></tr>
|
||||||
|
<tr><td><strong><?php echo __('Status'); ?>:</strong></td><td><span class="label label-${getStatusClass(subscription.currentStatus || subscription.status)}">${subscription.currentStatus || subscription.status}</span></td></tr>
|
||||||
|
<tr><td><strong><?php echo __('Amount'); ?>:</strong></td><td>$${parseFloat(subscription.amount).toFixed(2)}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<h5><i class="fa fa-calendar"></i> <?php echo __('Billing Information'); ?></h5>
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tr><td><strong><?php echo __('Billing Cycle'); ?>:</strong></td><td>Every ${subscription.interval.length} ${subscription.interval.unit}</td></tr>
|
||||||
|
<tr><td><strong><?php echo __('Start Date'); ?>:</strong></td><td>${subscription.startDate || 'N/A'}</td></tr>
|
||||||
|
<tr><td><strong><?php echo __('Next Payment'); ?>:</strong></td><td>${subscription.nextPaymentDate || 'N/A'}</td></tr>
|
||||||
|
<tr><td><strong><?php echo __('Total Occurrences'); ?>:</strong></td><td>${subscription.totalOccurrences || 'Unlimited'}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${subscription.paymentHistory ? `
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<h5><i class="fa fa-history"></i> <?php echo __('Payment History'); ?></h5>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><?php echo __('Date'); ?></th>
|
||||||
|
<th><?php echo __('Amount'); ?></th>
|
||||||
|
<th><?php echo __('Status'); ?></th>
|
||||||
|
<th><?php echo __('Transaction ID'); ?></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${subscription.paymentHistory.map(payment => `
|
||||||
|
<tr>
|
||||||
|
<td>${payment.date}</td>
|
||||||
|
<td>$${parseFloat(payment.amount).toFixed(2)}</td>
|
||||||
|
<td><span class="label label-${payment.status === 'completed' ? 'success' : 'warning'}">${payment.status}</span></td>
|
||||||
|
<td>${payment.transactionId}</td>
|
||||||
|
</tr>
|
||||||
|
`).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">
|
||||||
|
<i class="fa fa-times"></i> <?php echo __('Close'); ?>
|
||||||
|
</button>
|
||||||
|
${subscription.isActive ? `
|
||||||
|
<button type="button" class="btn btn-danger" onclick="cancelSubscription('${subscription.subscriptionId}')">
|
||||||
|
<i class="fa fa-times"></i> <?php echo __('Cancel Subscription'); ?>
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
$('body').append(modalContent);
|
||||||
|
$('#subscriptionDetailsModal').modal('show');
|
||||||
|
|
||||||
|
$('#subscriptionDetailsModal').on('hidden.bs.modal', function() {
|
||||||
|
$(this).remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
avideoAlert("<?php echo __('Error'); ?>", "<?php echo __('Failed to load subscription details'); ?>", "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStatusClass(status) {
|
||||||
|
switch(status.toLowerCase()) {
|
||||||
|
case 'active': return 'success';
|
||||||
|
case 'suspended': return 'warning';
|
||||||
|
case 'canceled':
|
||||||
|
case 'expired': return 'danger';
|
||||||
|
default: return 'default';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$_page->print();
|
||||||
|
?>
|
67
plugin/AuthorizeNet/getAcceptHostedToken.json.php
Normal file
67
plugin/AuthorizeNet/getAcceptHostedToken.json.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Google\Service\ServiceControl\Auth;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
if(!User::isLogged()){
|
||||||
|
forbiddenPage('You must be logged out to access this endpoint');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$obj = AVideoPlugin::getDataObject('AuthorizeNet');
|
||||||
|
$users_id = User::getId();
|
||||||
|
|
||||||
|
// ========== Validate payment amount ==========
|
||||||
|
if (!empty($_REQUEST['plans_id']) && AVideoPlugin::isEnabledByName('Subscription')) {
|
||||||
|
$sp = new SubscriptionPlansTable($_REQUEST['plans_id']);
|
||||||
|
$amount = $sp->getPrice();
|
||||||
|
}
|
||||||
|
if(empty($amount)){
|
||||||
|
$amount = isset($_REQUEST['amount']) ? floatval($_REQUEST['amount']) : 0;
|
||||||
|
}
|
||||||
|
if ($amount <= 0) {
|
||||||
|
echo json_encode(['error' => true, 'msg' => 'Invalid amount', 'line' => __LINE__]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== Add optional metadata ==========
|
||||||
|
$metadata = [];
|
||||||
|
$metadata['users_id'] = User::getId();
|
||||||
|
$metadata['plans_id'] = $_REQUEST['plans_id'] ?? 0;
|
||||||
|
|
||||||
|
AuthorizeNet::createWebhookIfNotExists();
|
||||||
|
|
||||||
|
// ========== Process payment via SDK using Accept opaque token + metadata ==========
|
||||||
|
$result = AuthorizeNet::generateHostedPaymentPage($amount, $metadata);
|
||||||
|
if (!empty($result['success'])) {
|
||||||
|
echo json_encode([
|
||||||
|
'error' => false,
|
||||||
|
'msg' => 'Payment created successfully',
|
||||||
|
'transactionId' => $result['transactionId'],
|
||||||
|
'line' => __LINE__
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== Return error response if payment fails ==========
|
||||||
|
echo json_encode([
|
||||||
|
'error' => !isset($result['error']) || !empty($result['error']),
|
||||||
|
'msg' => $result['msg'] ?? '',
|
||||||
|
'result' => $result,
|
||||||
|
'line' => __LINE__,
|
||||||
|
'url' => $result['url'] ?? '',
|
||||||
|
'token' => $result['token'] ?? '',
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// ========== Return exception error ==========
|
||||||
|
echo json_encode([
|
||||||
|
'error' => true,
|
||||||
|
'msg' => $e->getMessage(),
|
||||||
|
'line' => __LINE__
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
19
plugin/AuthorizeNet/getProfileManager.json.php
Normal file
19
plugin/AuthorizeNet/getProfileManager.json.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
require_once 'AuthorizeNet.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$users_id = User::getId();
|
||||||
|
$result = AuthorizeNet::generateManageProfileToken($users_id);
|
||||||
|
echo json_encode($result);
|
||||||
|
exit;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode([
|
||||||
|
'error' => true,
|
||||||
|
'msg' => $e->getMessage(),
|
||||||
|
'line' => __LINE__
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
78
plugin/AuthorizeNet/getSubscriptionStatus.json.php
Normal file
78
plugin/AuthorizeNet/getSubscriptionStatus.json.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->error = true;
|
||||||
|
$obj->msg = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if user is logged in
|
||||||
|
if (!User::isLogged()) {
|
||||||
|
$obj->msg = "You must be logged in to check subscription status";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if AuthorizeNet plugin is enabled
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
if (empty($plugin)) {
|
||||||
|
$obj->msg = "AuthorizeNet plugin is disabled";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get subscription ID from GET data
|
||||||
|
$subscriptionId = $_GET['subscriptionId'] ?? '';
|
||||||
|
|
||||||
|
if (empty($subscriptionId)) {
|
||||||
|
$obj->msg = "Missing subscription ID";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify ownership (similar to cancel endpoint)
|
||||||
|
$users_id = User::getId();
|
||||||
|
$customerProfileId = AuthorizeNet::getOrCreateCustomerProfile($users_id);
|
||||||
|
|
||||||
|
if (empty($customerProfileId)) {
|
||||||
|
$obj->msg = "Customer profile not found";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get subscription with current status
|
||||||
|
$subscriptionResult = AuthorizeNet::getSubscriptionWithCurrentStatus($subscriptionId);
|
||||||
|
|
||||||
|
if ($subscriptionResult['error']) {
|
||||||
|
$obj->msg = $subscriptionResult['msg'];
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify ownership
|
||||||
|
$userSubscriptions = AuthorizeNet::getUserActiveSubscriptions($users_id);
|
||||||
|
$subscriptionFound = false;
|
||||||
|
|
||||||
|
if (!$userSubscriptions['error']) {
|
||||||
|
foreach ($userSubscriptions['subscriptions'] as $sub) {
|
||||||
|
if ($sub['subscriptionId'] === $subscriptionId) {
|
||||||
|
$subscriptionFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$subscriptionFound) {
|
||||||
|
$obj->msg = "Subscription not found or does not belong to current user";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success response
|
||||||
|
$obj->error = false;
|
||||||
|
$obj->subscription = $subscriptionResult['subscription'];
|
||||||
|
$obj->status = $subscriptionResult['subscription']['currentStatus'];
|
||||||
|
$obj->isActive = $subscriptionResult['subscription']['isActive'];
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$obj->msg = "An error occurred: " . $e->getMessage();
|
||||||
|
_error_log("[AuthorizeNet] Error in getSubscriptionStatus.json.php: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($obj);
|
||||||
|
?>
|
72
plugin/AuthorizeNet/getSubscriptions.json.php
Normal file
72
plugin/AuthorizeNet/getSubscriptions.json.php
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$obj = new stdClass();
|
||||||
|
$obj->error = true;
|
||||||
|
$obj->msg = "";
|
||||||
|
$obj->subscriptions = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if user is logged in
|
||||||
|
if (!User::isLogged()) {
|
||||||
|
$obj->msg = "You must be logged in to view subscriptions";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if AuthorizeNet plugin is enabled
|
||||||
|
$plugin = AVideoPlugin::loadPluginIfEnabled('AuthorizeNet');
|
||||||
|
if (empty($plugin)) {
|
||||||
|
$obj->msg = "AuthorizeNet plugin is disabled";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
$users_id = User::getId();
|
||||||
|
|
||||||
|
// Get customer profile
|
||||||
|
$customerProfileId = AuthorizeNet::getOrCreateCustomerProfile($users_id);
|
||||||
|
|
||||||
|
if (empty($customerProfileId)) {
|
||||||
|
$obj->msg = "Customer profile not found";
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all subscriptions for this customer from Authorize.Net API
|
||||||
|
$subscriptionsResult = AuthorizeNet::getCustomerSubscriptions($customerProfileId);
|
||||||
|
|
||||||
|
if ($subscriptionsResult['error']) {
|
||||||
|
$obj->msg = $subscriptionsResult['msg'];
|
||||||
|
die(json_encode($obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
$subscriptionsWithStatus = [];
|
||||||
|
|
||||||
|
// Get current status for each subscription
|
||||||
|
foreach ($subscriptionsResult['subscriptions'] as $subscription) {
|
||||||
|
$subscriptionId = $subscription['subscriptionId'];
|
||||||
|
|
||||||
|
// Get detailed subscription info with current status
|
||||||
|
$detailsResult = AuthorizeNet::getSubscriptionWithCurrentStatus($subscriptionId);
|
||||||
|
|
||||||
|
if (!$detailsResult['error'] && !empty($detailsResult['subscription'])) {
|
||||||
|
$subscriptionsWithStatus[] = $detailsResult['subscription'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort subscriptions by creation date (newest first)
|
||||||
|
usort($subscriptionsWithStatus, function($a, $b) {
|
||||||
|
return $b['subscriptionId'] - $a['subscriptionId'];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Success response
|
||||||
|
$obj->error = false;
|
||||||
|
$obj->subscriptions = $subscriptionsWithStatus;
|
||||||
|
$obj->total = count($subscriptionsWithStatus);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$obj->msg = "An error occurred: " . $e->getMessage();
|
||||||
|
_error_log("[AuthorizeNet] Error in getSubscriptions.json.php: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($obj);
|
||||||
|
?>
|
22
plugin/AuthorizeNet/install/install.sql
Normal file
22
plugin/AuthorizeNet/install/install.sql
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS `anet_webhook_log` (
|
||||||
|
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`uniq_key` VARCHAR(120) NOT NULL,
|
||||||
|
`event_type` VARCHAR(120) NOT NULL,
|
||||||
|
`trans_id` VARCHAR(45) NULL,
|
||||||
|
`payload_json` JSON NOT NULL,
|
||||||
|
`processed` TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
|
`error_text` TEXT NULL,
|
||||||
|
`status` VARCHAR(45) NULL,
|
||||||
|
`created_php_time` BIGINT NULL,
|
||||||
|
`modified_php_time` BIGINT NULL,
|
||||||
|
`users_id` INT(11) NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE INDEX `uniq_key_UNIQUE` (`uniq_key` ASC),
|
||||||
|
INDEX `fk_anet_webhook_log_users1_idx` (`users_id` ASC),
|
||||||
|
INDEX `event_type_index` (`event_type` ASC),
|
||||||
|
CONSTRAINT `fk_anet_webhook_log_users1`
|
||||||
|
FOREIGN KEY (`users_id`)
|
||||||
|
REFERENCES `users` (`id`)
|
||||||
|
ON DELETE NO ACTION
|
||||||
|
ON UPDATE NO ACTION)
|
||||||
|
ENGINE = InnoDB;
|
29
plugin/AuthorizeNet/processPayment.json.php
Normal file
29
plugin/AuthorizeNet/processPayment.json.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$plugin = new AuthorizeNet();
|
||||||
|
$amount = isset($_POST['amount']) ? floatval($_POST['amount']) : 0;
|
||||||
|
$userData = isset($_POST['userData']) ? $_POST['userData'] : [];
|
||||||
|
if ($amount <= 0) {
|
||||||
|
echo json_encode(['error' => 'Invalid amount']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// TODO: Implement payment logic using Authorize.Net API
|
||||||
|
// Example: Call Authorize.Net API here
|
||||||
|
// $result = $plugin->chargePayment($amount, $userData);
|
||||||
|
|
||||||
|
// Simulate payment success for now
|
||||||
|
$paymentSuccess = true;
|
||||||
|
$users_id = @User::getId();
|
||||||
|
if ($paymentSuccess && !empty($users_id)) {
|
||||||
|
// Add funds to wallet
|
||||||
|
$walletPlugin = AVideoPlugin::loadPluginIfEnabled("YPTWallet");
|
||||||
|
if ($walletPlugin) {
|
||||||
|
$walletPlugin->addBalance($users_id, $amount, 'Authorize.Net one-time payment');
|
||||||
|
echo json_encode(['success' => true, 'result' => 'Payment processed and wallet updated']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo json_encode(['error' => 'Payment failed or user not logged in']);
|
140
plugin/AuthorizeNet/webhook.php
Normal file
140
plugin/AuthorizeNet/webhook.php
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../videos/configuration.php';
|
||||||
|
require_once $global['systemRootPath'] . 'plugin/AuthorizeNet/AuthorizeNet.php';
|
||||||
|
$global['bypassSameDomainCheck'] = 1;
|
||||||
|
|
||||||
|
$rawBody = file_get_contents('php://input');
|
||||||
|
$headers = getallheaders();
|
||||||
|
|
||||||
|
// 1) Parse + signature
|
||||||
|
$parsed = AuthorizeNet::parseWebhookRequest($rawBody, $headers);
|
||||||
|
if (!empty($parsed['error'])) {
|
||||||
|
_error_log('[Authorize.Net webhook] ' . $parsed['msg']);
|
||||||
|
http_response_code(200);
|
||||||
|
echo $parsed['msg'] ?? 'ignored';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
_error_log('[Authorize.Net webhook] Event: ' . $parsed['eventType']);
|
||||||
|
_error_log('[Authorize.Net webhook] uniq_key: ' . $parsed['uniq_key']);
|
||||||
|
|
||||||
|
// 2) Dedup
|
||||||
|
if (Anet_webhook_log::alreadyProcessed($parsed['uniq_key'])) {
|
||||||
|
_error_log('[Authorize.Net webhook] Duplicate ignored');
|
||||||
|
http_response_code(200);
|
||||||
|
echo 'duplicate';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Fetch txn (fallback/confirm)
|
||||||
|
$txnInfo = AuthorizeNet::getTransactionDetails($parsed['transactionId']);
|
||||||
|
|
||||||
|
// 4) Block only if both invalid signature AND no valid txn info
|
||||||
|
if (!$parsed['signatureValid'] && (empty($txnInfo) || !empty($txnInfo['error']))) {
|
||||||
|
_error_log('[Authorize.Net webhook] Bad signature and could not confirm transaction');
|
||||||
|
http_response_code(401);
|
||||||
|
echo 'invalid signature';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) Analyze payload + raw txn
|
||||||
|
$analysis = AuthorizeNet::analyzeTransactionFromWebhook($parsed['payload'], $txnInfo['raw'] ?? null);
|
||||||
|
|
||||||
|
// Fill missing basics from txnInfo if needed
|
||||||
|
if (!$analysis['users_id'] && !empty($txnInfo['users_id'])) {
|
||||||
|
$analysis['users_id'] = (int)$txnInfo['users_id'];
|
||||||
|
}
|
||||||
|
if (!$analysis['amount'] && isset($txnInfo['amount'])) {
|
||||||
|
$analysis['amount'] = (float)$txnInfo['amount'];
|
||||||
|
}
|
||||||
|
if (!$analysis['currency'] && !empty($txnInfo['currency'])) {
|
||||||
|
$analysis['currency'] = $txnInfo['currency'];
|
||||||
|
}
|
||||||
|
if (!$analysis['isApproved'] && !empty($txnInfo['isApproved'])) {
|
||||||
|
$analysis['isApproved'] = (bool)$txnInfo['isApproved'];
|
||||||
|
}
|
||||||
|
if (!$analysis['plans_id'] && !empty($txnInfo['plans_id'])) {
|
||||||
|
$analysis['plans_id'] = (int)$txnInfo['plans_id'];
|
||||||
|
}
|
||||||
|
_error_log('[Authorize.Net webhook] Analysis: ' . json_encode($analysis));
|
||||||
|
|
||||||
|
$result = AuthorizeNet::processSinglePayment(
|
||||||
|
$analysis['users_id'],
|
||||||
|
(float)$analysis['amount'],
|
||||||
|
$parsed['uniq_key'],
|
||||||
|
$parsed['eventType'],
|
||||||
|
$parsed['payload'],
|
||||||
|
!empty($analysis['plans_id'])? "Authorize.Net subscription charge plan [{$analysis['plans_id']}]" : 'Authorize.Net one-time payment'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($result['error'])) {
|
||||||
|
_error_log('[Authorize.Net webhook] Processing error: ' . $result['msg']);
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode($result);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8) Create subscription if needed
|
||||||
|
$subscriptionResult = null;
|
||||||
|
if (!empty($analysis['plans_id'])) {
|
||||||
|
_error_log('[Authorize.Net webhook] Creating subscription for plans_id: ' . $analysis['plans_id']);
|
||||||
|
// Check if user already has an active subscription for this plan
|
||||||
|
$existingCheck = AuthorizeNet::checkUserActiveSubscriptions(
|
||||||
|
$analysis['users_id'],
|
||||||
|
$analysis['plans_id']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$existingCheck['error'] && $existingCheck['hasActivePlanSubscription']) {
|
||||||
|
_error_log('[Authorize.Net webhook] User already has active subscription for plan: ' . $analysis['plans_id']);
|
||||||
|
$subscriptionResult = [
|
||||||
|
'error' => false,
|
||||||
|
'subscriptionId' => 'existing',
|
||||||
|
'msg' => 'User already has active subscription for this plan',
|
||||||
|
'existingSubscriptions' => $existingCheck['activeSubscriptions']
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$sp = new SubscriptionPlansTable($analysis['plans_id']);
|
||||||
|
$subscription_name = $sp->getName() ?? 'Subscription';
|
||||||
|
|
||||||
|
// Proceed with creating new subscription
|
||||||
|
$subscriptionMetadata = [
|
||||||
|
'users_id' => (int)$analysis['users_id'],
|
||||||
|
'plans_id' => (int)$analysis['plans_id'],
|
||||||
|
'subscription_name' => $subscription_name,
|
||||||
|
'initial_payment_id' => $parsed['transactionId']
|
||||||
|
];
|
||||||
|
|
||||||
|
$interval = (int)($sp->getHow_many_days() ?? 30);
|
||||||
|
$intervalUnit = 'days';
|
||||||
|
|
||||||
|
$subscriptionResult = AuthorizeNet::createSubscription(
|
||||||
|
$analysis['users_id'],
|
||||||
|
$analysis['amount'],
|
||||||
|
$subscriptionMetadata,
|
||||||
|
$interval,
|
||||||
|
$intervalUnit
|
||||||
|
);
|
||||||
|
|
||||||
|
Subscription::renew($analysis['users_id'], $analysis['plans_id'], SubscriptionTable::$gatway_authorize, $subscriptionResult['subscriptionId'], $subscriptionResult);
|
||||||
|
|
||||||
|
if (!empty($subscriptionResult['error'])) {
|
||||||
|
_error_log('[Authorize.Net webhook] Subscription creation failed: ' . $subscriptionResult['msg']);
|
||||||
|
// Don't fail the entire webhook - the payment was processed successfully
|
||||||
|
} else {
|
||||||
|
_error_log('[Authorize.Net webhook] Subscription created: ' . $subscriptionResult['subscriptionId']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9) Return success response
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'users_id' => $analysis['users_id'],
|
||||||
|
'subscription' => $analysis['isASubscription'],
|
||||||
|
'subscriptionId' => $analysis['subscriptionId'] ?? ($subscriptionResult['subscriptionId'] ?? null),
|
||||||
|
'newSubscription' => $shouldCreateSubscription,
|
||||||
|
'subscriptionCreated' => !empty($subscriptionResult) && empty($subscriptionResult['error']),
|
||||||
|
'sigValid' => $parsed['signatureValid'],
|
||||||
|
'logId' => $result['logId'] ?? null
|
||||||
|
]);
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
global $global;
|
||||||
|
require_once $global['systemRootPath'] . 'plugin/YPTWallet/YPTWalletPlugin.php';
|
||||||
|
require_once $global['systemRootPath'] . 'plugin/AuthorizeNet/AuthorizeNet.php';
|
||||||
|
|
||||||
|
class YPTWalletAuthorizeNet extends YPTWalletPlugin {
|
||||||
|
|
||||||
|
public function getAprovalLink() {
|
||||||
|
// Implement logic to generate Authorize.Net payment approval link if needed
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAprovalButton() {
|
||||||
|
global $global;
|
||||||
|
include $global['systemRootPath'].'plugin/YPTWallet/plugins/YPTWalletAuthorizeNet/confirmButton.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRecurrentAprovalButton() {
|
||||||
|
global $global;
|
||||||
|
include $global['systemRootPath'].'plugin/YPTWallet/plugins/YPTWalletAuthorizeNet/confirmRecurrentButton.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRecurrentAprovalButtonV2($total = '1.00', $currency = "USD", $frequency = "Month", $interval = 1, $name = '', $json = '', $addFunds_Success='', $trialDays = 0) {
|
||||||
|
$total = floatval($total);
|
||||||
|
if(empty($total)){
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
global $global;
|
||||||
|
include $global['systemRootPath'].'plugin/YPTWallet/plugins/YPTWalletAuthorizeNet/confirmRecurrentButtonV2.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmptyDataObject() {
|
||||||
|
$obj = new stdClass();
|
||||||
|
// Add custom config if needed
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// Authorize.Net Accept Hosted payment & profile management buttons for YPTWallet integration
|
||||||
|
?>
|
||||||
|
<div class="btn-group" role="group" aria-label="Authorize.Net Actions">
|
||||||
|
<button class="btn btn-primary" onclick="startAuthorizeNetAcceptHosted()">
|
||||||
|
<i class="fas fa-credit-card"></i> Pay with Authorize.Net
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-info" onclick="openAuthorizeNetProfileManager()">
|
||||||
|
<i class="fas fa-user-cog"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function startAuthorizeNetAcceptHosted() {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
var amount = $('#value<?php echo @$_GET['plans_id']; ?>').val();
|
||||||
|
if (!amount || isNaN(amount) || amount <= 0) {
|
||||||
|
avideoAlertError('Invalid amount');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch(webSiteRootURL + 'plugin/AuthorizeNet/getAcceptHostedToken.json.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: 'amount=' + encodeURIComponent(amount)
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
if (!data.error && data.token && data.url) {
|
||||||
|
const strWindowFeatures = "directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,resizable=no,height=650,width=1000";
|
||||||
|
openWindowWithPost(data.url, 'Authorize.Net' ,{'token': data.token}, strWindowFeatures);
|
||||||
|
} else {
|
||||||
|
avideoAlertError('Payment error: ' + (data.msg || 'Could not get payment token'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
avideoAlertError('Payment request failed: ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function openAuthorizeNetProfileManager() {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
fetch(webSiteRootURL + 'plugin/AuthorizeNet/getProfileManager.json.php')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
if (!data.error && data.token && data.url) {
|
||||||
|
avideoDialogWithPost(data.url, {'token': data.token});
|
||||||
|
} else {
|
||||||
|
avideoAlertError('Profile error: ' + (data.msg || 'Could not get profile token'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
avideoAlertError('Profile request failed: ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
$uniqid = uniqid('anetSub_');
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="btn-group" role="group" aria-label="Authorize.Net Actions">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-primary"
|
||||||
|
id="AuthorizeNetRecurringBtn<?php echo $uniqid; ?>">
|
||||||
|
<i class="fas fa-sync-alt"></i> <?php echo __('Subscribe with Authorize.Net'); ?>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-info" onclick="openAuthorizeNetProfileManager()">
|
||||||
|
<i class="fas fa-user-cog"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$('#AuthorizeNetRecurringBtn<?php echo $uniqid; ?>').on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
modal.showPleaseWait();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: webSiteRootURL + 'plugin/AuthorizeNet/getAcceptHostedToken.json.php',
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
"plans_id": "<?php echo @$_GET['plans_id']; ?>"
|
||||||
|
},
|
||||||
|
success: function(resp) {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
|
||||||
|
if (resp.error) {
|
||||||
|
avideoAlertError(resp.msg || 'Unknown error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show payment details and redirect to Accept Hosted
|
||||||
|
if (resp.token && resp.url) {
|
||||||
|
const strWindowFeatures = "directories=no,titlebar=no,toolbar=no,location=no,status=no,menubar=no,resizable=no,height=650,width=1000";
|
||||||
|
openWindowWithPost(resp.url, 'Authorize.Net', {
|
||||||
|
'token': resp.token
|
||||||
|
}, strWindowFeatures);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
avideoAlertSuccess(resp.msg || "<?php echo __('Request processed successfully'); ?>");
|
||||||
|
},
|
||||||
|
error: function(xhr, status, error) {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
console.error('XHR Error:', xhr, status, error);
|
||||||
|
try {
|
||||||
|
var errorResp = JSON.parse(xhr.responseText);
|
||||||
|
avideoAlertError(errorResp.msg || 'Connection error');
|
||||||
|
} catch (e) {
|
||||||
|
avideoAlertError('Connection error: ' + (error || 'Unknown error'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function openAuthorizeNetProfileManager() {
|
||||||
|
modal.showPleaseWait();
|
||||||
|
fetch(webSiteRootURL + 'plugin/AuthorizeNet/getProfileManager.json.php')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
if (!data.error && data.token && data.url) {
|
||||||
|
avideoDialogWithPost(data.url, {
|
||||||
|
'token': data.token
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
avideoAlertError('Profile error: ' + (data.msg || 'Could not get profile token'));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
modal.hidePleaseWait();
|
||||||
|
avideoAlertError('Profile request failed: ' + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue