Professional Documents
Culture Documents
Project Report
Project Report
BATCH – A1
DECLARATION BY THE CANDIDATE
I hereby declare that minor project report entitled “MEENA’S KITCHEN - AN E-COMMERCE
WEBSITE” submitted by me to JECRC University. In partial fulfilment of the requirement for
the award of the degree of MASTER OF COMPUTER APPLICATION is a record of bona fide
project work carried out by me under the guidance of Mr. Harshit Sharma. I further declare
that the work reported in this project has not been submitted and will not be submitted,
either in part or in full, for the award of any other degree in this institute or any other institute
or university.
Submitted To:
State: Rajasthan
ABSTRACT
Meena’s Kitchen is an E-commerce website which deals with sales and purchase of
homemade snacks and beverages. The customer can place orders and make purchases of
multiple goods with the help of online payment system. The orders then get delivered to the
provided address anywhere within India.
This project is built on WordPress with is CMS – (Content Management System). A content
management system or CMS is a software that is used to build websites and create content
to be published on the internet. Typically, CMS allows you to create a website without writing
any code. It keeps the track of every piece of content on our website.
1. INTRODUCTION
This section gives a scope description and overview of everything included in this Project
Report. Also, the purpose for this document is described and system overview along with
goal and vision are listed.
1.1. Purpose
This is an e-commerce website which deals with sales and purchase of homemade
snacks and beverages. Electronic Commerce is process of doing business through
computer networks. The customer can place orders and make purchases of multiple
goods with the help of online payment system. Unlike traditional commerce that is
carried out physically with effort of a person to go & get products, ecommerce has
made it easier for human to reduce physical work and to save time. The main
advantage of e-commerce over traditional commerce is the user can browse online
shops, compare prices and order merchandise sitting at home on their PC.
The main purpose of this website is to deliver the good quality snacks at your doorstep
anywhere in India. The main advantage of e-commerce over traditional commerce is
the user can browse online shops, compare prices and order merchandise sitting at
home on their PC. The orders then get delivered to the provided address anywhere
within India.
SYSTEM DESIGN
WordPress offers a bench of free applications coded in PHP, to manage MySQL databases.
The queries are run, optimized and repaired by the user through creating, altering, dropping,
deleting, importing and exporting tables (columns, relations, indexes, users). The latter is
called PhpMyAdmin software that is integrated as well in the cPanel so that the user can
execute any SQL statement using the interface. This online database supports LTR (left to
right) and RTL (right to left) languages within 72 translations available.
E-R DIAGRAM
reference
wp commentmeta wp comments
meta id
post id
meta ke
meta value
wp postmeta
count
comment comment record
post name
reference
user pass
post date
wp posts
has a
user status
reference
term id
name
umeta id
slug
wp terms wp usermeta user id
term group
meta ke
has a
has a
term ta onom id meta value
descrip on
wp term ta onom
count
term id
ta onom
parent has a
ob ect id
term order
DATABASE/TABLES STRUCTURE/SCHEMA
Database of Customers
List of Tables in the Database
Fitting with the association’s needs, the most suitable tool to be used is a Content
Management System (CMS). The latter is a system that will facilitate the management of the
virtual platform in terms of creation, modification and elimination of content, since it
leverages web-based publishing as well as controlling format and revision. It is an appropriate
tool for allowing users to change Web content, which includes the feature adjustment of legal
electronic documents formatted into HTML or PDF format for the virtual platform.
Additionally, the board members of the association can track the posted files
through the indexing of data using keywords and retrievals. Based on design and
implementation, the choice of CMS technology was due to the geographical dispersion of
Mimouna Foundation members in Morocco, so the electronic data forms can be more
accessible throughout this virtual platform. In fact, the selection of the most appropriate tool
that will be adapted in designing this virtual platform, so that it would fit the association’
requirements, was a difficult choice. The main aim was to reduce time, improve system
quality, make an operational design, and able any user (from any field of proficiency) to use
it efficiently. Therefore, a content management system was a good choice, one that satisfies
the needed software criteria for this kind of web management system. CMS and other
blogging platforms simplify publishing and sharing information in a cost-effective way via a
group of applications and tools that facilitate the organization of electronic data through
creating, editing, reviewing, and publishing, in addition, to many web-provided features and
options to index and search documents using different engines.
System Architecture
1. Hosting Server
The server, where the website of Meena’s Kitchen is hosted, is managed by Hostinger.
The Hostinger is a web-based system that let the designer control services as well as
configure open-source applications. This is an online interface that allowed the
management of the server (operating system of the hosting machine), and through it the
creation of virtual hosts can be done which contain WordPress and the PhpMyAdmin
online database.
2. Mailing System
The mailing s stem used in this virtual platform is ‘Round Cube’, which is an open-source
free solution coded mainly in PHP. It offers a friendly user interface that allows the
creation of email to be hosted in an IMAP (Internet Message Access Protocol) web server
that manages email messages and stores them. Accordingly, Mimouna Foundation
members will have their own mailing system to communicate within their personal
domain part ‘@meenakitchen.in. For instance: ‘contact@meenakitchen.in’ which will be
applied to all members. An administrator will be enabled to add and delete users’ emails
accounts based on membership status.
3. Database Management System: PhpMyAdmin
WordPress offers a bench of free applications coded in PHP, to manage MySQL databases.
The queries are run, optimized and repaired by the user through creating, altering,
dropping, deleting, importing and exporting tables (columns, relations, indexes, users).
The latter is called PhpMyAdmin software that is integrated as well in the cPanel so that
the user can execute any SQL statement using the interface. This online database supports
LTR (left to right) and RTL (right to left) languages within 72 translations available.
4. Virtual Platform
4.3.1. Administrator
Administrators have access to the whole virtual platform by being enabled to edit
events, tasks, finance, pages, profiles, documents and features are enabled for
administrators as well as creating new users. They also have user modules to manage
access of members, especially communication members who are privileged.
4.3.2. Customer
Customer is created when they create an account on the website. This role is basically
equivalent to that of a normal blog subscriber, but customers can edit their own
account information and view past or current orders.
TECH STACK
1. Software Tools Used
The whole Project is divided in two parts the front end and the back end.
1.1. Front End
The front end is designed using of HTML, CSS, JavaScript.
HTML- HTML or Hyper Text Markup Language is the main markup language for
creating web pages and other information that can be displayed in a web
browser.HTML is written in the form of HTML elements consisting of tags enclosed in
angle brackets (like <html>), within the web page content. HTML tags most
commonly come in pairs like <h1> and </h1>, although some tags represent empty
elements and so are unpaired, for example <img>. The first tag in a pair is the start
tag, and the second tag is the end tag (they are also called opening tags and closing
tags). In between these tags web designers can add text, further tags, comments and
other types of text-based content. The purpose of a web browser is to read HTML
documents and compose them into visible or audible web pages. The browser does
not display the HTML tags, but uses the tags to interpret the content of the
page.HTML elements form the building blocks of all websites. HTML allows images
and objects to be embedded and can be used to create interactive forms. It provides
a means to create structured documents by denoting structural semantics for text
such as headings, paragraphs, lists, links, quotes and other items. It can embed
scripts written in languages such as JavaScript which affect the behaviour of HTML
web pages.
CSS - Cascading Style Sheets (CSS) is a style sheet language used for describing the
look and formatting of a document written in a markup language. While most often
used to style web pages and interfaces written in HTML and XHTML, the language
can be applied to any kind of XML document, including plain XML, SVG and XUL. CSS
is a cornerstone specification of the web and almost all web pages use CSS style
sheets to describe their presentation.CSS is designed primarily to enable the
separation of document content from document presentation, including elements
such as the layout, colours, and fonts. This separation can improve content
accessibility, provide more flexibility and control in the specification.
JavaScript - JavaScript (JS) is a dynamic computer programming language. It is most
commonly used as part of web browsers, whose implementations allow clientside
scripts to interact with the user, control the browser, communicate asynchronously,
and alter the document content that is displayed. It is also being used in server-side
programming, game development and the creation of desktop and mobile
applications. JavaScript is a prototype-based scripting language with dynamic typing
and has first-class functions. Its syntax was influenced by C. JavaScript copies many
names and naming conventions from Java, but the two languages are otherwise
unrelated and have very different semantics. The key design principles within
JavaScript are taken from the Self and Scheme programming languages. It is a multi-
paradigm language, supporting object-oriented, imperative, and functional
programming styles. The application of JavaScript to use outside of web pages—for
example, in PDF documents, site-specific browsers, and desktop widgets—is also
significant. Newer and faster JavaScript VMs and platforms built upon them (notably
Node.js) have also increased the popularity of JavaScript for server-side web
applications. On the client side, JavaScript was traditionally implemented as an
interpreted language but just-in-time compilation is now performed by recent (post-
2012) browsers.
1.2. Back End
The front end is designed using of PHP.
PHP - The PHP is a server-side scripting language designed for web development but
also used as a general-purpose programming language. PHP is now installed on more
than 244 million websites and 2.1 million web servers. Originally created by Rasmus
Lerdorf in 1995, the reference implementation of PHP is now produced by The PHP
Group. While PHP originally stood for Personal Home Page, it now stands for PHP:
Hypertext Pre-processor, a recursive backronym. PHP code is interpreted by a
webserver with a PHP processor module, which generates the resulting web page:
PHP commands can be embedded directly into an HTML source document rather
than calling an external file to process data. It has also evolved to include a
command-line interface capability and can be used in standalone graphical
applications. PHP is free software released under the PHP License. PHP can be
deployed on most web servers and also as a standalone shell on almost every
operating system and platform, free of charge.
MySQL - MySQL ("My S-Q-L", officially, but also called "My Sequel") is (as of July
2013) the world's second most widely used open-source relational database
management system (RDBMS). It is named after co-founder Michael Widenius
daughter, My. The SQL phrase stands for Structured Query Language. The MySQL
development project has made its source code available under the terms of the GNU
General Public License, as well as under a variety of proprietary agreements. MySQL
was owned and sponsored by a single for-profit firm, the Swedish company MySQL
AB, now owned by Oracle Corporation. MySQL is a popular choice of database for
use in web applications, and is a central component of the widely used LAMP open
source web application software stack (and other 'AMP' stacks). LAMP is an acronym
for "Linux, Apache, MySQL, Perl/PHP/Python." Free-software-open source projects
that require a full-featured database management system often use MySQL. For
commercial use, several paid editions are available, and offer additional
functionality. Applications which use MySQL databases
CODE
WordPress comprises different templates files as the following:
header.php: This is related to the header and navigation that can be edited within the php
file or through the Admin Panel.
<?php if (!defined('ABSPATH'))
{
exit;
} ?><!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>">
<link rel="profile" href="https://gmpg.org/xfn/11">
<?php wp_head(); ?>
</head>
index.php: This displays the posts of the virtual platform (website) that contains a loop as
PHP codes. It is displayed in excerpt or full-length form in the front or a separate static page
of the website.
<?php if (!defined('ABSPATH'))
{
exit;
}
get_header(); ?>
<?php do_action('generate_after_primary_content_area');
generate_construct_sidebars();
get_footer();
functions.php: This is meant for users who are looking to customize their themes’ features.
This is not provided b all WordPress themes, so it needs to be created under ‘wp-
content/themes/ThemeFolder” within PHP functions.
<?php if (!defined('ABSPATH'))
{
exit;
}
define('GENERATE_VERSION', '3.1.3');
if (!function_exists('generate_setup'))
{
add_action('after_setup_theme', 'generate_setup');
function generate_setup()
{
load_theme_textdomain('generatepress');
add_theme_support('automatic-feed-links');
add_theme_support('post-thumbnails');
add_theme_support('post-formats', array(
'aside',
'image',
'video',
'quote',
'link',
'status'
));
add_theme_support('woocommerce');
add_theme_support('title-tag');
add_theme_support('html5', array(
'search-form',
'comment-form',
'comment-list',
'gallery',
'caption',
'script',
'style'
));
add_theme_support('customize-selective-refresh-widgets');
add_theme_support('align-wide');
add_theme_support('responsive-embeds');
$color_palette = generate_get_editor_color_palette();
if (!empty($color_palette))
{
add_theme_support('editor-color-palette', $color_palette);
}
add_theme_support('custom-logo', array(
'height' => 70,
'width' => 350,
'flex-height' => true,
'flex-width' => true,
));
register_nav_menus(array(
'primary' => __('Primary Menu', 'generatepress') ,
));
global $content_width;
if (!isset($content_width))
{
$content_width = 1200;
}
add_theme_support('editor-styles');
$editor_styles = apply_filters('generate_editor_styles', array(
'assets/css/admin/block-editor.css',
));
add_editor_style($editor_styles);
}
}
$theme_dir = get_template_directory();
require $theme_dir . '/inc/theme-functions.php';
require $theme_dir . '/inc/defaults.php';
require $theme_dir . '/inc/class-css.php';
require $theme_dir . '/inc/css-output.php';
require $theme_dir . '/inc/general.php';
require $theme_dir . '/inc/customizer.php';
require $theme_dir . '/inc/markup.php';
require $theme_dir . '/inc/typography.php';
require $theme_dir . '/inc/plugin-compat.php';
require $theme_dir . '/inc/block-editor.php';
require $theme_dir . '/inc/class-typography.php';
require $theme_dir . '/inc/class-typography-migration.php';
require $theme_dir . '/inc/class-html-attributes.php';
require $theme_dir . '/inc/class-theme-update.php';
require $theme_dir . '/inc/class-rest.php';
require $theme_dir . '/inc/deprecated.php';
if (is_admin())
{
require $theme_dir . '/inc/meta-box.php';
require $theme_dir . '/inc/class-dashboard.php';
}
require $theme_dir . '/inc/structure/archives.php';
require $theme_dir . '/inc/structure/comments.php';
require $theme_dir . '/inc/structure/featured-images.php';
require $theme_dir . '/inc/structure/footer.php';
require $theme_dir . '/inc/structure/header.php';
require $theme_dir . '/inc/structure/navigation.php';
require $theme_dir . '/inc/structure/post-meta.php';
require $theme_dir . '/inc/structure/sidebars.php';
footer.php: This file is used to change the footer of every web page of the website so that
JavaScript code should be added before the </body/> tag.
<?php if (!defined('ABSPATH'))
{
exit;
} ?><?php do_action('generate_before_footer'); ?><div<?php
generate_do_attr('footer'); ?>><?php
do_action('generate_before_footer_content');
do_action('generate_footer');
do_action('generate_after_footer_content'); ?></div><?php
do_action('generate_after_footer');
wp_footer(); ?>
404.php: This informs that the post or queried page is not found by WordPress
<?php if (!defined('ABSPATH'))
{
exit;
}
get_header(); ?>
<?php do_action('generate_after_primary_content_area');
generate_construct_sidebars();
get_footer();
search.php: This is related to the search result page to be displayed.
<?php if (!defined('ABSPATH'))
{
exit;
}
get_header(); ?>
<?php do_action('generate_after_primary_content_area');
generate_construct_sidebars();
get_footer();
order-details.php: This is related to the order details from the WooCommerce plugin.
<thead>
<tr>
<th class="woocommerce-table__product-name product-name"><?php
esc_html_e('Product', 'woocommerce'); ?></th>
<th class="woocommerce-table__product-table product-
total"><?php esc_html_e('Total', 'woocommerce'); ?></th>
</tr>
</thead>
<tbody>
<?php
do_action('woocommerce_order_details_before_order_table_items', $order);
foreach ($order_items as $item_id => $item)
{
$product = $item->get_product();
wc_get_template('order/order-details-item.php', array(
'order' => $order,
'item_id' => $item_id,
'item' => $item,
'show_purchase_note' => $show_purchase_note,
'purchase_note' => $product ? $product->get_purchase_note() : '',
'product' => $product,
));
}
do_action('woocommerce_order_details_after_order_table_items', $order); ?>
</tbody>
<tfoot>
<?php foreach ($order->get_order_item_totals() as $key => $total)
{ ?>
<tr>
<th scope="row"><?php echo esc_html($total['label']);
?></th>
<td><?php echo ('payment_method' === $key) ?
esc_html($total['value']) : wp_kses_post($total['value']); ?></td>
</tr>
<?php
} ?>
<?php if ($order->get_customer_note()): ?>
<tr>
<th><?php esc_html_e('Note:', 'woocommerce'); ?></th>
<td><?php echo wp_kses_post(nl2br(wptexturize($order-
>get_customer_note()))); ?></td>
</tr>
<?php
endif; ?>
</tfoot>
</table>
tracking.php: This is the PHP code page which allows to track the order.
<?php
defined( 'ABSPATH' ) || exit;
$notes = $order->get_customer_order_notes();
?>
<p class="order-info">
<?php
echo wp_kses_post(
apply_filters(
'woocommerce_order_tracking_status',
sprintf(
__( 'Order #%1$s was placed on %2$s and is currently %3$s.',
'woocommerce' ),
'<mark class="order-number">' . $order->get_order_number() .
'</mark>',
'<mark class="order-date">' . wc_format_datetime( $order-
>get_date_created() ) . '</mark>',
'<mark class="order-status">' . wc_get_order_status_name(
$order->get_status() ) . '</mark>'
)
)
);
?>
</p>
<?php
define( 'WP_CACHE', true );
$table_prefix = 'wp_';
<?php
/*
* Plugin Name: Razorpay for WooCommerce
* Plugin URI: https://razorpay.com
* Description: Razorpay Payment Gateway Integration for WooCommerce
* Version: 4.1.0
* Stable tag: 4.1.0
* Author: Team Razorpay
* WC tested up to: 6.7.0
* Author URI: https://razorpay.com
*/
if ( ! defined( 'ABSPATH' ) )
{
exit; // Exit if accessed directly
}
require_once __DIR__.'/includes/razorpay-webhook.php';
require_once __DIR__.'/razorpay-sdk/Razorpay.php';
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once __DIR__.'/includes/razorpay-route.php';
require_once __DIR__ .'/includes/razorpay-route-actions.php';
require_once __DIR__.'/includes/api/api.php';
require_once __DIR__.'/includes/utils.php';
require_once __DIR__.'/includes/state-map.php';
require_once __DIR__.'/includes/plugin-instrumentation.php';
require_once __DIR__.'/includes/support/cartbounty.php';
use Razorpay\Api\Api;
use Razorpay\Api\Errors;
// instrumentation hooks
add_action('activated_plugin', 'razorpayPluginActivated', 10, 2 );
add_action('deactivated_plugin', 'razorpayPluginDeactivated', 10, 2 );
add_action('upgrader_process_complete', 'razorpayPluginUpgraded', 10, 2);
function woocommerce_razorpay_init()
{
if (!class_exists('WC_Payment_Gateway'))
{
return;
}
class WC_Razorpay extends WC_Payment_Gateway
{
// This one stores the WooCommerce Order Id
const SESSION_KEY = 'razorpay_wc_order_id';
const RAZORPAY_PAYMENT_ID = 'razorpay_payment_id';
const RAZORPAY_ORDER_ID = 'razorpay_order_id';
const RAZORPAY_ORDER_ID_1CC = 'razorpay_order_id_1cc';
const RAZORPAY_SIGNATURE = 'razorpay_signature';
const RAZORPAY_WC_FORM_SUBMIT = 'razorpay_wc_form_submit';
/**
* Can be set to true if you want payment fields
* to show on the checkout (if doing a direct integration).
* @var boolean
*/
public $has_fields = false;
/**
* Unique ID for the gateway
* @var string
*/
public $id = 'razorpay';
/**
* Title of the payment method shown on the admin page.
* @var string
*/
public $method_title = 'Razorpay';
/**
* Description of the payment method shown on the admin page.
* @var string
*/
public $method_description = 'Allow customers to securely pay via
Razorpay (Credit/Debit Cards, NetBanking, UPI, Wallets)';
/**
* Icon URL, set in constructor
* @var string
*/
public $icon;
/**
* TODO: Remove usage of $this->msg
*/
protected $msg = array(
'message' => '',
'class' => '',
);
/**
* Return Wordpress plugin settings
* @param string $key setting key
* @return mixed setting value
*/
public function getSetting($key)
{
return $this->get_option($key);
}
/**
* @param boolean $hooks Whether or not to
* setup the hooks on
* calling the constructor
*/
public function __construct($hooks = true)
{
$this->icon
= "https://cdn.razorpay.com/static/assets/logo/payment.svg";
// 1cc flags should be enabled only if merchant has access to 1cc
feature
$is1ccAvailable = false;
$api = $this->getRazorpayApiInstance();
$merchantPreferences = $api->request->request('GET',
'merchant/1cc_preferences');
if
(!empty($merchantPreferences['features']['one_click_checkout'])) {
$is1ccAvailable = true;
}
}
}
if ($is1ccAvailable) {
$this->visibleSettings = array_merge($this->visibleSettings,
array(
'enable_1cc',
'enable_1cc_mandatory_login',
'enable_1cc_test_mode',
'enable_1cc_pdp_checkout',
'enable_1cc_mini_cart_checkout',
'enable_1cc_ga_analytics',
'enable_1cc_fb_analytics',
'1cc_min_cart_amount',
'1cc_min_COD_slab_amount',
'1cc_max_COD_slab_amount',
));
}
$this->init_form_fields();
$this->init_settings();
$this->title = $this->getSetting('title');
}
add_filter( 'woocommerce_thankyou_order_received_text',
array($this, 'getCustomOrdercreationMessage'), 20, 2 );
}
$defaultFormFields = array(
'enabled' => array(
'title' => __('Enable/Disable', $this->id),
'type' => 'checkbox',
'label' => __('Enable this module?', $this->id),
'default' => 'yes'
),
'title' => array(
'title' => __('Title', $this->id),
'type'=> 'text',
'description' => __('This controls the title which the
user sees during checkout.', $this->id),
'default' => __(static::DEFAULT_LABEL, $this->id)
),
'description' => array(
'title' => __('Description', $this->id),
'type' => 'textarea',
'description' => __('This controls the description which
the user sees during checkout.', $this->id),
'default' => __(static::DEFAULT_DESCRIPTION, $this->id)
),
'key_id' => array(
'title' => __('Key ID', $this->id),
'type' => 'text',
'description' => __('The key Id and key secret can be
generated from "API Keys" section of Razorpay Dashboard. Use test or live for
test or live mode.', $this->id)
),
'key_secret' => array(
'title' => __('Key Secret', $this->id),
'type' => 'text',
'description' => __('The key Id and key secret can be
generated from "API Keys" section of Razorpay Dashboard. Use test or live for
test or live mode.', $this->id)
),
'payment_action' => array(
'title' => __('Payment Action', $this->id),
'type' => 'select',
'description' => __('Payment action on order compelete',
$this->id),
'default' => self::CAPTURE,
'options' => array(
self::AUTHORIZE => 'Authorize',
self::CAPTURE => 'Authorize and Capture'
)
),
'order_success_message' => array(
'title' => __('Order Completion Message', $this->id),
'type' => 'textarea',
'description' => __('Message to be displayed after a
successful order', $this->id),
'default' => __(STATIC::DEFAULT_SUCCESS_MESSAGE, $this-
>id),
),
'enable_1cc_debug_mode' => array( //Added this config for both
native and 1cc merchants
'title' => __('Activate debug mode'),
'type' => 'checkbox',
'description' => 'When debug mode is active, API logs and
errors are collected and stored in your Woocommerce dashboard. It is
recommended to keep this activated.',
'label' => __('Enable debug mode'),
'default' => 'yes',
),
);
$key_id = $this->getSetting('key_id');
$key_secret = $this->getSetting('key_secret');
$enabled = true;
$secret = empty($this->getSetting('webhook_secret')) ? $this-
>generateSecret() : $this->getSetting('webhook_secret');
$this->update_option('webhook_secret', $secret);
$getWebhookFlag = get_option('webhook_enable_flag');
$time = time();
if (empty($getWebhookFlag))
{
add_option('webhook_enable_flag', $time);
}
else
{
update_option('webhook_enable_flag', $time);
}
//validating the key id and key secret set properly or not.
if($key_id == null || $key_secret == null)
{
?>
<div class="notice error is-dismissible" >
<p><b><?php _e( 'Key Id and Key Secret are required.');
?><b></p>
</div>
<?php
$domain_ip = gethostbyname($domain);
?>
<div class="notice error is-dismissible" >
<p><b><?php _e( 'Could not enable webhook for localhost
server.'); ?><b></p>
</div>
<?php
do {
$webhook = $this->webhookAPI("GET",
"webhooks?count=".$count."&skip=".$skip);
$skip += 10;
if ($webhook['count'] > 0)
{
foreach ($webhook['items'] as $key => $value)
{
$webhookItems[] = $value;
}
}
} while ( $webhook['count'] === $count);
$data = [
'url' => $webhookUrl,
'active' => $enabled,
'events' => $this->defaultWebhookEvents,
'secret' => $secret,
];
if (count($webhookItems) > 0)
{
foreach ($webhookItems as $key => $value)
{
if ($value['url'] === $webhookUrl)
{
foreach ($value['events'] as $evntkey => $evntval)
{
if (($evntval == 1) and
(in_array($evntkey, $this-
>supportedWebhookEvents) === true))
{
$this->defaultWebhookEvents[$evntkey] = true;
}
}
$data = [
'url' => $webhookUrl,
'active' => $enabled,
'events' => $this->defaultWebhookEvents,
'secret' => $secret,
];
$webhookExist = true;
$webhookId = $value['id'];
}
}
}
if ($webhookExist)
{
rzpLogInfo('Updating razorpay webhook');
$this->webhookAPI('PUT', "webhooks/".$webhookId, $data);
}
else
{
rzpLogInfo('Creating razorpay webhook');
$this->webhookAPI('POST', "webhooks/", $data);
}
}
$trackObject = new
TrackPluginInstrumentation($_POST['woocommerce_razorpay_key_id'],
$_POST['woocommerce_razorpay_key_secret']);
$existingVersion = get_option('rzp_woocommerce_current_version');
if(isset($existingVersion))
{
update_option('rzp_woocommerce_current_version',
get_plugin_data(__FILE__)['Version']);
}
else
{
add_option('rzp_woocommerce_current_version',
get_plugin_data(__FILE__)['Version']);
}
try
{
global $wpdb;
$isTransactingUser = false;
$rzpTrancationData = $wpdb->get_row($wpdb->prepare("SELECT
post_id FROM $wpdb->postmeta AS P WHERE meta_key = %s AND meta_value = %s",
"_payment_method", "razorpay"));
$arrayPost = json_decode(json_encode($rzpTrancationData),
true);
$authEvent = '';
$pluginStatusEvent = '';
$authProperties = [
'is_key_id_populated' => true,
'is_key_secret_populated' => true,
'page_url' => $_SERVER['REQUEST_SCHEME'] .
'://' . $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
'auth_successful_status' => true,
'is_plugin_activated' =>
(isset($_POST['woocommerce_razorpay_enabled'])) ? true :false
];
if (empty($this->getSetting('key_id')) and
empty($this->getSetting('key_secret')))
{
$authEvent = 'saving auth details';
$response = $trackObject->rzpTrackSegment($authEvent,
$authProperties);
return $secret;
}
error_log(json_encode($log));
rzpLogError(json_encode($log));
}
return $webhook;
}
/**
* Receipt Page
* @param string $orderId WC Order Id
**/
function receipt_page($orderId)
{
echo $this->generate_razorpay_form($orderId);
}
/**
* Returns key to use in session for storing Razorpay order Id
* @param string $orderId Razorpay Order Id
* @return string Session Key
*/
protected function getOrderSessionKey($orderId)
{
$is1ccOrder = get_post_meta( $orderId, 'is_magic_checkout_order',
true );
if($is1ccOrder == 'yes')
{
return self::RAZORPAY_ORDER_ID_1CC . $orderId;
}
return self::RAZORPAY_ORDER_ID . $orderId;
}
/**
* Given a order Id, find the associated
* Razorpay Order from the session and verify
* that is is still correct. If not found
* (or incorrect), create a new Razorpay Order
*
* @param string $orderId Order Id
* @return mixed Razorpay Order Id or Exception
*/
public function createOrGetRazorpayOrderId($orderId, $is1ccCheckout =
'no')
{
global $woocommerce;
rzpLogInfo("createOrGetRazorpayOrderId $orderId and is1ccCheckout
is set to $is1ccCheckout");
$create = false;
if($is1ccCheckout == 'no')
{
update_post_meta( $orderId, 'is_magic_checkout_order', 'no' );
$sessionKey = $this->getOrderSessionKey($orderId);
try
{
$razorpayOrderId = get_transient($sessionKey);
rzpLogInfo("razorpayOrderId $razorpayOrderId | sessionKey
$sessionKey");
// If we don't have an Order
// or the if the order is present in transient but doesn't
match what we have saved
if (($razorpayOrderId === false) or
(($razorpayOrderId and ($this-
>verifyOrderAmount($razorpayOrderId, $orderId, $is1ccCheckout)) === false)))
{
$create = true;
}
else
{
return $razorpayOrderId;
}
}
// Order doesn't exist or verification failed
// So try creating one
catch (Exception $e)
{
$create = true;
}
if ($create)
{
try
{
return $this->createRazorpayOrderId($orderId,
$sessionKey);
}
// For the bad request errors, it's safe to show the
message to the customer.
catch (Errors\BadRequestError $e)
{
return $e;
}
// For any other exceptions, we make sure that the error
message
// does not propagate to the front-end.
catch (Exception $e)
{
return new Exception("Payment failed");
}
}
}
/**
* Returns redirect URL post payment processing
* @return string redirect URL
*/
private function getRedirectUrl($orderId)
{
$order = wc_get_order($orderId);
$query = [
'wc-api' => $this->id,
'order_key' => $order->get_order_key(),
];
/**
* Specific payment parameters to be passed to checkout
* for payment processing
* @param string $orderId WC Order Id
* @return array payment params
*/
protected function getRazorpayPaymentParams($orderId)
{
$getWebhookFlag = get_option('webhook_enable_flag');
$time = time();
if (empty($getWebhookFlag) == false)
{
if ($getWebhookFlag + 86400 < time())
{
$this->autoEnableWebhook();
}
}
else
{
update_option('webhook_enable_flag', $time);
$this->autoEnableWebhook();
}
rzpLogInfo("getRazorpayPaymentParams $orderId");
$razorpayOrderId = $this->createOrGetRazorpayOrderId($orderId);
return [
'order_id' => $razorpayOrderId
];
}
/**
* Generate razorpay button link
* @param string $orderId WC Order Id
**/
public function generate_razorpay_form($orderId)
{
$order = wc_get_order($orderId);
try
{
$params = $this->getRazorpayPaymentParams($orderId);
}
catch (Exception $e)
{
return $e->getMessage();
}
$checkoutArgs = $this->getCheckoutArguments($order, $params);
$html .= $this->generateOrderForm($checkoutArgs);
return $html;
}
/**
* default parameters passed to checkout
* @param WC_Order $order WC Order
* @return array checkout params
*/
public function getDefaultCheckoutArguments($order)
{
global $woocommerce;
$orderId = $order->get_order_number();
$wcOrderId = $order->get_id();
$callbackUrl = $this->getRedirectUrl($wcOrderId);
$sessionKey = $this->getOrderSessionKey($wcOrderId);
$razorpayOrderId = get_transient($sessionKey);
return array(
'key' => $this->getSetting('key_id'),
'name' => html_entity_decode(get_bloginfo('name'),
ENT_QUOTES),
'currency' => self::INR,
'description' => $productinfo,
'notes' => array(
self::WC_ORDER_ID => $orderId,
self::WC_ORDER_NUMBER => $wcOrderId
),
'order_id' => $razorpayOrderId,
'callback_url' => $callbackUrl,
'prefill' => $this->getCustomerInfo($order)
);
}
/**
* @param WC_Order $order
* @return string currency
*/
private function getOrderCurrency($order)
{
if (version_compare(WOOCOMMERCE_VERSION, '2.7.0', '>='))
{
return $order->get_currency();
}
return $order->get_order_currency();
}
/**
* Returns array of checkout params
*/
private function getCheckoutArguments($order, $params)
{
$args = $this->getDefaultCheckoutArguments($order);
$currency = $this->getOrderCurrency($order);
return $args;
}
return $args;
}
$api = $this->getRazorpayApiInstance();
$data = $this->getOrderCreationData($orderId);
rzpLogInfo('For order ' . $orderId);
rzpLogInfo(json_encode($data));
try
{
$razorpayOrder = $api->order->create($data);
}
catch (Exception $e)
{
return $e;
}
$getWebhookFlag = get_option('webhook_enable_flag');
$time = time();
if (empty($getWebhookFlag) == false)
{
if ($getWebhookFlag + 43200 < time())
{
$this->autoEnableWebhook();
}
}
else
{
update_option('webhook_enable_flag', $time);
$this->autoEnableWebhook();
}
$razorpayOrderId = $razorpayOrder['id'];
return $razorpayOrderId;
}
$api = $this->getRazorpayApiInstance();
try
{
$razorpayOrder = $api->order->fetch($razorpayOrderId);
}
catch (Exception $e)
{
$message = $e->getMessage();
rzpLogInfo("Failed at verifyOrderAmount with $message");
return "RAZORPAY ERROR: Order fetch failed with the message
'$message'";
}
$orderCreationData = $this->getOrderCreationData($orderId);
$razorpayOrderArgs = array(
'id' => $razorpayOrderId,
'currency' => $orderCreationData['currency'],
'receipt' => (string) $orderId,
);
if($is1ccCheckout == 'no'){
$razorpayOrderArgs['amount'] = $orderCreationData['amount'];
}else{
$razorpayOrderArgs['line_items_total'] =
$orderCreationData['amount'];
}
$orderKeys = array_keys($razorpayOrderArgs);
return true;
}
$data = array(
'receipt' => $orderId,
'amount' => (int) round($order->get_total() * 100),
'currency' => $this->getOrderCurrency($order),
'payment_capture' => ($this->getSetting('payment_action') ===
self::AUTHORIZE) ? 0 : 1,
'app_offer' => ($order->get_discount_total() > 0) ? 1 :
0,
'notes' => array(
self::WC_ORDER_NUMBER => (string) $orderId,
),
);
if ($this->getSetting('route_enable') == 'yes')
{
$razorpayRoute = new RZP_Route_Action();
$orderTransferArr = $razorpayRoute-
>getOrderTransferData($orderId);
return $data;
}
$i = 0;
// Get and Loop Over Order Items
foreach ( $order->get_items() as $item_id => $item )
{
$product = $item->get_product();
$productDetails = $product->get_data();
$data['line_items'][$i]['type'] = "e-commerce";
$data['line_items'][$i]['sku'] = $product->get_sku();
$data['line_items'][$i]['variant_id'] = $item-
>get_variation_id();
$data['line_items'][$i]['price'] =
(empty($productDetails['price'])=== false) ?
round(wc_get_price_excluding_tax($product)*100) + round($item-
>get_subtotal_tax()*100 / $item->get_quantity()) : 0;
$data['line_items'][$i]['offer_price'] =
(empty($productDetails['sale_price'])=== false) ? (int)
$productDetails['sale_price']*100 : $productDetails['price']*100;
$data['line_items'][$i]['quantity'] = (int)$item-
>get_quantity();
$data['line_items'][$i]['name'] = mb_substr($item->get_name(),
0, 125, "UTF-8");
$data['line_items'][$i]['description'] = mb_substr($item-
>get_name(), 0, 250,"UTF-8");
$productImage = $product->get_image_id()?? null;
$data['line_items'][$i]['image_url'] = $productImage?
wp_get_attachment_url( $productImage ) : null;
$data['line_items'][$i]['product_url'] = $product-
>get_permalink();
$i++;
}
return $data;
}
wp_register_script('razorpay_checkout',
'https://checkout.razorpay.com/v1/checkout.js',
null, null);
}
wp_localize_script('razorpay_wc_script',
'razorpay_wc_checkout_vars',
$data
);
wp_enqueue_script('razorpay_wc_script');
}
$formFields = "";
foreach ($data as $fieldKey => $val) {
if(in_array($fieldKey, array('notes', 'prefill', '_')))
{
foreach ($data[$fieldKey] as $field => $fieldVal) {
$formFields .= "<input type='hidden' name='$fieldKey"
."[$field]"."' value='$fieldVal'> \n";
}
}
}
/**
* Generates the order form
**/
function generateOrderForm($data)
{
$data["_"] = $this->getVersionMetaInfo($data);
$wooOrderId = $data['notes']['woocommerce_order_number'];
$redirectUrl = $this->getRedirectUrl($wooOrderId);
$data['cancel_url'] = wc_get_checkout_url();
$merchantPreferences = $api->request->request("GET",
"preferences");
if(isset($merchantPreferences['options']['redirect']) &&
$merchantPreferences['options']['redirect'] === true)
{
$this->enqueueCheckoutScripts('checkoutForm');
$data['preference']['image'] =
$merchantPreferences['options']['image'];
return $this->hostCheckoutScripts($data);
} else {
$this->enqueueCheckoutScripts($data);
return <<<EOT
<form name='razorpayform' action="$redirectUrl" method="POST">
<input type="hidden" name="razorpay_payment_id" id="razorpay_payment_id">
<input type="hidden" name="razorpay_signature" id="razorpay_signature" >
<!-- This distinguishes all our various wordpress plugins -->
<input type="hidden" name="razorpay_wc_form_submit" value="1">
</form>
<p id="msg-razorpay-success" class="woocommerce-info woocommerce-message"
style="display:none">
Please wait while we are processing your payment.
</p>
<p>
<button id="btn-razorpay">Pay Now</button>
<button id="btn-razorpay-cancel"
onclick="document.razorpayform.submit()">Cancel</button>
</p>
EOT;
}
}
/**
* Gets the Order Key from the Order
* for all WC versions that we suport
*/
protected function getOrderKey($order)
{
$orderKey = null;
return $order->order_key;
}
if (! $order or ! $order->get_transaction_id())
{
return new WP_Error('error', __('Refund failed: No transaction
ID', 'woocommerce'));
}
$client = $this->getRazorpayApiInstance();
$paymentId = $order->get_transaction_id();
$data = array(
'amount' => (int) round($amount * 100),
'notes' => array(
'reason' => $reason,
'order_id' => $orderId,
'refund_from_website' => true,
'source' => 'woocommerce',
)
);
try
{
$refund = $client->payment
->fetch( $paymentId )
->refund( $data );
return true;
}
catch(Exception $e)
{
return new WP_Error('error', __($e->getMessage(),
'woocommerce'));
}
}
/**
* Process the payment and return the result
**/
function process_payment($order_id)
{
rzpLogInfo("Called process_payment with params order_id
$order_id");
global $woocommerce;
$order = wc_get_order($order_id);
$orderKey = $this->getOrderKey($order);
/**
* Check for valid razorpay server callback
* Called once payment is completed using redirect method
*/
function check_razorpay_response()
{
global $woocommerce;
global $wpdb;
$order = false;
$post_type = 'shop_order';
$post_password = sanitize_text_field($_GET['order_key']);
$meta_key = '_order_key';
if (!empty($arrayPost) and
$arrayPost != null)
{
$orderId = $postMetaData->post_id;
$order = wc_get_order($orderId);
rzpLogInfo("Get order id in check_razorpay_response: orderId
$orderId");
}
wp_redirect(wc_get_cart_url());
exit;
}
wp_redirect(wc_get_checkout_url());
exit;
}
$cartHash = get_transient(RZP_1CC_CART_HASH.$orderId);
if ($cartHash != false)
{
// Need to delete the cart hash stored in transient.
// Becuase the cart hash will be depending on the cart items
so this will cause the issue when order api triggers.
$woocommerce->session->__unset(RZP_1CC_CART_HASH.$cartHash);
}
$this->redirectUser($order);
}
$razorpayPaymentId = null;
try
{
$this->verifySignature($orderId);
$success = true;
$razorpayPaymentId =
sanitize_text_field($_POST[self::RAZORPAY_PAYMENT_ID]);
$cartHash = get_transient(RZP_1CC_CART_HASH.$orderId);
if ($cartHash != false)
{
// Need to delete the cart hash stored in transient.
// Becuase the cart hash will be depending on the cart
items so this will cause the issue when order api triggers.
$woocommerce->session-
>__unset(RZP_1CC_CART_HASH.$cartHash);
}
}
catch (Errors\SignatureVerificationError $e)
{
$error = 'WOOCOMMERCE_ERROR: Payment to Razorpay Failed. '
. $e->getMessage();
}
}
else
{
if(isset($_POST[self::RAZORPAY_WC_FORM_SUBMIT]) &&
$_POST[self::RAZORPAY_WC_FORM_SUBMIT] ==1)
{
$success = false;
$error = 'Customer cancelled the payment';
}
else
{
$success = false;
$error = "Payment Failed.";
}
$this->updateOrderAddress($razorpayData, $order);
}
$this->handleErrorCase($order);
$this->updateOrder($order, $success, $error,
$razorpayPaymentId, null);
if (is1ccEnabled())
{
wp_redirect(wc_get_cart_url());
exit;
}
wp_redirect(wc_get_checkout_url());
exit;
}
$this->redirectUser($order);
}
wp_redirect($redirectUrl);
exit;
}
global $woocommerce;
$api = $this->getRazorpayApiInstance();
$attributes = array(
self::RAZORPAY_PAYMENT_ID =>
$_POST[self::RAZORPAY_PAYMENT_ID],
self::RAZORPAY_SIGNATURE => $_POST[self::RAZORPAY_SIGNATURE],
);
$sessionKey = $this->getOrderSessionKey($orderId);
//Check the transient data for razorpay order id, if it's not
available then look into session data.
if(get_transient($sessionKey))
{
$razorpayOrderId = get_transient($sessionKey);
}
else
{
$razorpayOrderId = $woocommerce->session->get($sessionKey);
}
$description = htmlentities($error['description']);
$code = htmlentities($error['code']);
/**
* Modifies existing order and handles success case
*
* @param $success, & $order
*/
public function updateOrder(& $order, $success, $errorMessage,
$razorpayPaymentId, $virtualAccountId = null, $webhook = false)
{
global $woocommerce;
$orderId = $order->get_order_number();
$this->update1ccOrderWC($order, $wcOrderId,
$razorpayPaymentId);
}
}
} catch (Exception $e) {
$message = $e->getMessage();
rzpLogError("Failed to update 1cc flow with error :
$message");
}
$payment_method=$order->get_payment_method();
if(is_plugin_active('woo-save-abandoned-carts/cartbounty-
abandoned-carts.php')){
handleCBRecoveredOrder($orderId);
}
if($this->getSetting('route_enable') == 'yes')
{
$razorpayRoute = new RZP_Route_Action();
$wcOrderId = $order->get_id();
$razorpayRoute->transferFromPayment($wcOrderId,
$razorpayPaymentId); // creates transfers from payment
}
if($virtualAccountId != null)
{
$order->add_order_note("Virtual Account Id:
$virtualAccountId");
}
if ($razorpayPaymentId)
{
$order->add_order_note("Payment Failed. Please check
Razorpay Dashboard. <br/> Razorpay Id: $razorpayPaymentId");
}
$order->add_order_note("Transaction Failed:
$errorMessage<br/>");
$order->update_status('failed');
}
$logObj = array();
rzpLogInfo("update1ccOrderWC wcOrderId: $wcOrderId,
razorpayPaymentId: $razorpayPaymentId");
//To avoid the symultanious update from callback and webhook
set_transient('wc_order_under_process_'.$wcOrderId, true, 300);
$api = $this->getRazorpayApiInstance();
$sessionKey = $this->getOrderSessionKey($wcOrderId);
//Check the transient data for razorpay order id, if it's not
available then look into session data.
if(get_transient($sessionKey))
{
$razorpayOrderId = get_transient($sessionKey);
}
else
{
$razorpayOrderId = $woocommerce->session->get($sessionKey);
}
$razorpayData = $api->order->fetch($razorpayOrderId);
$this->updateOrderAddress($razorpayData, $order);
if (sizeof($existingItems) != 0) {
// Loop through shipping items
foreach ($existingItems as $existingItemKey =>
$existingItemVal) {
$order->remove_item($existingItemKey);
}
}
if (class_exists('WCFMmp'))
{
$shippingOptions = get_option(
'wcfm_shipping_options', array());
// By default store shipping should be consider enable
$isStoreShippingEnabled = isset(
$shippingOptions['enable_store_shipping'] ) ?
$shippingOptions['enable_store_shipping'] : 'yes';
}
if ($isStoreShippingEnabled == 'yes')
{
foreach ($shippingData as $key => $value)
{
$item = new WC_Order_Item_Shipping();
//$item->set_method_id($test[$key]['rate_id']);
$item-
>set_method_title($shippingData[$key]['name']);
$item->set_total($shippingData[$key]['price']/100
);
$order->add_item($item);
$item->save();
$itemId = $item->get_id();
$wcfmCommissionOptions = get_option(
'wcfm_commission_options', array() );
$vendorGetShipping = isset(
$wcfmCommissionOptions['get_shipping'] ) ?
$wcfmCommissionOptions['get_shipping'] : 'yes';
if (isset($shippingData[$key]['vendor_id']) &&
$vendorGetShipping == 'yes')
{
$itemData = array(
'method_id' =>
$shippingData[$key]['method_id'],
'instance_id' =>
$shippingData[$key]['instance_id'],
'vendor_id' =>
$shippingData[$key]['vendor_id'],
'Items' =>
$shippingData[$key]['meta_data'][0]['value']
);
updateVendorDetails($shippingData[$key]['price
']/100, $shippingData[$key]['vendor_id'], $wcOrderId);
}
}
else
{
$item = new WC_Order_Item_Shipping();
// if shipping charges zero
if ($razorpayData['shipping_fee'] == 0)
{
$item->set_method_title( 'Free Shipping' );
}
else
{
$item-
>set_method_title($shippingData??[0]['name']);
}
$order->add_item( $item );
$item->save();
}
// Calculate totals and save
$order->calculate_totals();
}
}
$paymentDoneBy = $razorpayPyamentData['method'];
if (isset($razorpayData['customer_details']['shipping_address']))
{
$shippingAddressKey =
$razorpayData['customer_details']['shipping_address'];
$shippingAddress = [];
$shippingAddress['first_name'] = $shippingAddressKey['name'];
$shippingAddress['address_1'] = $shippingAddressKey['line1'];
$shippingAddress['address_2'] = $shippingAddressKey['line2'];
$shippingAddress['city'] = $shippingAddressKey['city'];
$shippingAddress['country'] =
strtoupper($shippingAddressKey['country']);
$shippingAddress['postcode'] = $shippingAddressKey['zipcode'];
$shippingAddress['email'] =
$razorpayData['customer_details']['email'];
$shippingAddress['phone'] = $shippingAddressKey['contact'];
$shippingState = strtoupper($shippingAddressKey['state']);
$shippingStateName = str_replace(" ", '', $shippingState);
$shippingStateCode =
getWcStateCodeFromName($shippingStateName);
$order->set_shipping_state($shippingStateCode);
$this->updateUserAddressInfo('shipping_', $shippingAddress,
$shippingStateCode, $order);
rzpLogInfo('shipping details for receipt id: '.$receipt .' is
'. json_encode($shippingAddress));
if
(empty($razorpayData['customer_details']['billing_address']) == false)
{
$billingAddress['first_name'] =
$razorpayData['customer_details']['billing_address']['name'];
$billingAddress['address_1'] =
$razorpayData['customer_details']['billing_address']['line1'];
$billingAddress['address_2'] =
$razorpayData['customer_details']['billing_address']['line2'];
$billingAddress['city'] =
$razorpayData['customer_details']['billing_address']['city'];
$billingAddress['country'] =
strtoupper($razorpayData['customer_details']['billing_address']['country']);
$billingAddress['postcode'] =
$razorpayData['customer_details']['billing_address']['zipcode'];
$billingAddress['email'] =
$razorpayData['customer_details']['email'];
$billingAddress['phone'] =
$razorpayData['customer_details']['billing_address']['contact'];
$order->set_address( $billingAddress, 'billing' );
$billingState =
strtoupper($razorpayData['customer_details']['billing_address']['state']);
$billingStateName = str_replace(" ", '', $billingState);
$billingStateCode =
getWcStateCodeFromName($billingStateName);
$order->set_billing_state($billingStateCode);
$this->updateUserAddressInfo('billing_', $billingAddress,
$billingStateCode, $order);
rzpLogInfo('billing details for receipt id: '.$receipt .'
is '. json_encode($billingAddress));
}
else
{
$order->set_address( $shippingAddress, 'billing' );
$order->set_billing_state($shippingStateCode);
$this->updateUserAddressInfo('billing_', $shippingAddress,
$shippingStateCode, $order);
}
$order->save();
}
}
/**
* Retrieve a Shipping Zone by it's ID.
*
* @param int $zone_id Shipping Zone ID.
* @return WC_Shipping_Zone|WP_Error
*/
// TODO: can't we directly return the statement?
protected function getShippingZone($zoneId)
{
$zone = WC_Shipping_Zones::get_zone_by('zone_id', $zoneId);
return $zone;
}
update_user_meta($order->get_user_id(), $addressKeyPrefix .
'state', $stateValue);
}
if (isset($cut_off_time))
{
$cartCutOffTime = intval($cutOffTime) * 60;
}
else
{
$cartCutOffTime = 60 * 60;
}
$abandonedOrderId =
wcal_common::wcal_get_cart_session('abandoned_cart_id_lite');
/**
* Add a woocommerce notification message
*
* @param string $message Notification message
* @param string $type Notification type, default = notice
*/
protected function add_notice($message, $type = 'notice')
{
global $woocommerce;
$type = in_array($type, array('notice','error','success'), true) ?
$type : 'notice';
// Check for existence of new notification api. Else use previous
add_error
if (function_exists('wc_add_notice'))
{
wc_add_notice($message, $type);
}
else
{
// Retrocompatibility WooCommerce < 2.1
switch ($type)
{
case "error" :
$woocommerce->add_error($message);
break;
default :
$woocommerce->add_message($message);
break;
}
}
}
/**
* Fetching version info for woo-razorpay and woo-razorpay-
subscription
* Which will be sent through checkout as meta info
* @param $data
* @return array
*/
public function getVersionMetaInfo($data)
{
if (isset($data['subscription_id']) && isset($data['recurring']))
{
$pluginRoot = WP_PLUGIN_DIR . '/razorpay-subscriptions-for-
woocommerce';
return array(
'integration' => 'woocommerce-subscription',
'integration_version' => get_plugin_data($pluginRoot .
'/razorpay-subscriptions.php')['Version'],
'integration_woo_razorpay_version' =>
get_plugin_data(plugin_dir_path(__FILE__) . 'woo-razorpay.php')['Version'],
'integration_parent_version' => WOOCOMMERCE_VERSION,
);
} else {
return array(
'integration' => 'woocommerce',
'integration_version' =>
get_plugin_data(plugin_dir_path(__FILE__) . 'woo-razorpay.php')['Version'],
'integration_parent_version' => WOOCOMMERCE_VERSION,
);
}
}
}
if (count($commission) > 0)
{
$totalComm = $commission[0]->total_commission+$shippingFee;
$wpdb->query(
$wpdb->prepare(
'UPDATE `' . $wpdb->prefix . 'wcfm_marketplace_orders` SET
shipping = %d, total_commission = %d WHERE vendor_id = %d AND order_id = %d',
$shippingFee,
$totalComm,
$vendorId,
$orderId
)
);
}
}
/**
* Add the Gateway to WooCommerce
**/
function woocommerce_add_razorpay_gateway($methods)
{
$methods[] = 'WC_Razorpay';
return $methods;
}
add_filter('woocommerce_payment_gateways',
'woocommerce_add_razorpay_gateway');
/**
* Creating the settings link from the plugins page
**/
function razorpay_woo_plugin_links($links)
{
$pluginLinks = array(
'settings' => '<a href="'. esc_url(admin_url('admin.php?page=wc-
settings&tab=checkout§ion=razorpay')) .'">Settings</a>',
'docs' => '<a href="https://razorpay.com/docs/payment-
gateway/ecommerce-plugins/woocommerce/woocommerce-pg/">Docs</a>',
'support' => '<a
href="https://razorpay.com/contact/">Support</a>'
);
return $links;
}
add_filter('plugin_action_links_' . plugin_basename(__FILE__),
'razorpay_woo_plugin_links');
}
$rzpWebhook->process();
}
function enqueueScriptsFor1cc()
{
$siteurl = get_option('siteurl');
function addCheckoutButton()
{
add_action('wp_enqueue_scripts', 'enqueueScriptsFor1cc', 0);
add_action( 'woocommerce_widget_shopping_cart_buttons',
'addMiniCheckoutButton', 20 );
}, 1 );
}
function addMiniCheckoutButton()
{
add_action('wp_enqueue_scripts', 'enqueueScriptsFor1cc', 0);
if (isTestModeEnabled()) {
$current_user = wp_get_current_user();
if ($current_user->has_cap( 'administrator' ) || preg_match(
'/@razorpay.com$/i', $current_user->user_email )) {
$tempTest = RZP_PATH . 'templates/rzp-mini-checkout-btn.php';
load_template( $tempTest, false, array() );
}
} else {
$tempTest = RZP_PATH . 'templates/rzp-mini-checkout-btn.php';
load_template( $tempTest, false, array() );
}
function addPdpCheckoutButton()
{
add_action('wp_enqueue_scripts', 'enqueueScriptsFor1cc', 0);
if (isTestModeEnabled()) {
$current_user = wp_get_current_user();
if ($current_user->has_cap( 'administrator' ) || preg_match(
'/@razorpay.com$/i', $current_user->user_email )) {
$tempTest = RZP_PATH . 'templates/rzp-pdp-checkout-btn.php';
load_template( $tempTest, false, array() );
}
} else {
$tempTest = RZP_PATH . 'templates/rzp-pdp-checkout-btn.php';
load_template( $tempTest, false, array() );
}
}
add_action('admin_enqueue_scripts', 'addAdminSettingsAlertScript');
function disable_coupon_field_on_cart($enabled)
{
if (isTestModeEnabled()) {
$current_user = wp_get_current_user();
if ($current_user->has_cap( 'administrator' ) || preg_match(
'/@razorpay.com$/i', $current_user->user_email )) {
if (is_cart()) {
$enabled = false;
}
}
} else {
if (is_cart()) {
$enabled = false;
}
}
return $enabled;
}
if(is1ccEnabled())
{
add_filter('woocommerce_coupons_enabled', 'disable_coupon_field_on_cart');
add_action('woocommerce_cart_updated', 'enqueueScriptsFor1cc', 10);
add_filter('woocommerce_order_needs_shipping_address', '__return_true');
}
// instrumentation
$activateProperties = [
'page_url' => $_SERVER['HTTP_REFERER'],
'redirect_to_page' => $_SERVER['REQUEST_SCHEME'] . '://' .
$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']
];
$paymentSettings = get_option('woocommerce_razorpay_settings');
$deactivateProperties = [
'page_url' => $_SERVER['HTTP_REFERER'],
'is_transacting_user' => $isTransactingUser
];
$upgradeProperties = [
'page_url' => $_SERVER['HTTP_REFERER'],
'prev_version' =>
get_option('rzp_woocommerce_current_version'),
'new_version' => get_plugin_data(__FILE__)['Version'],
];
if(isset($existingVersion))
{
update_option('rzp_woocommerce_current_version',
get_plugin_data(__FILE__)['Version']);
}
else
{
add_option('rzp_woocommerce_current_version',
get_plugin_data(__FILE__)['Version']);
}
}
}
//Changes Recovery link URL to Magic cart URL to avoid redirection to checkout
page
function cartbounty_alter_automation_button( $button ){
return str_replace("cartbounty=","cartbounty=magic_",$button);
}
if(is_plugin_active('woo-save-abandoned-carts/cartbounty-abandoned-
carts.php')){
add_filter( 'cartbounty_automation_button_html',
'cartbounty_alter_automation_button' );
}
RESULTS
1. Hostinger Server
This is the server where the website is hosted represented as the following:
The PHP files connected to the database:
2. User Roles
2.1. Dashboard
2.2. Plugins
2.3. Products
2.4. Customers
2.5. Front-End
3. Database: PhpMyAdmin
eCommerce testing helps in the prevention of errors and adds value to the product by
ensuring conformity to client requirements. The objective of testing is to ensure
• Software reliability
• Software quality
• System Assurance
• Optimum performance and capacity utilization
UNIT TESTING
Unit testing is undertaken when a module has been created and successfully reviewed. In
order to test a single module, we need to provide a complete environment i.e., besides the
module we would require
• The procedures belonging to other modules that the module under test calls
• Non local data structures that module accesses
• A procedure to call the functions of the module under test with appropriate
parameters
INTEGRATION TESTING
In this type of testing, we test various integration of the project module by providing the
input. The primary objective is to test the module interfaces in order to ensure that no errors
are occurring when one module invokes the other module.
Integration testing is the second level of the software testing process comes after unit testing.
In this testing, units or individual components of the software are tested in a group. The focus
of the integration testing level is to expose defects at the time of interaction between
integrated components or units.
Unit testing uses modules for testing purpose, and these modules are combined and tested
in integration testing. The Software is developed with a number of software modules that are
coded by different coders or programmers. The goal of integration testing is to check the
correctness of communication among all the modules.
Once all the components or modules are working independently, then we need to check the
data flow between the dependent modules is known as integration testing.
Guidelines for Integration Testing
• We go for the integration testing only after the functional testing is completed on each
module of the application.
• We always do integration testing by picking module by module so that a proper
sequence is followed, and also, we don't miss out on any integration scenarios.
• First, determine the test case strategy through which executable test cases can be
prepared according to test data.
• Examine the structure and architecture of the application and identify the crucial
modules to test them first and also identify all possible scenarios.
• Design test cases to verify each interface in detail.
• Choose input data for test case execution. Input data plays a significant role in testing.
• If we find any bugs then communicate the bug reports to developers and fix defects
and retest.
• Perform positive and negative integration testing.
2. Page display
• Incorrect display of pages
• Runtime error messages
• Poor page download time
• Dead hyperlink, plugin dependency, font sizing, etc.
3. Session Management
• Session Expiration
• Session storage
4. Usability
• Non-intuitive design
• Poor site navigation
• Catalog navigation
• Lack of help-support
5. Content Analysis
• Misleading, offensive and litigious content
• Royalty free images and copyright infringement
• Personalization functionality
• Availability 24/7
6. Availability
• Denial of service attacks
• Unacceptable levels of unavailability
12. Performance
• Performance bottlenecks
• Load handling
• Scalability analysis
Variety of Sharbat
Sweet Delicacies
Aachari Maza
Product Page
Product Page
Cart Page
Checkout Page
Payment Gateway – Razorpay
CONCLUSION
After completing this “Meena’s Kitchen - An eCommerce website” project, I can now look
back and see how much I have learnt and grown as a software engineer. As a future
graduating student from JECRC University, I got a vision that incorporates values based on the
perception of development, progress and continuous improvement. Hence, my leadership
within the student activities office was considered as a crucial factor in acquiring creativity,
organization and management.
Throughout this eCommerce website project, there were many constraints encountered. The
key one that picked my interest is that most implemented approaches demand the right
behaviour of the user.
Finally, I can say that working with a Content Management System which was WordPress in
the project was a skilful experience for me. It was an opportunity that has long term
professional and personal goals, by learning new technologies and tools on a practical level.
Perhaps the most important thing that I have learnt through this project is the following: As
a software engineer, I should adapt to the needs of the market/client, not try to impose my
own vision of how things should be. Indeed, it is constant adaptability that is the hallmark of
a true engineer, as Carl Sagan said “Science is a wa of thinking, much more than it is a body
of knowledge”.
BIBLIOGRAPHY
1. WordPress.org (https://wordpress.org/)
3. WooCommerce (https://woocommerce.com/)
4. Hostinger (https://www.hostinger.in/)
5. phpMyAdmin (https://www.phpmyadmin.net/)
7. Guru99 (https://www.guru99.com/)
8. WPBeginner (https://www.wpbeginner.com/)
9. W3Schools (https://www.w3schools.com/)