When the user is sent to the "thank you page" (cart/checkout/complete) I need to get some info about the order to send it to a 3rd party tracking API. Problem is that in this point there is no info about the order, either in session nor in any other place that I know of. As a workaround I tried querying the last order for the currently connected user but this fails when the user is unregistered as Ubercart registers an account on the fly and leaves the user unlogged.
So my question is, is there a way to get the Order object at this point (cart/checkout/complete) from the page-cart.tpl.php template ?
My solution so far:
Grab the $_SESSION['cart_order'] variable at cart/checkout/review , assign it to $_SESSION['faux_order'] and use faux_order in my script at cart/checkout/complete ... which feels as ugly as seeing a giraffe choke to death.
WARNING! DO NOT USE THE ANSWER ABOVE. See my comment for explanation.
Instead of the answer submitted above (which you should NEVER! use) create a custom Ubercart conditional action (CA) and add it to the section "Trigger: Customer completes checkout" in your Ubercart CA workflow, found in https://dev.betternow.org/admin/store/ca/overview
Here I am defining a custom CA
function my_module_ca_action() {
$order_arg = array(
'#entity' => 'uc_order',
'#title' => t('Order'),
);
$actions['my_module_status_update'] = array(
'#title' => t('Some Title'),
'#category' => t('Custom UC AC'),
'#callback' => 'my_module_some_function_name',
'#arguments' => array(
'order' => $order_arg,
),
);
return $actions;
}
Now I can use the order id in my own callback function defined in my module:
function my_module_some_function_name(&$order, $settings) {
echo "This is the order id: " . $order->order_id;
}
I use this approach myself to show a "Thank You" page to users with a link to the product they just purchased.
$_SESSION['cart_order'] is available on the order review page.
So ...
Create a cookie representing the order ID like this:
<?php setcookie('orderID', '$_SESSION['cart_order']'); ?>
Then, on the order confirmation page, you can call the saved cookie like this:
<?php
if (isset($_COOKIE['orderID'])):
$theOrder = $_COOKIE['orderID'));
echo 'The order ID is: ' . $theOrder;
endif;
?>
If the user then goes back and creates a new order, the cookie will be updated whenever they reach the order review page.
Related
I'm new to Wordpress plugin development but I've decided to build one in order to internally connect to the WishList Member (WLM) API.
I want to capture the user's sign-up information every time they register using the WLM checkout form on our website. The WLM tech support suggested I use the wishlistmember_shoppingcart_register hook in their API. They also said information about the registration can be found in the $_POST variable.
Since I'm so new to Wordpress Plugin development I'm not really sure how to implement the hook. I've learned how to use the WLM API's main functions from the code they provided but that's all I can figure out.
How does the hook get triggered every time the user is added? Should I use a shortcode on the page with the WLM form? How do I access the $_POST variable in my plugin?
Also, I've noticed some Wordpress plugins are just series of function calls and others create a class object. Can I use either approach in my plugin?
A little guidance would be appretiated.
Thanks
Mike
UPDATE: Here's the code I've been working on...
<?php
/*
Plugin Name: MGC
Description: A plugin to integrate with WLM
Author: Mike Grossman
Version: 0.1
*/
require(dirname(__FILE__) . '/wlmapiclass.php');
//echo "<h1>Hello world!</h1>";
$member_registration_results = array();
add_action('admin_menu', 'mgc_plugin_setup_menu'); //load menu bar on the admin panela and run the function
function mgc_plugin_setup_menu(){
add_menu_page( 'MGC Plugin Page', 'MGC Plugin', 'manage_options', 'mgc-plugin', 'dp_api_internal' );
}
function mgc_init(){
echo "<h1>Hello World!</h1>";
}
function dp_api_internal(){
if (function_exists('wlmapi_get_levels')){
$levels = wlmapi_get_levels();
print_r($levels);
}
}
function dp_api_external(){
//No external connection needed
}
function member_registration() {
$test_member_data = array(
"user_login" => 'test_wlmtest_member',
"user_email" => 'test_member#wlmtest.com',
"first_name" => 'Test First Name',
"last_name" => 'Test Last Name',
"display_name"=>'Test Display Name',
"user_pass" => '1234567890',
"Sequential"=> true,
"SendMail" => 'true',
"Levels" => array($_POST['wlmtest_level_id'])
);
if (isset($_POST['wlmtest_action'] ) && $_POST['wlmtest_action']=="member_registration_internal_api" ) {
/* Test Member Registration Using Internal API */
$this->member_registration_results['internal'] = $this->RegisterMemberInternalAPI($test_member_data);
}
}
function RegisterMemberInternalAPI ($member_data) {
$response = wlmapi_add_member($member_data);
return $response;
}
?>
I found all of the WLM code in tutorials and free 3D party plugins.
I finally figured out how to get the WLM member data I wanted without using the API. I captured the WLM shortcodes (i.e. [wlm_lastname]) after the user has registered on the website. Also, the plugin I created didn't need a Wordpress admin panel so I removed that code as well.
I have created a custom payment module and currently it calls validateOrder() after the redirection from the payment website, and this method creates the order, sends email etc. But the issue is if user closed the payment website before it can redirect back to the PrestaShop website the order won't be created in this case. So, I want to create an order(say with "pending" status) before I redirect to the payment website and after redirection from the payment website I can simply mark the same payment as done and send mails etc.
Currently for this I was trying to call validateOrder twice, once in hookdisplayPayment(here I set the status as "pending") and once after redirection. But now after redirection I am getting "The cart cannot be loaded, or an order has already been placed using this cart". I think that's because I can't update the same order twice using the same Card Id.
Note that I want to send the emails only once, once the payment is successful. Currently for this I am using a custom payment status with 'send_email' set to 0.
What's a good workaround for this?
I would like to support versions 1.5+ and 1.6+ if that matters.
A better way to do it than my first answer would be to create a override in your module of function validateOrder.
You will modify:
/** #var Order $order */
$order = new Order();
Into:
/** #var Order $order */
$order = new Order($this->currentOrder);
Then test if is loaded object, skip the part where it sets the order fields. If it's not loaded, set the order fields appropriately with the pending status.
Also test if $this->currentOrder is set where the email is sent, if it's not set skip the email part. If it's set it means the order is pending and you should change the status and send the email.
After you override the function, you can call validateOrder twice, before and after redirection.
You could try something like this:
Before making the redirection you can call once function validateOrder and set status as pending. This will set for your module the variable $this->currentOrder with the id of the pending order.
After redirection don't call again validateOrder, but create your own function to call, eg. validateOrderAfterRedirect in which you check that the payment was made and change the status of the current order. It will be something like this:
// your way of checking that te payment was made
$payment_completed = $this->paymentIsComplete();
if($payment_completed) {
$order = new Order($this->currentOrder);
if(Validate::isLoadedObject($order) && $order->getCurrentOrderState() == [id of pending status]) {
$order->setCurrentState([id of payment accepted status]);
}
}
Create an order with "pending payment" status before the website is redirected to payment system. Once the customer returns the system should just change the payment status to "completed". If the customer closes the payment site, the status will remain "pending" and should be manually updated after checking the payment system.
Many payment gateways provide a mechanism where on completed or failed payment they post data including amount paid and cart ID to a URL you supply to them.
When you process this information using a server-side script at that stage you can validate the order. This should happen before the user is redirected back to your website. Once they are redirected to your site it will already have acknowledged payment in the background.
The reason this method is preferred is that it is the only way to ensure the customer cannot manipulate a URL to make your store think they have paid for an order when in fact no money has changed hands, after which you could end up shipping products for free.
You can do it by adding some like this
$result = $this->validateOrder((int) $cart->id, Configuration::get('PPQ_CREATED_STATUS'), $total, $this->displayName, NULL, array(), (int) $currency->id, false, $customer->secure_key);
in any plays where you need before redirection(where $this is payment module instance)
And after redirection to confirm page I have use wrote this
public function hookPaymentReturn($params)
{
$id_module = (int) Tools::getValue('id_module');
if ($id_module === (int) $this->id) {
$orderHistory = new OrderHistory();
$orderHistory->changeIdOrderState(Configuration::get('PPQ_SUCCESS_STATUS'), $params['objOrder']);
}
}
For mail sending you can configure needed order status
For my case (need work only with paypal, I have change write my own one page checkout module and write my own payment module and befour redirect to paypal I have wrote this
public function hookPayment($params)
{
$customer = &$this->context->customer;
$cart = &$this->context->cart;
$currency = &$this->context->currency;
if (
$customer->isLogged(true) &&
$cart->nbProducts()
) {
$total = (float) $cart->getOrderTotal(true, Cart::BOTH);
$result = $this->validateOrder((int) $cart->id, Configuration::get('PPQ_CREATED_STATUS'), $total, $this->displayName, NULL, array(), (int) $currency->id, false, $customer->secure_key);
if ($result) {
if (!Configuration::get('PPQ_TEST_MODE')) {
$paypal_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=' . Configuration::get('PPQ_PROFILE');
} else {
$paypal_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_xclick&business=' . Configuration::get('PPQ_PROFILE');
}
$order_confirmation_url = $this->context->link->getPageLink('order-confirmation', null, null, array(
'id_cart' => (int) $cart->id,
'id_module' => (int) $this->id,
'id_order' => (int) $this->currentOrder,
'key' => $customer->secure_key,
));
$this->context->smarty->assign(array(
'paypal_url' => $paypal_url,
'order_confirmation_url' => $order_confirmation_url,
'order_id' => (int) $this->currentOrder,
'shop_name' => $this->context->shop->name,
'total_without_shipping' => Tools::convertPriceFull((float) $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING)),
'total_shipping' => Tools::convertPriceFull((float) $cart->getOrderTotal(true, Cart::ONLY_SHIPPING)),
'currency_iso' => Tools::strtoupper($currency->iso_code)
));
return $this->display(__FILE__, 'paypalquick.tpl');
} else {
$this->context->controller->errors[] = $this->l('Can\'t create order. Pleas contact with us');
}
} else {
$this->context->controller->errors[] = $this->l('Problem with loginin or cart empty');
}
}
and tpl
<form id="paypalquick" action="{$paypal_url}" method="post" enctype="multipart/form-data">
<input type="hidden" value="{l s='%s order #%s' sprintf=[$shop_name|escape:'html':'UTF-8', $order_id|intval] mod='paypalquick'}" name="item_name"/>
<input type="hidden" value="{$total_without_shipping}" name="amount"/>
<input type="hidden" value="{$total_shipping}" name="shipping"/>
<input type="hidden" value="{$currency_iso}" name="currency_code"/>
<input type="hidden" value="{$order_confirmation_url}" name="return"/>
<div class="text-center">
<button class="submit">{l s='Go to PayPal for payment' mod='paypalquick'}</button>
</div>
But it was my private cas you can't use it on default but you can see how to make it.
I think we need you to call another hook (that you create) at the time of validation on the site (before leaving that matter) who put a pending status, and keep ValidateOrder hook () to to payment confirmed
Regards,
Arthur
Im building an e-commerce site for wholesale foods and the pricing for products change depending on the user logged in. Ive looked at member pricing and basically every module i could find to do with altering the price but they are either for drupal 6 or not really what im after. Im using Drupal 7 with ubercart 3.
Ive found this module http://drupal.org/project/uc_custom_price. It adds a field within product creation that allows custom php code to be added to each individual product which is exactly what im after. however im not that good with php which is why ive been hunting modules instead of changing code.
What ive got at the moment is:
if ([roles] == 'test company') {
$item->price = $item->price*0.8;
}
Except the [roles] part is the wrong thing to use there and it just throws errors. Ive tried using things like $users->uid =='1' to try to hook onto a user like that but that didnt work either.
what would be the correct variable to put there?
thanks
try this Drupal 7 global $user object
global $user; // access the global user object
if(in_array("administrator",$user->roles)){ // if its administrator
$item->price = $item->price*0.8;
}elseif(in_array("vip",$user->roles)){ // if its a vip
//..
}elseif(in_array("UserCompanyX",$user->roles)){ // if its a user from company X
//..
}
or
if($user->roles[OFFSET] == "ROLE"){
// price calculation
}
$user->roles is an array of the roles assigned to the user.
hope it helped
Make your own module with UC Price API:
http://www.ubercart.org/docs/developer/11375/price_api
function example_uc_price_handler() {
return array(
'alter' => array(
'title' => t('Reseller price handler'),
'description' => t('Handles price markups by customer roles.'),
'callback' => 'example_price_alterer',
),
);
}
function example_price_alterer(&$price_info, $context, $options = array()){
global $user;
if (in_array("reseller", $user->roles)) { //Apply 30% reseller discount
$price_info["price"] = $context["subject"]["node"]->sell_price - (
$context["subject"]["node"]->sell_price * 0.30) ;
}
return;
}
See also: http://www.ubercart.org/forum/development/14381/price_alteration_hook
I have created a 'Companyname' attribute which gets added up in my Customer's Account information and is a required field.
It gets filled up on registration, form and edit pages fine and gets displayed on Customer's Grid in the back-end too.
However I am not able to display the Company name in any of my order email templates.
I believe this is because there is neither any column called 'companyname' in my order tables nor do I have any custom variable which I can pass to order/invoice/shipment templates to display Company name right next to the line after Customer's name.
Can any one point out the file where I can create this custom variable containing my custom 'companyname' attribute and pass it to all types of sales email templates
Thanks
After a little bit of searching I found the right file to make the changes. Since I already had 'companyname' as one of my attributes I retrieved the value of this field and passed it as a param in the following function
app/code/core/Mage/Sales/Model/Order.php
public function sendNewOrderEmail()
{
/*Existing Code*/
if ($this->getCustomerIsGuest()) {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
$customerId = Mage::getModel('customer/customer')->load($this->getCustomerId());
$companyname = $customerId->getCompanyname();
$customerName = $this->getBillingAddress()->getName();
} else {
$templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
$customerId = Mage::getModel('customer/customer')->load($this->getCustomerId());
$companyname = $customerId->getCompanyname();
$customerName = $this->getCustomerName();
}
/*Existing Code*/
$mailer->setTemplateParams(array(
'order' => $this,
'billing' => $this->getBillingAddress(),
'payment_html' => $paymentBlockHtml,
'companyname' => $companyname
));
/*Rest of the code remains the same*/
}
After making this change. I edited my Transactional Email to include this param. Since I wanted to display inside Shipping Address, I placed my variable just before this line in
System > Transactional Emails > New Order Email
{{ var companyname }}
{{var order.getShippingAddress.format('html')}}
If your companyname is getting saved as a part of Customer Information then this would get displayed in your Order Email in 'Shipping Address' Information right at the Start.
You can do the same for Invoice and Shipment Emails.
Hope this helps someone !!! :-)
I’m using a cart library to get orders in my web bookstore. But when I call a addCart function on one of my book it’s works, but not all the time. Please, help
There is my model function:
function get_books_by_ID($id)
{
$this->db->where('BOOK_ID', $id);
$query = $this->db->get('books');
return $query;
echo vardump($query);
}
Controller:
function addCards($id=1)
{
$query = $this->Kategorie_model->get_books_by_ID($id);
if($query->num_rows() > 0)
{
$item = $query->row();
$data = array(
'id' => $item->BOOK_ID,
'qty' => 1,
'price' => $item->BOOK_Price,
'name' => $item->BOOK_Title
);
$this->cart->insert($data);
}
}
View:
<tr>
<td class="color"><b>Cena: </b><?php echo $data->BOOK_Price;?>zł</td>
<td class="border" id="koszyk" ><?php echo anchor('ksiegarnia/addCards/'.$data->BOOK_ID, 'Koszyk'); ?></td>
</tr>
UPDATE:
vardump is nothing necessary. I want to use var_dump. But the problem is related with adding items to the session with carts library. I have a bookstore, and when I call a addCarts function, sometimes items is added to Carts, and cart function total() and total_items displaying it, but sometimes when I call function, nothing is happened. The items not add into carts. I don't now why this thing have a place. Why the carts library works randomly?
I just ran into this issue and it seems that in the codeigniter cart library the insert function checks the product(s) id and name against a regex only allow alpha-numeric, dashes, underscores and periods
Adjust the regex to what may come up:
$this->cart->product_id_rules = '.a-z0-9_';
$this->cart->product_name_rules = '.\:-_ a-z0-9';
In my case it would randomly add thing to carts too. If you turn on logging and check you'll be able to see that the name or id may contain invalid chars
i am doing as you did, and like you said, the cart is randomly works,
it seems can only contain 3 product in cart when i add another product, the product i added wont get into cart..
i am so hopeless, i get mind to change cart libraries with 3rd party
it is because i did not setting session to save to database, like in the tutorial (cart & session) the cart need session to write to database in order to work.
when i set session write to database, the problem solved
you can try...