From dd77f799cf2225f055765a6b7e9ed810abb5a176 Mon Sep 17 00:00:00 2001 From: Prabal Mallick Date: Thu, 16 Jul 2020 15:40:38 +0600 Subject: [PATCH] Initial Release of Moodle --- README.md | 32 +++ sslcommerz/api/Sslcommerz.php | 89 +++++++ sslcommerz/db/access.php | 57 ++++ sslcommerz/db/install.php | 33 +++ sslcommerz/db/install.xml | 46 ++++ sslcommerz/db/messages.php | 29 ++ sslcommerz/edit.php | 135 ++++++++++ sslcommerz/edit_form.php | 142 ++++++++++ sslcommerz/enrolment_form.php | 108 ++++++++ sslcommerz/lang/en/enrol_sslcommerz.php | 60 +++++ sslcommerz/lib.php | 336 ++++++++++++++++++++++++ sslcommerz/pay_process.php | 112 ++++++++ sslcommerz/pix/sslcommerz.png | Bin 0 -> 19229 bytes sslcommerz/pix/ssltitle.png | Bin 0 -> 5173 bytes sslcommerz/return.php | 69 +++++ sslcommerz/settings.php | 79 ++++++ sslcommerz/unenrolself.php | 62 +++++ sslcommerz/validation.php | 303 +++++++++++++++++++++ sslcommerz/version.php | 33 +++ 19 files changed, 1725 insertions(+) create mode 100644 README.md create mode 100644 sslcommerz/api/Sslcommerz.php create mode 100644 sslcommerz/db/access.php create mode 100644 sslcommerz/db/install.php create mode 100644 sslcommerz/db/install.xml create mode 100644 sslcommerz/db/messages.php create mode 100644 sslcommerz/edit.php create mode 100644 sslcommerz/edit_form.php create mode 100644 sslcommerz/enrolment_form.php create mode 100644 sslcommerz/lang/en/enrol_sslcommerz.php create mode 100644 sslcommerz/lib.php create mode 100644 sslcommerz/pay_process.php create mode 100644 sslcommerz/pix/sslcommerz.png create mode 100644 sslcommerz/pix/ssltitle.png create mode 100644 sslcommerz/return.php create mode 100644 sslcommerz/settings.php create mode 100644 sslcommerz/unenrolself.php create mode 100644 sslcommerz/validation.php create mode 100644 sslcommerz/version.php diff --git a/README.md b/README.md new file mode 100644 index 0000000..41a0c95 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# SSLCommerz-Moodle 3.9 + +Enrolment in Moodle using SSLCommerz payment gateway for paid courses + +This plugin helps admins and webmasters use SSLCommerz as the payment gateway. SSLCommerz is one of the most commonly used payment gateways and offers considerable number of features unsupported by other payment gateways like Paypal. This plugin has all the settings for development as well as for production usage. Its easy to install, set up and effective. + +## Installation Guidence : + +Login to your moodle site as an `admin user` and follow the steps. + +1) Upload the zip package from `Site administration` > `Plugins` > `Install plugins`. Choose Plugin type `Enrolment method (enrol)`. Upload the ZIP package, check the acknowledgement and install. + +2) Go to `Enrolments` > `Manage enrol plugins` > `Enable SSLCOmmerz` from list + +3) Click `Settings` which will lead to the settings page of the plugin + +4) Provide merchant credentials for SSLCommerz, select the checkbox as per requirement. Save the settings. + +5) Select any course from course listing page. + +6) Go to `Course administration` > `Users` > `Enrolment methods` > `Add method` `SSLCommerz` from the dropdown. Set `Custom instance name`, `Enrol cost` etc and add the method. + +This completes all the steps from the administrator end. Now registered users can login to the Moodle site and view the course after a successful payment. + + +## Contributor + +- Author : Prabal Mallick +- Team Email: integration@sslcommerz.com (For any query) +- More info: https://www.sslcommerz.com + +© 2019 SSLCOMMERZ ALL RIGHTS RESERVED \ No newline at end of file diff --git a/sslcommerz/api/Sslcommerz.php b/sslcommerz/api/Sslcommerz.php new file mode 100644 index 0000000..3ae0f3d --- /dev/null +++ b/sslcommerz/api/Sslcommerz.php @@ -0,0 +1,89 @@ +window.location.href = '". $sslcz['GatewayPageURL'] ."';"; + echo ""; + # header("Location: ". $sslcz['GatewayPageURL']); + exit; + } else { + echo "JSON Data parsing error!"; + } + } + + public static function orderValidation($store_id, $password, $env, $val_id) + { + if($env == "yes"){ + $direct_api_url = "https://securepay.sslcommerz.com/validator/api/validationserverAPI.php"; + } else{ + $direct_api_url = "https://sandbox.sslcommerz.com/validator/api/validationserverAPI.php"; + } + + $requested_url = $direct_api_url."?val_id=".$val_id."&store_id=".$store_id."&store_passwd=".$password."&v=1&format=json"; + + $handle = curl_init(); + curl_setopt($handle, CURLOPT_URL, $requested_url); + curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); + curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, false); # IF YOU RUN FROM LOCAL PC + curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false); # IF YOU RUN FROM LOCAL PC + + $result = curl_exec($handle); + + $code = curl_getinfo($handle, CURLINFO_HTTP_CODE); + + if($code == 200 && !( curl_errno($handle))) + { + # TO CONVERT AS ARRAY + # $result = json_decode($result, true); + # $status = $result['status']; + + # TO CONVERT AS OBJECT + $result = json_decode($result, true); + return $result; + } + else { + echo "Failed to connect with SSLCOMMERZ"; + } + } + } +?> \ No newline at end of file diff --git a/sslcommerz/db/access.php b/sslcommerz/db/access.php new file mode 100644 index 0000000..b64a05a --- /dev/null +++ b/sslcommerz/db/access.php @@ -0,0 +1,57 @@ +. + +/** + * Capabilities for SSLCommerz enrolment plugin. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$capabilities = array( + + 'enrol/sslcommerz:config' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'manager' => CAP_ALLOW, + ) + ), + 'enrol/sslcommerz:manage' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'manager' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + ) + ), + 'enrol/sslcommerz:unenrol' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'manager' => CAP_ALLOW, + ) + ), + 'enrol/sslcommerz:unenrolself' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + ) + ), +); diff --git a/sslcommerz/db/install.php b/sslcommerz/db/install.php new file mode 100644 index 0000000..09b283d --- /dev/null +++ b/sslcommerz/db/install.php @@ -0,0 +1,33 @@ +. + +/** + * SSLCommerz - database creation. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); +/** + * Sets up installation script. + * @return void + */ +function xmldb_enrol_sslcommerz_install() { + global $CFG, $DB; + +} diff --git a/sslcommerz/db/install.xml b/sslcommerz/db/install.xml new file mode 100644 index 0000000..76f7c23 --- /dev/null +++ b/sslcommerz/db/install.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
diff --git a/sslcommerz/db/messages.php b/sslcommerz/db/messages.php new file mode 100644 index 0000000..054f517 --- /dev/null +++ b/sslcommerz/db/messages.php @@ -0,0 +1,29 @@ +. + +/** + * Defines message providers (types of message sent) for the Stripe enrolment plugin. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Arkaprava Midya, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$messageproviders = array( + 'sslcommerz_enrolment' => array(), +); diff --git a/sslcommerz/edit.php b/sslcommerz/edit.php new file mode 100644 index 0000000..770d569 --- /dev/null +++ b/sslcommerz/edit.php @@ -0,0 +1,135 @@ +. + +/** + * Adds new instance of enrol_sslcommerz to specified course or edits current instance. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require ('../../config.php'); +require_once ('edit_form.php'); + +$courseid = required_param('courseid', PARAM_INT); +$instanceid = optional_param('id', 0, PARAM_INT); + +$course = $DB->get_record('course', array( + 'id' => $courseid +) , '*', MUST_EXIST); +$context = context_course::instance($course->id, MUST_EXIST); + +require_login($course); +require_capability('enrol/sslcommerz:config', $context); + +$PAGE->set_url('/enrol/sslcommerz/edit.php', array( + 'courseid' => $course->id, + 'id' => $instanceid +)); +$PAGE->set_pagelayout('admin'); + +$return = new moodle_url('/enrol/instances.php', array( + 'id' => $course->id +)); +if (!enrol_is_enabled('sslcommerz')) +{ + redirect($return); +} + +$plugin = enrol_get_plugin('sslcommerz'); + +if ($instanceid) +{ + $instance = $DB->get_record('enrol', array( + 'courseid' => $course->id, + 'enrol' => 'sslcommerz', + 'id' => $instanceid + ) , '*', MUST_EXIST); + $instance->cost = format_float($instance->cost, 2, true); +} +else +{ + require_capability('moodle/course:enrolconfig', $context); + // No instance yet, we have to add new instance. + navigation_node::override_active_url(new moodle_url('/enrol/instances.php', array( + 'id' => $course->id + ))); + $instance = new stdClass(); + $instance->id = null; + $instance->courseid = $course->id; +} + +$mform = new enrol_sslcommerz_edit_form(null, array( + $instance, + $plugin, + $context +)); + +if ($mform->is_cancelled()) +{ + redirect($return); + +} +else if ($data = $mform->get_data()) +{ + if ($instance->id) + { + $reset = ($instance->status != $data->status); + + $instance->status = $data->status; + $instance->name = $data->name; + $instance->cost = unformat_float($data->cost); + $instance->currency = $data->currency; + $instance->roleid = $data->roleid; + $instance->enrolperiod = $data->enrolperiod; + $instance->enrolstartdate = $data->enrolstartdate; + $instance->enrolenddate = $data->enrolenddate; + $instance->timemodified = time(); + $DB->update_record('enrol', $instance); + + if ($reset) + { + $context->mark_dirty(); + } + + } + else + { + $fields = array( + 'status' => $data->status, + 'name' => $data->name, + 'cost' => unformat_float($data->cost) , + 'currency' => $data->currency, + 'roleid' => $data->roleid, + 'enrolperiod' => $data->enrolperiod, + 'enrolstartdate' => $data->enrolstartdate, + 'enrolenddate' => $data->enrolenddate + ); + $plugin->add_instance($course, $fields); + } + + redirect($return); +} + +$PAGE->set_heading($course->fullname); +$PAGE->set_title(get_string('sslc_pluginname', 'enrol_sslcommerz')); + +echo $OUTPUT->header(); +echo $OUTPUT->heading(get_string('sslc_pluginname', 'enrol_sslcommerz')); +$mform->display(); +echo $OUTPUT->footer(); + diff --git a/sslcommerz/edit_form.php b/sslcommerz/edit_form.php new file mode 100644 index 0000000..9ef5f93 --- /dev/null +++ b/sslcommerz/edit_form.php @@ -0,0 +1,142 @@ +. + +/** + * Adds new instance of enrol_sslcommerz to specified course or edits current instance. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once ($CFG->libdir . '/formslib.php'); +/** + * Sets up moodle edit form class methods. + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_sslcommerz_edit_form extends moodleform +{ + /** + * Sets up moodle form. + * @return void + */ + public function definition() + { + global $CFG; + + $mform = $this->_form; + + list($instance, $plugin, $context) = $this->_customdata; + + $mform->addElement('header', 'header', get_string('pluginname', 'enrol_sslcommerz')); + + $mform->addElement('text', 'name', get_string('custominstancename', 'enrol')); + $mform->setType('name', PARAM_TEXT); + $options = array( + ENROL_INSTANCE_ENABLED => get_string('yes') , + ENROL_INSTANCE_DISABLED => get_string('no') + ); + $mform->addElement('select', 'status', get_string('status', 'enrol_sslcommerz') , $options); + $mform->setDefault('status', $plugin->get_config('status')); + $mform->addElement('text', 'cost', get_string('cost', 'enrol_sslcommerz') , array( + 'size' => 4 + )); + $mform->setType('cost', PARAM_RAW); // Use unformat_float to get real value. + $mform->setDefault('cost', format_float($plugin->get_config('cost') , 2, true)); + + $currencies = $plugin->get_currencies(); + $mform->addElement('select', 'currency', get_string('currency', 'enrol_sslcommerz') , $currencies); + $mform->setDefault('currency', $plugin->get_config('currency')); + + if ($instance->id) + { + $roles = get_default_enrol_roles($context, $instance->roleid); + } + else + { + $roles = get_default_enrol_roles($context, $plugin->get_config('roleid')); + } + $mform->addElement('select', 'roleid', get_string('assignrole', 'enrol_sslcommerz') , $roles); + $mform->setDefault('roleid', $plugin->get_config('roleid')); + + $mform->addElement('duration', 'enrolperiod', get_string('enrolperiod', 'enrol_sslcommerz') , array( + 'optional' => true, + 'defaultunit' => 86400 + )); + $mform->setDefault('enrolperiod', $plugin->get_config('enrolperiod')); + $mform->addHelpButton('enrolperiod', 'enrolperiod', 'enrol_sslcommerz'); + + $mform->addElement('date_time_selector', 'enrolstartdate', get_string('enrolstartdate', 'enrol_sslcommerz') , array( + 'optional' => true + )); + $mform->setDefault('enrolstartdate', 0); + $mform->addHelpButton('enrolstartdate', 'enrolstartdate', 'enrol_sslcommerz'); + + $mform->addElement('date_time_selector', 'enrolenddate', get_string('enrolenddate', 'enrol_sslcommerz') , array( + 'optional' => true + )); + $mform->setDefault('enrolenddate', 0); + $mform->addHelpButton('enrolenddate', 'enrolenddate', 'enrol_sslcommerz'); + + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + + $mform->addElement('hidden', 'courseid'); + $mform->setType('courseid', PARAM_INT); + + if ($CFG->version >= '2013111801') + { + if (enrol_accessing_via_instance($instance)) + { + $mform->addElement('static', 'selfwarn', get_string('instanceeditselfwarning', 'core_enrol') , get_string('instanceeditselfwarningtext', 'core_enrol')); + } + } + + $this->add_action_buttons(true, ($instance->id ? null : get_string('addinstance', 'enrol'))); + + $this->set_data($instance); + } + /** + * Sets up moodle form validation. + * @param stdClass $data + * @param stdClass $files + * @return $error error list + */ + public function validation($data, $files) + { + global $DB, $CFG; + $errors = parent::validation($data, $files); + + list($instance, $plugin, $context) = $this->_customdata; + + if (!empty($data['enrolenddate']) and $data['enrolenddate'] < $data['enrolstartdate']) + { + $errors['enrolenddate'] = get_string('enrolenddaterror', 'enrol_sslcommerz'); + } + + $cost = str_replace(get_string('decsep', 'langconfig') , '.', $data['cost']); + if (!is_numeric($cost)) + { + $errors['cost'] = get_string('costerror', 'enrol_sslcommerz'); + } + + return $errors; + } +} + diff --git a/sslcommerz/enrolment_form.php b/sslcommerz/enrolment_form.php new file mode 100644 index 0000000..f572e9a --- /dev/null +++ b/sslcommerz/enrolment_form.php @@ -0,0 +1,108 @@ +. + +/** + * Authorize.net enrolment plugin - enrolment form. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$loginid = $this->get_config('loginid'); +$transactionkey = $this->get_config('transactionkey'); +$clientkey = $this->get_config('clientkey'); +$store_id = $this->get_config('store_id'); +$store_pass = $this->get_config('store_pass'); +$enrolperiod = $this->get_config('enrolperiod'); + +$auth_modess = $this->get_config('checkproductionmode'); + +if ($auth_modess == 1) +{ + $api_env = "yes"; +} +elseif ($auth_modess == 0) +{ + $api_env = "no"; +} + +$amount = $cost; +$description = $coursefullname; + +$invoice = date('YmdHis'); +$_SESSION['sequence'] = $sequence = rand(1, 1000); +$_SESSION['timestamp'] = $timestamp = time(); + +?> + + + + + +
+

This course requires a payment for entry.

+

+

currency} {$localisedcost}"; ?>

