How to get all users ever paid/complete an order? - php

I am working on a custom Magento Extension.
Here is how I take all customers in a customer group:
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*');
foreach($customers as $customer)
{
$email=$customer->getEmail();
$CustomerPhone = $customer->getPrimaryBillingAddress()->getTelephone();
$CustomerName = $customer->getName();
$CustomerEmail = $customer->getEmail();
}
This how I get information about the users in a specific customer group.
How I can get all the users ever paid or complete (for example) an order?

This is 90% of the way there:
<?php
require_once '<path_to_magento_root>/app/Mage.php';
Mage::app('default');
$customers = Mage::getResourceModel('reports/customer_collection')
->setPage(0,10)
//->addAttributeToFilter('orders_count', array('gt' => 0))
->addOrdersStatistics();
foreach ($customers as $c) {
echo $c->getId().' - '.$c->getEmail().': '.$c->getOrdersCount()." orders, average amount ".$c->getOrdersAvgAmount().", sum amount ".$c->getOrdersSumAmount().PHP_EOL;
}
The missing 10% is that this lists all customers, and their order information, rather than only ones with at least one order (which will include in-progress orders - the addOrdersStatistics() includes any orders that aren't canceled).
I have that commented line in there, //->addAttributeToFilter('orders_count', array('gt' => 0)), because I thought that should do it, but it appears to be doing nothing at all. Still, I figured I'd put this much up at least, because maybe it's at least a step in the right direction.
Of course, you also could just loop through every order, and build an array of customers that fit your criteria, but that's probably going to be much, much slower than using Magento's reports models like this. As a last resort, though, it'd work. So would querying the database directly, for that matter.

Try following solution this should work for you.
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('*');
$customers->joinTable(
array('sales/order'),
'customer_email=email',
array('*'),
null,
'right'
);
// print_r($customers->getData());
$data = $customers->getData();
foreach($data as $d)
{
//print_r($d); // print this to see the available fields
echo $d[customer_email]; //get the desired information
echo "<br>";
}

Related

Load product information by comparing custom attribute in Magento

I am working on some scripts to automate some things inside our webshop.
I have looked through many forums and questions.
Now I almost have finished my script but there is a small thing that doesn't work but I can not think of what I am doing wrong.
What the goal of this script is, is to get products that has the same attribute value as the values in an array (pulled from DB).
So here is my code:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once('../app/Mage.php');
require_once('db.php');
Mage::app();
$db = db_connection();
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ean');
$getean = $db->prepare('SELECT ean_l FROM mytable');
$getean->execute();
$allean = $getean->fetchAll();
foreach($allean as $ean) {
$collection->addFieldToFilter(array(
array('attribute'=>'ean','eq'=>'' . $ean['ean_l'] . ''),
));
echo 'ean_l: ' . $ean['ean_l'] . '<br>';
foreach ($collection as $product) {
echo $product['entity_id'];
}
}
So here's how it works:
We select an attribute (ean).
We get a list of all ean numbers from the database.
We loop through the list and compare any product with the ean number.
Then we loop through the collection and get the id of the corresponding product.
Yet, all $product['entity_id']'s are 273. It is correct that the entity_id is 273, but there is also product 274 with a corresponding ean number.
Here is the result from the script (it's alot more):
So why is this? Because in my reasoning, it changes the ean_l every loop and it equalizes it with the attribute values.
And then it should change the collection, right?
So shouldn't it at least show 274 at some point?
This question is not especially for Magento programmers, but other programmers can help too, so I figured to post it on SO.
Magento comes with powerfull filtering and queries into collections. If that doesn't satisfy, you can always extend with custom queries into getSelect function. Some info here.
Using addFieldToFilter into that foreach will filter the remaining values after another iterated filtering. So it's not good.
$allean = array("of", "ean", "values", "needed", "for", "filtering");
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ean');
//addAttributeToFilter for EAV collections
$collection->addAttributeToFilter('ean', array('in' => $allean)); //not addFieldToFilter
$collection->getColumnValues('entity_id');
var_dump($collection); //will output an array of product_ids
Alternative, if you want to group by ean values you should remove getColumnValues and run group command.
You can find additional info here.
Or you can just remove getColumnValues, start a foreach($collection as $product) and group manually or do what you want with those filtered products.

How to delete item ID from array used as session shopping cart

I have a SESSION['cart'] with ID numbers only. I have a form passing the ID with a remove button. Once passed to my controller, I cannot figure out how to write the code that uses the ID ($_POST['id']) to delete the item from the SESSION['cart'].
I can loop through and display the array contents, but I cannot figure out how to delete based on ID passed from the form.
How do I loop through the SESSION['cart'] array to find a match with the ID passed from my delete form, and then delete that ID? I know that unset($_SESSION['cart'][X] deletes the ID at index X, but I cannot figure out how to loop through all the elements to find a match.
I have read a number of related issues in this forum but have been unable to apply any of those solutions to resolve this challenge. Any assistance is appreciated.
The way you have your values ($products = array(3,7,99,152)) isn't a very good method. Every time you want to perform an action, you have to loop through the array, you don't want that. Apart from that, how do you store quantity? Or variations like e.g. size or color?
if your structure is $array[ ID_OF_PRODUCT ], you can simply do this:
unset( $_SESSION['cart'][$_POST['id']] ); // Instant access via the key!
This should be the method to use. This allows you to create an array like this, with advanced info, but with easy access (42/63 are example id's)
$_SESSION['cart']['products'][42] = array(
'quantity' = 11,
'size' = 'large',
'color' = 'blue'
);
$_SESSION['cart']['products'][63] = array(
'quantity' = 9,
'size' = 'small',
'color' = 'red'
);
This way you can access a lot of info with the product ID, and now also see which size and color (both just examples) the user selected. You may not have need for this now, but you will further down the road :)
As you might see, you can easily do stuff with the item:
isset($_SESSION['cart'][$_POST['id']]); // check if the product exists
unset($_SESSION['cart'][$_POST['id']]); // remove the product
echo $_SESSION['cart'][$_POST['id']]['quantity']; // get the quantity.
Not a loop in the code. You should only use loops when you have to, try to somewhat avoid them because often their slow. Say you have an extreme case of 1000 items in your shop, and you need to delete no999... That'll take a noticable moment.
Here is the code to do it right:
$id = $_POST['id'];
$items = $_SESSION["cart"];
if(($key = array_search($id, $items)) !== false) {
unset($items[$key]);
}
$_SESSION["cart"] = array_values($items);
Advice
Beside item ID, you can also sve item count in SESSION array because user can add several times same item into cart. In that case your $_SESSION["card"] should be structured like:
array(
'1'=>12,//Item with ID=1 is added 12 times in shopping cart
'17'=>2,//Item with ID=17 is added 2 times in shopping cart etc.
'32'=>12,
)

Accessing image field of line items in Drupal 7 module

I am creating custom emails to be sent to customers wanting to share their cart with others. So far, I have each product's quantity, SKU, price, path (node/XYZ), and title. The last item I need in the email is the product's image path.
I found all the other information with the following:
$order = commerce_cart_order_load($user->uid);
foreach($wrapper->commerce_line_items as $d => $line_item_wrapper) {
$sku = $line_item_wrapper->line_item_label->value();
//...
Printing out the following I was able to see a protected "data" property for the wrapper object:
print_r($line_item_wrapper->commerce_product);
Then, I tried finding the getter method for the field_image property with the following:
print_r($line_item_wrapper->commerce_product->getPropertyInfo('field_image');
I ended up here with entity_metadata_field_verbatim_get() but I don't know what parameters to pass. Also, in the last print statement above I didn't see anything else of value.
I'm wondering if I need to query for this data, and what table / columns to query for? Or maybe use something like node_load()? However, i'm not finding it too easy to find the node ID from the line item wrapper.
I was able to solve the above problem with this code:
$order = commerce_cart_order_load($user->uid);
$wrapper = entity_metadata_wrapper('commerce_order', $order);
$result = array();
foreach($wrapper->commerce_line_items as $d => $line_item_wrapper) {
$product = array();
$product['quantity'] = $line_item_wrapper->quantity->value();
$product['sku'] = $line_item_wrapper->line_item_label->value();
$product['path'] = $line_item_wrapper->commerce_display_path->value();
$product['price'] = $line_item_wrapper->commerce_unit_price->amount->value();
$product['title'] = $line_item_wrapper->commerce_product->title->value();
$product['image'] = $line_item_wrapper->commerce_product->field_image->value();
$product['image'] = $product['image'][0]['filename'];
array_push($result, $product);
}
I have to say, finding all these discrete functions was quite difficult. I did not find any clear documentation about Drupal Commerce metadata_wrappers. If anyone could provide further information I'd love to take a look.
In general, I used a lot of print_r(); to find these values.

Better Way to handle an ordered list of items?

I have list of items that need to be processed and printed to the user.
Each item on the list needs to have a unique set of calculations to it.
The only thing is, the user also supplies me with the order of how items will be printed & handled first - for example: item4,item2,item1,item3
How can one approach this in PHP?
I thought of running a for loop against the user submitted ordered list and tackle each calculation and print it to the user, the problem is that this will be hard to maintain because the user will have to edit the for loop each time he will want to add a new item or calculation.
Given a list of 1-n items:
$items['item1'] = $item1;
With a co-related list of 1-n functions:
$functions['item1'] = function($item) {return ...;};
You can sort items according to the user-input:
$subset = orderAndFilterItems($items, $userInput);
and then iterate:
foreach($subset as $key => $item)
{
$function = $functions[$key];
$value = $function($item);
}
Naturally you can encapsulate this further on, but it should give you the idea.

Invoicing a partial order; totals aren't updated

In our order proces it is possible to send an invoice for a partial order. So when a couple of order lines are being shipped, an invoice have to be send also.
To make this possible I use this code:
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($items);
if (!$invoice->getTotalQty()) {
Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products.'));
}
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
$invoice->register();
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($invoice)
->addObject($invoice->getOrder());
$transactionSave->save();
$invoice->sendEmail();
$invoice->setEmailSent(true);
$invoice->save();
Where the $items variable is an array containing the order ids and the amount of products to be invoiced.
The created invoice shows the correct products to be invoiced, but somehow the totals aren't updated. The totals still are the totals of the complete order, instead of the partial invoice.
I probably have to update or recalculate the totals but can't find the right code to force the update.
Anyone around who can put me in the right direction?
Well, it seems I have found the problem. The functionality as described above works manually executing it in the administrator interface. The code as enclosed above I only got to work by changing a core file of Magento.
If you change line 103 of Mage_Sales_Model_Service_Order from continue; to $qty = 0; the functionality works.
In short, this is what happens. With continue the second row item isn't added to the invoice which the invoice makes thinks the curren item is the last item of the whole order and therefore needs to invoice the complete outstanding amount. In my case the invoice I did want to invoice and the row I didn't want to invoice.
I've submitted it as issue on the Magento issue list.
Today I faced with exactly this problem, but I found a more elegant way to solve it without editing the core. The solution is to pass the products that we don't want to invoice, with 0 quantity.
In this way, the code you changed in core will act exactly like in your solution :)
As an example if I have 2 products in my order:
array(
1234 => 1,
1235 => 2
)
passing this array:
$qtys = array(
1234 => 1,
1235 => 0
)
will force this code:
// Mage_Sales_Model_Service_Order: lines 97-103
if (isset($qtys[$orderItem->getId()])) { // here's the magic
$qty = (float) $qtys[$orderItem->getId()];
} elseif (!count($qtys)) {
$qty = $orderItem->getQtyToInvoice();
} else {
continue; // the line to edit according to previous solution
}
to act exactly like in your solution, so you don't have to edit core code.
Hope it helps :)
OK - took me a bit, but now I see how to correctly create the array.
foreach ($items as $itemId => $item) {
$itemQtyToShip = $item->getQtyToShip()*1;
if ($itemQtyToShip>0) {
$itemQtyOnHand = $stockItem->getQty()*1;
if ($itemQtyOnHand>0) {
//use the order item id as key
//set the amount to invoice for as the value
$toShip[$item->getId()] = $itemQtyToShip;
} else {
//if not shipping the item set the qty to 0
$toShip[$item->getId()] = 0;
}
}
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($toShip);
This creates a proper invoice.

Categories