+ +

 

+

SSLCommerz

+

 

+ + + +

+ +

+
diff --git a/sslcommerz/lang/en/enrol_sslcommerz.php b/sslcommerz/lang/en/enrol_sslcommerz.php new file mode 100644 index 0000000..493fa79 --- /dev/null +++ b/sslcommerz/lang/en/enrol_sslcommerz.php @@ -0,0 +1,60 @@ +. + +/** + * Strings for component 'enrol_sslcommerz', language 'en'. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['pluginname'] = 'SSLCOMMERZ'; +$string['pluginname_desc'] = 'The SSLCommerz module allows you to set up paid courses. If the cost for any course is zero, then students are not asked to pay for entry. There is a site-wide cost that you set here as a default for the whole site and then a course setting that you can set for each course individually. The course cost overrides the site cost.'; +// $string['loginid'] = 'SSLCommerz login ID'; +// $string['transactionkey'] = 'SSLCommerz Store ID'; +$string['store_id'] = 'SSLCommerz Store ID'; +$string['store_pass'] = 'SSLCommerz Store Password'; +$string['checkproductionmode'] = 'Check for Live mode'; +$string['mailadmins'] = 'Notify admin'; +$string['mailstudents'] = 'Notify students'; +$string['mailteachers'] = 'Notify teachers'; +$string['expiredaction'] = 'Enrolment expiration action'; +$string['expiredaction_help'] = 'Select action to carry out when user enrolment expires. Please note that some user data and settings are purged from course during course unenrolment.'; +$string['cost'] = 'Enrol cost'; +$string['costerror'] = 'The enrolment cost is not numeric'; +$string['costorkey'] = 'Please choose one of the following methods of enrolment.'; +$string['currency'] = 'Currency'; +$string['assignrole'] = 'Assign role'; +$string['defaultrole'] = 'Default role assignment'; +$string['defaultrole_desc'] = 'Select role which should be assigned to users during SSLCommerz enrolments'; +$string['enrolenddate'] = 'End date'; +$string['enrolenddate_help'] = 'If enabled, users can be enrolled until this date only.'; +$string['enrolenddaterror'] = 'Enrolment end date cannot be earlier than start date'; +$string['enrolperiod'] = 'Enrolment duration'; +$string['enrolperiod_desc'] = 'Default length of time that the enrolment is valid. If set to zero, the enrolment duration will be unlimited by default.'; +$string['enrolperiod_help'] = 'Length of time that the enrolment is valid, starting with the moment the user is enrolled. If disabled, the enrolment duration will be unlimited.'; +$string['enrolstartdate'] = 'Start date'; +$string['enrolstartdate_help'] = 'If enabled, users can be enrolled from this date onward only.'; +$string['expiredaction'] = 'Enrolment expiration action'; +$string['expiredaction_help'] = 'Select action to carry out when user enrolment expires. Please note that some user data and settings are purged from course during course unenrolment.'; +$string['sslcommerz:config'] = 'Configure SSLCommerz enrol instances'; +$string['sslcommerz:manage'] = 'Manage enrolled users'; +$string['sslcommerz:unenrol'] = 'Unenrol users from course'; +$string['sslcommerz:unenrolself'] = 'Unenrol self from the course'; +$string['status'] = 'Allow SSLCommerz enrolments'; +$string['status_desc'] = 'Allow users to use SSLCommerz to enrol into a course by default.'; +$string['unenrolselfconfirm'] = 'Do you really want to unenrol yourself from course "{$a}"?'; diff --git a/sslcommerz/lib.php b/sslcommerz/lib.php new file mode 100644 index 0000000..e965db4 --- /dev/null +++ b/sslcommerz/lib.php @@ -0,0 +1,336 @@ +. + +/** + * SSLCommerz enrolment plugin. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); +/** + * Sets up essential methods for plugin. + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrol_sslcommerz_plugin extends enrol_plugin { + /** + * Lists all currencies available for plugin. + * @return $currencies + */ + public function get_currencies() { + $codes = array('AUD', 'USD', 'CAD', 'EUR', 'GBP', 'NZD'); + $currencies = array(); + foreach ($codes as $c) { + $currencies[$c] = new lang_string($c, 'core_currencies'); + } + + return $currencies; + } + /** + * Returns optional enrolment information icons. + * + * This is used in course list for quick overview of enrolment options. + * + * We are not using single instance parameter because sometimes + * we might want to prevent icon repetition when multiple instances + * of one type exist. One instance may also produce several icons. + * + * @param array $instances all enrol instances of this type in one course + * @return array of pix_icon + */ + public function get_info_icons(array $instances) { + return array(new pix_icon('icon', get_string('pluginname', 'enrol_sslcommerz'), 'enrol_sslcommerz')); + } + /** + * Lists all protected user roles. + * @return bool(true or false) + */ + public function roles_protected() { + // Users with role assign cap may tweak the roles later. + return false; + } + /** + * Defines if user can be unenrolled. + * @param stdClass $instance of the plugin + * @return bool(true or false) + */ + public function allow_unenrol(stdClass $instance) { + // Users with unenrol cap may unenrol other users manually - requires enrol/sslcommerz:unenrol. + return true; + } + /** + * Defines if user can be managed from admin. + * @param stdClass $instance of the plugin + * @return bool(true or false) + */ + public function allow_manage(stdClass $instance) { + // Users with manage cap may tweak period and status - requires enrol/sslcommerz:manage. + return true; + } + /** + * Defines if 'enrol me' link will be shown on course page. + * @param stdClass $instance of the plugin + * @return bool(true or false) + */ + public function show_enrolme_link(stdClass $instance) { + return ($instance->status == ENROL_INSTANCE_ENABLED); + } + /** + * Adds navigation links into course admin block. + * + * By defaults looks for manage links only. + * + * @param navigation_node $instancesnode + * @param stdClass $instance + * @return void + */ + public function add_course_navigation($instancesnode, stdClass $instance) { + if ($instance->enrol !== 'sslcommerz') { + throw new coding_exception('Invalid enrol instance type!'); + } + + $context = context_course::instance($instance->courseid); + if (has_capability('enrol/sslcommerz:config', $context)) { + $managelink = new moodle_url('/enrol/sslcommerz/edit.php', + array('courseid' => $instance->courseid, 'id' => $instance->id)); + $instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING); + } + } + + /** + * Returns edit icons for the page with list of instances + * @param stdClass $instance + * @return array + */ + public function get_action_icons(stdClass $instance) { + global $OUTPUT; + + if ($instance->enrol !== 'sslcommerz') { + throw new coding_exception('invalid enrol instance!'); + } + $context = context_course::instance($instance->courseid); + + $icons = array(); + + if (has_capability('enrol/sslcommerz:config', $context)) { + $editlink = new moodle_url("/enrol/sslcommerz/edit.php", + array('courseid' => $instance->courseid, 'id' => $instance->id)); + $icons[] = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit'), 'core', + array('class' => 'iconsmall'))); + } + + return $icons; + } + + /** + * Returns link to page which may be used to add new instance of enrolment plugin in course. + * @param int $courseid + * @return moodle_url page url + */ + public function get_newinstance_link($courseid) { + $context = context_course::instance($courseid, MUST_EXIST); + + if (!has_capability('moodle/course:enrolconfig', $context) or !has_capability('enrol/sslcommerz:config', $context)) { + return null; + } + + // Multiple instances supported - different cost for different roles. + return new moodle_url('/enrol/sslcommerz/edit.php', array('courseid' => $courseid)); + } + /** + * Creates course enrol form, checks if form submitted + * and enrols user if necessary. It can also redirect. + * + * @param stdClass $instance + * @return string html text, usually a form in a text box + */ + public function enrol_page_hook(stdClass $instance) { + global $CFG, $USER, $OUTPUT, $PAGE, $DB; + ob_start(); + + if ($DB->record_exists('user_enrolments', array('userid' => $USER->id, 'enrolid' => $instance->id))) { + return ob_get_clean(); + } + + if ($instance->enrolstartdate != 0 && $instance->enrolstartdate > time()) { + return ob_get_clean(); + } + + if ($instance->enrolenddate != 0 && $instance->enrolenddate < time()) { + return ob_get_clean(); + } + + $course = $DB->get_record('course', array('id' => $instance->courseid)); + $context = context_course::instance($course->id); + + $shortname = format_string($course->shortname, true, array('context' => $context)); + $strloginto = get_string("loginto", "", $shortname); + $strcourses = get_string("courses"); + + // Pass $view=true to filter hidden caps if the user cannot see them. + if ($users = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC', + '', '', '', '', false, true)) { + $users = sort_by_roleassignment_authority($users, $context); + $teacher = array_shift($users); + } else { + $teacher = false; + } + + if ( (float) $instance->cost <= 0 ) { + $cost = (float) $this->get_config('cost'); + } else { + $cost = (float) $instance->cost; + } + + if (abs($cost) < 0.01) { + // No cost, other enrolment methods (instances) should be used. + echo '

'.get_string('nocost', 'enrol_sslcommerz').'

'; + } else { + + // Calculate localised and "." cost, make sure we send SSLCommerz the same value, + // please note SSLCommerz expects amount with 2 decimal places and "." separator. + $localisedcost = format_float($cost, 2, true); + $cost = format_float($cost, 2, false); + + if (isguestuser()) { + // Force login only for guest user, not real users with guest role. + if (empty($CFG->loginhttps)) { + $wwwroot = $CFG->wwwroot; + } else { + // This actually is not so secure ;-), 'cause we're + // in unencrypted connection... + $wwwroot = str_replace("http://", "https://", $CFG->wwwroot); + } + echo '

'.get_string('paymentrequired').'

'; + echo '

'.get_string('cost').": $instance->currency $localisedcost".'

'; + echo '

'.get_string('loginsite').'

'; + echo '
'; + } else { + // Sanitise some fields before building the payment form. + $coursefullname = format_string($course->fullname, true, array('context' => $context)); + $courseshortname = $shortname; + $userfullname = fullname($USER); + $userfirstname = $USER->firstname; + $userlastname = $USER->lastname; + $useraddress = $USER->address; + $usercity = $USER->city; + $instancename = $this->get_instance_name($instance); + + include($CFG->dirroot.'/enrol/sslcommerz/enrolment_form.php'); + } + + } + + return $OUTPUT->box(ob_get_clean()); + } + /** + * Restore instance and map settings. + * + * @param restore_enrolments_structure_step $step + * @param stdClass $data + * @param stdClass $course + * @param int $oldid + */ + public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) { + global $DB; + if ($step->get_task()->get_target() == backup::TARGET_NEW_COURSE) { + $merge = false; + } else { + $merge = array( + 'courseid' => $data->courseid, + 'enrol' => $this->get_name(), + 'roleid' => $data->roleid, + 'cost' => $data->cost, + 'currency' => $data->currency, + ); + } + if ($merge and $instances = $DB->get_records('enrol', $merge, 'id')) { + $instance = reset($instances); + $instanceid = $instance->id; + } else { + $instanceid = $this->add_instance($course, (array)$data); + } + $step->set_mapping('enrol', $oldid, $instanceid); + } + /** + * Restore user enrolment. + * + * @param restore_enrolments_structure_step $step + * @param stdClass $data + * @param stdClass $instance + * @param int $userid + * @param int $oldinstancestatus + */ + public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) { + $this->enrol_user($instance, $userid, null, $data->timestart, $data->timeend, $data->status); + } + /** + * Gets an array of the user enrolment actions + * + * @param course_enrolment_manager $manager + * @param stdClass $ue A user enrolment object + * @return array An array of user_enrolment_actions + */ + public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) { + $actions = array(); + $context = $manager->get_context(); + $instance = $ue->enrolmentinstance; + $params = $manager->get_moodlepage()->url->params(); + $params['ue'] = $ue->id; + if ($this->allow_unenrol($instance) && has_capability("enrol/sslcommerz:unenrol", $context)) { + $url = new moodle_url('/enrol/unenroluser.php', $params); + $actions[] = new user_enrolment_action(new pix_icon('t/delete', ''), get_string('unenrol', 'enrol'), $url, + array('class' => 'unenrollink', 'rel' => $ue->id)); + } + if ($this->allow_manage($instance) && has_capability("enrol/sslcommerz:manage", $context)) { + $url = new moodle_url('/enrol/editenrolment.php', $params); + $actions[] = new user_enrolment_action(new pix_icon('t/edit', ''), get_string('edit'), $url, + array('class' => 'editenrollink', 'rel' => $ue->id)); + } + return $actions; + } + /** + * Set up cron for the plugin (if any). + * + */ + public function cron() { + $trace = new text_progress_trace(); + $this->process_expirations($trace); + } + /** + * Is it possible to delete enrol instance via standard UI? + * + * @param stdClass $instance + * @return bool + */ + public function can_delete_instance($instance) { + $context = context_course::instance($instance->courseid); + return has_capability('enrol/sslcommerz:config', $context); + } + /** + * Is it possible to hide/show enrol instance via standard UI? + * + * @param stdClass $instance + * @return bool + */ + public function can_hide_show_instance($instance) { + $context = context_course::instance($instance->courseid); + return has_capability('enrol/sslcommerz:config', $context); + } +} diff --git a/sslcommerz/pay_process.php b/sslcommerz/pay_process.php new file mode 100644 index 0000000..99e040d --- /dev/null +++ b/sslcommerz/pay_process.php @@ -0,0 +1,112 @@ +. + +/** + * Listens for Instant Payment Notification from Authorize.net + * + * This script waits for Payment notification from Authorize.net, + * then it sets up the enrolment for that user. + * + * @package enrol_sslcommerz + * @copyright 2015 Dualcube, Moumita Ray, Parthajeet Chakraborty + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// Disable moodle specific debug messages and any errors in output, +// comment out when debugging or better look into error log! +define('NO_DEBUG_DISPLAY', true); + +require ("../../config.php"); +require_once ("lib.php"); +require_once ("api/Sslcommerz.php"); +//require_once($CFG->libdir.'/eventslib.php'); +require_once ($CFG->libdir . '/enrollib.php'); +require_once ($CFG->libdir . '/filelib.php'); +// echo "
"; print_r($_POST); die;
+//require_once($CFG->dirroot . '/admin/environment.php');
+use Sslcommerz\API\Sslcommerz_API;
+
+require_login();
+
+global $DB, $CFG;
+
+if (empty($_POST) or !empty($_GET))
+{
+    print_error("Sorry, you can not use the script that way.");
+    die;
+}
+$PAGE->set_pagelayout('admin');
+$PAGE->set_url($CFG->wwwroot . '/enrol/sslcommerz/pay_process.php');
+echo $OUTPUT->header();
+echo $OUTPUT->heading("Your Payment is in Process....");
+echo $OUTPUT->heading("Don't Reload or Leave This Page. This Page Will Automatically Redirect You To SSLCommerz Payment Page. ");
+echo $OUTPUT->footer();
+
+$store_id = $_POST['store_id'];
+$store_password = $_POST['store_password'];
+$is_live = $_POST['is_live'];
+$enrolperiod = $_POST['enrolperiod'];
+
+$trans_id = $_POST['x_invoice_num'];
+
+$enrolsslcommerz = new stdClass();
+$postdata = array_map('utf8_encode', $_POST);
+$existing_array = array(
+    'transId' => $trans_id
+);
+$postdata = array_merge($postdata, $existing_array);
+
+$enrolsslcommerz->auth_json = json_encode($postdata);
+$enrolsslcommerz->trans_id = $trans_id;
+$enrolsslcommerz->timeupdated = time();
+
+$ret1 = $DB->insert_record("enrol_sslcommerz", $enrolsslcommerz, true);
+
+$post_data = array();
+
+$post_data['total_amount'] = $_POST['amount'];
+$post_data['currency'] = $_POST['x_currency_code'];
+$post_data['tran_id'] = $trans_id;
+$post_data['success_url'] = $CFG->wwwroot . '/enrol/sslcommerz/validation.php?id=' . $ret1;
+$post_data['fail_url'] = $CFG->wwwroot . '/enrol/sslcommerz/validation.php?id=' . $ret1;
+$post_data['cancel_url'] = $CFG->wwwroot . '/enrol/sslcommerz/validation.php?id=' . $ret1;
+
+$post_data['shipping_method'] = 'NO';
+$post_data['num_of_item'] = '1';
+$post_data['product_name'] = $_POST['x_description'];
+$post_data['product_profile'] = 'general';
+$post_data['product_category'] = 'course';
+
+# CUSTOMER INFORMATION
+$post_data['cus_name'] = "Test Customer";
+$post_data['cus_email'] = "test@test.com";
+$post_data['cus_add1'] = "Dhaka";
+$post_data['cus_add2'] = "Dhaka";
+$post_data['cus_city'] = "Dhaka";
+$post_data['cus_state'] = "Dhaka";
+$post_data['cus_postcode'] = "1000";
+$post_data['cus_country'] = "Bangladesh";
+$post_data['cus_phone'] = "01711111111";
+$post_data['cus_fax'] = "01711111111";
+
+# OPTIONAL PARAMETERS
+$post_data['value_a'] = $_POST['x_cust_id'];
+$post_data['value_b'] = $_POST['x_fp_sequence'];
+$post_data['value_c'] = $enrolperiod;
+
+Sslcommerz_API::requestToSSL($store_id, $store_password, $is_live, $post_data);
+exit;
+
diff --git a/sslcommerz/pix/sslcommerz.png b/sslcommerz/pix/sslcommerz.png
new file mode 100644
index 0000000000000000000000000000000000000000..34bff62542197c1d1404341165db8d622dc08693
GIT binary patch
literal 19229
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
j2>OUn|DWwC|0}=%I+q}.
+
+/**
+ * Authorize.net utility script
+ *
+ * @package    enrol_sslcommerz
+ * @copyright  2015 Dualcube, Moumita Ray, Parthajeet Chakraborty
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require ("../../config.php");
+require_once ("$CFG->dirroot/enrol/sslcommerz/lib.php");
+
+$id = required_param('id', PARAM_INT);
+
+if (!$course = $DB->get_record("course", array(
+    "id" => $id
+)))
+{
+    redirect($CFG->wwwroot);
+}
+
+$context = context_course::instance($course->id, MUST_EXIST);
+$PAGE->set_context($context);
+
+require_login();
+
+if (!empty($SESSION->wantsurl))
+{
+    $destination = $SESSION->wantsurl;
+    unset($SESSION->wantsurl);
+}
+else
+{
+    $destination = "$CFG->wwwroot/course/view.php?id=$course->id";
+}
+
+$fullname = format_string($course->fullname, true, array(
+    'context' => $context
+));
+
+if (is_enrolled($context, null, '', true))
+{
+    redirect($destination, get_string('paymentthanks', '', $fullname));
+}
+else
+{
+    $PAGE->set_url($destination);
+    echo $OUTPUT->header();
+    $a = new stdClass();
+    $a->teacher = get_string('defaultcourseteacher');
+    $a->fullname = $fullname;
+    notice(get_string('paymentsorry', '', $a) , $destination);
+}
+
diff --git a/sslcommerz/settings.php b/sslcommerz/settings.php
new file mode 100644
index 0000000..2c7f64f
--- /dev/null
+++ b/sslcommerz/settings.php
@@ -0,0 +1,79 @@
+.
+
+/**
+ * SSLCommerz enrolments plugin settings and presets.
+ *
+ * @package    enrol_sslcommerz
+ * @copyright  2015 Dualcube, Moumita Ray, Parthajeet Chakraborty
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($ADMIN->fulltree)
+{
+
+    // Settings.
+    $settings->add(new admin_setting_heading('enrol_sslcommerz_settings', '', get_string('pluginname_desc', 'enrol_sslcommerz')));
+    // $settings->add(new admin_setting_configtext('enrol_sslcommerz/loginid',
+    //                get_string('loginid', 'enrol_sslcommerz'),
+    //                'Copy API Login ID from merchant account & paste here', '', PARAM_RAW));
+    // $settings->add(new admin_setting_configtext('enrol_sslcommerz/transactionkey',
+    //                get_string('transactionkey', 'enrol_sslcommerz'),
+    //                'Copy API Transaction Key from merchant account & paste here', '', PARAM_RAW));
+    $settings->add(new admin_setting_configtext('enrol_sslcommerz/store_id', get_string('store_id', 'enrol_sslcommerz') , 'Copy store_id from merchant account & paste here', '', PARAM_RAW));
+
+    $settings->add(new admin_setting_configtext('enrol_sslcommerz/store_pass', get_string('store_pass', 'enrol_sslcommerz') , 'Copy Store Password & paste here', '', PARAM_RAW));
+
+    $settings->add(new admin_setting_configcheckbox('enrol_sslcommerz/checkproductionmode', get_string('checkproductionmode', 'enrol_sslcommerz') , '', 0));
+    $settings->add(new admin_setting_configcheckbox('enrol_sslcommerz/mailstudents', get_string('mailstudents', 'enrol_sslcommerz') , '', 0));
+    $settings->add(new admin_setting_configcheckbox('enrol_sslcommerz/mailteachers', get_string('mailteachers', 'enrol_sslcommerz') , '', 0));
+    $settings->add(new admin_setting_configcheckbox('enrol_sslcommerz/mailadmins', get_string('mailadmins', 'enrol_sslcommerz') , '', 0));
+
+    // Note: let's reuse the ext sync constants and strings here, internally it is very similar,
+    //       it describes what should happen when users are not supposed to be enrolled any more.
+    $options = array(
+        ENROL_EXT_REMOVED_KEEP => get_string('extremovedkeep', 'enrol') ,
+        ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol') ,
+        ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol') ,
+    );
+    $settings->add(new admin_setting_configselect('enrol_sslcommerz/expiredaction', get_string('expiredaction', 'enrol_sslcommerz') , get_string('expiredaction_help', 'enrol_sslcommerz') , ENROL_EXT_REMOVED_SUSPENDNOROLES, $options));
+
+    // Enrol instance defaults.
+    $settings->add(new admin_setting_heading('enrol_sslcommerz_defaults', get_string('enrolinstancedefaults', 'admin') , get_string('enrolinstancedefaults_desc', 'admin')));
+
+    $options = array(
+        ENROL_INSTANCE_ENABLED => get_string('yes') ,
+        ENROL_INSTANCE_DISABLED => get_string('no')
+    );
+    $settings->add(new admin_setting_configselect('enrol_sslcommerz/status', get_string('status', 'enrol_sslcommerz') , get_string('status_desc', 'enrol_sslcommerz') , ENROL_INSTANCE_DISABLED, $options));
+
+    $settings->add(new admin_setting_configtext('enrol_sslcommerz/cost', get_string('cost', 'enrol_sslcommerz') , '', 0, PARAM_FLOAT, 4));
+
+    $currencies = enrol_get_plugin('sslcommerz')->get_currencies();
+    $settings->add(new admin_setting_configselect('enrol_sslcommerz/currency', get_string('currency', 'enrol_sslcommerz') , '', 'USD', $currencies));
+    if (!during_initial_install())
+    {
+        $options = get_default_enrol_roles(context_system::instance());
+        $student = get_archetype_roles('student');
+        $student = reset($student);
+        $settings->add(new admin_setting_configselect('enrol_sslcommerz/roleid', get_string('defaultrole', 'enrol_sslcommerz') , get_string('defaultrole_desc', 'enrol_sslcommerz') , $student->id, $options));
+    }
+
+    $settings->add(new admin_setting_configduration('enrol_sslcommerz/enrolperiod', get_string('enrolperiod', 'enrol_sslcommerz') , get_string('enrolperiod_desc', 'enrol_sslcommerz') , 0));
+}
+
diff --git a/sslcommerz/unenrolself.php b/sslcommerz/unenrolself.php
new file mode 100644
index 0000000..970ac7e
--- /dev/null
+++ b/sslcommerz/unenrolself.php
@@ -0,0 +1,62 @@
+.
+
+/**
+ * Authorize.net enrolment plugin - support for user self unenrolment.
+ *
+ * @package    enrol_sslcommerz
+ * @copyright  2015 Dualcube, Moumita Ray, Parthajeet Chakraborty
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require('../../config.php');
+
+$enrolid = required_param('enrolid', PARAM_INT);
+$confirm = optional_param('confirm', 0, PARAM_BOOL);
+
+$instance = $DB->get_record('enrol', array('id' => $enrolid, 'enrol' => 'sslcommerz'), '*', MUST_EXIST);
+$course = $DB->get_record('course', array('id' => $instance->courseid), '*', MUST_EXIST);
+$context = context_course::instance($course->id, MUST_EXIST);
+
+require_login();
+if (!is_enrolled($context)) {
+    redirect(new moodle_url('/'));
+}
+require_login($course);
+
+$plugin = enrol_get_plugin('sslcommerz');
+
+// Security defined inside following function.
+if (!$plugin->get_unenrolself_link($instance)) {
+    redirect(new moodle_url('/course/view.php', array('id' => $course->id)));
+}
+
+$PAGE->set_url('/enrol/sslcommerz/unenrolself.php', array('enrolid' => $instance->id));
+$PAGE->set_title($plugin->get_instance_name($instance));
+
+if ($confirm and confirm_sesskey()) {
+    $plugin->unenrol_user($instance, $USER->id);
+
+    redirect(new moodle_url('/index.php'));
+}
+
+echo $OUTPUT->header();
+$yesurl = new moodle_url($PAGE->url, array('confirm' => 1, 'sesskey' => sesskey()));
+$nourl = new moodle_url('/course/view.php', array('id' => $course->id));
+$message = get_string('unenrolselfconfirm', 'enrol_sslcommerz', format_string($course->fullname));
+echo $OUTPUT->confirm($message, $yesurl, $nourl);
+echo $OUTPUT->footer();
diff --git a/sslcommerz/validation.php b/sslcommerz/validation.php
new file mode 100644
index 0000000..d1d73bc
--- /dev/null
+++ b/sslcommerz/validation.php
@@ -0,0 +1,303 @@
+.
+
+/**
+ * Listens for Instant Payment Notification from Authorize.net
+ *
+ * This script waits for Payment notification from Authorize.net,
+ * then it sets up the enrolment for that user.
+ *
+ * @package    enrol_sslcommerz
+ * @copyright  2015 Dualcube, Moumita Ray, Parthajeet Chakraborty
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// Disable moodle specific debug messages and any errors in output,
+// comment out when debugging or better look into error log!
+//define('NO_DEBUG_DISPLAY', true);
+require ("../../config.php");
+require_once ("lib.php");
+//require_once($CFG->libdir.'/eventslib.php');
+require_once ($CFG->libdir . '/enrollib.php');
+require_once ($CFG->libdir . '/filelib.php');
+require_once ("api/Sslcommerz.php");
+use Sslcommerz\API\Sslcommerz_API;
+
+global $DB, $CFG;
+
+$id = required_param('id', PARAM_INT);
+
+$response = $DB->get_record('enrol_sslcommerz', array(
+    'id' => $id
+));
+$responsearray = json_decode($response->auth_json, true);
+$store_id = $responsearray['store_id'];
+$store_pass = $responsearray['store_password'];
+$auth_modess = $responsearray['is_live'];
+
+// Check if the response is from authorize.net.
+
+
+$loginid = get_config('enrol_sslcommerz', 'loginid');
+$transactionid = $responsearray['transId'];
+$amount = $responsearray['amount'];
+
+//$generatemd5hash = strtoupper(md5($merchantmd5hash.$loginid.$transactionid.$amount));
+$arraycourseinstance = explode('-', $responsearray['x_cust_id']);
+
+// Required for message_send.
+$PAGE->set_context(context_system::instance());
+
+/*
+if ($generatemd5hash != $responsearray['x_MD5_Hash']) {
+    print_error("We can't validate your transaction. Please try again!!"); die;
+}
+*/
+
+$arraycourseinstance = explode('-', $responsearray['x_cust_id']);
+if (empty($arraycourseinstance) || count($arraycourseinstance) < 4)
+{
+    print_error("Received an invalid payment notification!! (Fake payment?)");
+    die;
+}
+
+if (!$user = $DB->get_record("user", array(
+    "id" => $arraycourseinstance[1]
+)))
+{
+    print_error("Not a valid user id");
+    die;
+}
+
+if (!$course = $DB->get_record("course", array(
+    "id" => $arraycourseinstance[0]
+)))
+{
+    print_error("Not a valid course id");
+    die;
+}
+
+if (!$context = context_course::instance($arraycourseinstance[0], IGNORE_MISSING))
+{
+    print_error("Not a valid context id");
+    die;
+}
+
+if (!$plugininstance = $DB->get_record("enrol", array(
+    "id" => $arraycourseinstance[2],
+    "status" => 0
+)))
+{
+    print_error("Not a valid instance id");
+    die;
+}
+
+$enrolsslcommerz = $userenrolments = $roleassignments = new stdClass();
+
+$enrolsslcommerz->id = $id;
+$enrolsslcommerz->item_name = $responsearray['x_description'];
+$enrolsslcommerz->courseid = $arraycourseinstance[0];
+$enrolsslcommerz->userid = $arraycourseinstance[1];
+$enrolsslcommerz->instanceid = $arraycourseinstance[2];
+$enrolsslcommerz->amount = $responsearray['amount'];
+// $enrolsslcommerz->tax = $responsearray['x_tax'];
+// $enrolsslcommerz->duty = $responsearray['x_duty'];
+
+
+if (isset($_POST['status']) && $_POST['status'] == 'VALID' && (isset($_POST['val_id']) && $_POST['val_id'] != ""))
+{
+    $responseCode = 1;
+    $validation = Sslcommerz_API::orderValidation($store_id, $store_pass, $auth_modess, $_POST['val_id']);
+    $enrolsslcommerz->payment_status = 'Approved';
+
+    $PAGE->set_context($context);
+    $coursecontext = context_course::instance($course->id, IGNORE_MISSING);
+
+    if ($users = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC', '', '', '', '', false, true))
+    {
+        $users = sort_by_roleassignment_authority($users, $context);
+        $teacher = array_shift($users);
+    }
+    else
+    {
+        $teacher = false;
+    }
+
+    $plugin = enrol_get_plugin('sslcommerz');
+
+    $mailstudents = $plugin->get_config('mailstudents');
+    $mailteachers = $plugin->get_config('mailteachers');
+    $mailadmins = $plugin->get_config('mailadmins');
+    $shortname = format_string($course->shortname, true, array(
+        'context' => $context
+    ));
+
+    if (!empty($mailstudents))
+    {
+        $a = new stdClass();
+        $a->coursename = format_string($course->fullname, true, array(
+            'context' => $coursecontext
+        ));
+        $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id";
+
+        if ($CFG->version >= 2015051100)
+        {
+            $eventdata = new \core\message\message();
+        }
+        else
+        {
+            $eventdata = new stdClass();
+        }
+        $eventdata->component = 'enrol_sslcommerz';
+        $eventdata->name = 'sslcommerz_enrolment';
+        //$eventdata->courseid          = $course->id;
+        $eventdata->userfrom = empty($teacher) ? core_user::get_noreply_user() : $teacher;
+        $eventdata->userto = $user;
+        $eventdata->subject = get_string("enrolmentnew", 'enrol', $shortname);
+        $eventdata->fullmessage = get_string('welcometocoursetext', '', $a);
+        $eventdata->fullmessageformat = FORMAT_PLAIN;
+        $eventdata->fullmessagehtml = '';
+        $eventdata->smallmessage = '';
+        message_send($eventdata);
+
+    }
+
+    if (!empty($mailteachers) && !empty($teacher))
+    {
+        $a->course = format_string($course->fullname, true, array(
+            'context' => $coursecontext
+        ));
+        $a->user = fullname($user);
+
+        if ($CFG->version >= 2015051100)
+        {
+            $eventdata = new \core\message\message();
+        }
+        else
+        {
+            $eventdata = new stdClass();
+        }
+        $eventdata->component = 'enrol_sslcommerz';
+        $eventdata->name = 'sslcommerz_enrolment';
+        //$eventdata->courseid          = $course->id;
+        $eventdata->userfrom = $user;
+        $eventdata->userto = $teacher;
+        $eventdata->subject = get_string("enrolmentnew", 'enrol', $shortname);
+        $eventdata->fullmessage = get_string('enrolmentnewuser', 'enrol', $a);
+        $eventdata->fullmessageformat = FORMAT_PLAIN;
+        $eventdata->fullmessagehtml = '';
+        $eventdata->smallmessage = '';
+        message_send($eventdata);
+    }
+
+    if (!empty($mailadmins))
+    {
+        $a->course = format_string($course->fullname, true, array(
+            'context' => $coursecontext
+        ));
+        $a->user = fullname($user);
+        $admins = get_admins();
+        foreach ($admins as $admin)
+        {
+
+            if ($CFG->version >= 2015051100)
+            {
+                $eventdata = new \core\message\message();
+            }
+            else
+            {
+                $eventdata = new stdClass();
+            }
+            $eventdata->component = 'enrol_sslcommerz';
+            $eventdata->name = 'sslcommerz_enrolment';
+            //$eventdata->courseid          = $course->id;
+            $eventdata->userfrom = $user;
+            $eventdata->userto = $admin;
+            $eventdata->subject = get_string("enrolmentnew", 'enrol', $shortname);
+            $eventdata->fullmessage = get_string('enrolmentnewuser', 'enrol', $a);
+            $eventdata->fullmessageformat = FORMAT_PLAIN;
+            $eventdata->fullmessagehtml = '';
+            $eventdata->smallmessage = '';
+            message_send($eventdata);
+        }
+    }
+
+    $enrolsslcommerz->response_code = $responseCode;
+    // $enrolsslcommerz->response_reason_code = $responsearray['x_response_reason_code'];
+    // $enrolsslcommerz->response_reason_text = $responsearray['x_response_reason_text'];
+    $enrolsslcommerz->auth_code = $responseCode;
+    $enrolsslcommerz->trans_id = $validation['tran_id'];
+    // $enrolsslcommerz->method = $responsearray['x_method'];
+    $enrolsslcommerz->account_number = isset($validation['card_no']) ? $validation['card_no'] : '';
+    $enrolsslcommerz->card_type = isset($validation['card_brand']) ? $validation['card_brand'] : '';
+    $enrolsslcommerz->first_name = isset($responsearray['x_first_name']) ? $responsearray['x_first_name'] : '';
+    $enrolsslcommerz->last_name = isset($responsearray['x_last_name']) ? $responsearray['x_last_name'] : '';
+    $enrolsslcommerz->company = isset($responsearray['x_company']) ? $responsearray['x_company'] : '';
+    $enrolsslcommerz->phone = isset($responsearray['x_phone']) ? $responsearray['x_phone'] : '';
+    $enrolsslcommerz->fax = isset($responsearray['x_fax']) ? $responsearray['x_fax'] : '';
+    $enrolsslcommerz->address = isset($responsearray['x_address']) ? $responsearray['x_address'] : '';
+    $enrolsslcommerz->city = isset($responsearray['x_city']) ? $responsearray['x_city'] : '';
+    $enrolsslcommerz->state = isset($responsearray['x_state']) ? $responsearray['x_state'] : '';
+    $enrolsslcommerz->zip = isset($responsearray['x_zip']) ? $responsearray['x_zip'] : '';
+    $enrolsslcommerz->country = isset($responsearray['x_country']) ? $responsearray['x_country'] : '';
+    $enrolsslcommerz->email = isset($responsearray['x_email']) ? $responsearray['x_email'] : '';
+    $enrolsslcommerz->invoice_num = $responsearray['x_invoice_num'];
+    // $enrolsslcommerz->test_request = ($responsearray['x_test_request'] == 'true') ? '1' : '0';
+    $enrolsslcommerz->timeupdated = time();
+    /* Inserting value to enrol_sslcommerz table */
+    $ret1 = $DB->update_record("enrol_sslcommerz", $enrolsslcommerz, false);
+
+    if ($plugininstance->enrolperiod)
+    {
+        $timestart = time();
+        $timeend = $timestart + $plugininstance->enrolperiod;
+    }
+    else
+    {
+        $timestart = 0;
+        $timeend = 0;
+    }
+    $plugin = enrol_get_plugin('sslcommerz');
+
+    /* Enrol User */
+    $plugin->enrol_user($plugininstance, $user->id, $plugininstance->roleid, $timestart, $timeend);
+
+    echo '';
+    die;
+
+}
+else if (isset($_POST['status']) && $_POST['status'] == 'FAILED')
+{
+    $responseCode = 2;
+    $enrolsslcommerz->payment_status = 'Error';
+    print_error("Sorry! Transaction Failed.");
+    die;
+}
+else if (isset($_POST['status']) && $_POST['status'] == 'CANCELLED')
+{
+    $responseCode = 3;
+    $enrolsslcommerz->payment_status = 'Declined';
+    print_error("Transaction Cancelled By User!");
+    die;
+}
+else
+{
+    print_error("Invalid request!");
+    die;
+}
+
diff --git a/sslcommerz/version.php b/sslcommerz/version.php
new file mode 100644
index 0000000..eefd719
--- /dev/null
+++ b/sslcommerz/version.php
@@ -0,0 +1,33 @@
+.
+
+/**
+ * SSLCommerz enrolment plugin version specification.
+ *
+ * @package    enrol_sslcommerz
+ * @copyright  2015 Dualcube, Moumita Ray, Parthajeet Chakraborty
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version = 2020071200;
+$plugin->requires = 2013051401;
+$plugin->component = 'enrol_sslcommerz';
+$plugin->maturity = MATURITY_STABLE;
+$plugin->release = 4;
+$plugin->cron = 60;
+