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.
Related
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,
)
BACKGROUND
I have two tables in my database, CampaignList and CampaignProduct. The logic is simple, if the user successfuly purchases products I have to create one new CampaignList and CampaignProducts based for the number of products bought. These two tables will be mapped together in the future, right now I am just trying to insert them correctly.
So for example if a user successfuly buys 3 products one new table is inserted in CampaignList and 3 new tables is CampaignProduct.
Now the products are storred in session like this:
11 => 2
29 => 1
The key is the id of the product and the value is the quantity. So this session has 3 products, two products with the id of 11 and one products with the id of 29. Now for the problem and the code.
THE PROBLEM
The inserts are working correctly, except one. I need to save the quantity of the product too in the database. But this way that I am creating I dont think i can? Because I am creating tables in a different loop where the quantity is never iterated? Here is the code
THE CODE
if ($session->has('cart') && count($session->get('cart')) > 0) {
// if the session is good create the new campaign
$campaign = New CampaignList();
$campaign->setUserId($user->getId());
$campaign->setName('Karpedeal');
$campaign->setState(1);
$em->persist($campaign);
$em->flush();
foreach ($cart as $id => $quantity) {
// store the product ids in an array
$productIds[] = $id;
//get all the products based on the id array
$product = $em->getRepository('MpShopBundle:Product')->findById($productIds);
}
// for each new product create new CampaignProduct
foreach($product as $item){
$campaignProduct = New CampaignProduct();
$campaignProduct->setCampaignId($campaign->getId());
$campaignProduct->setProductId($item->getId());
$campaignProduct->setSellingPrice($item->getPrice());
$campaignProduct->setStock($item->getStockAvailable());
$campaignProduct->setReserved($quantity); // PROBLEM how to get the quantity from the session??
$em->persist($campaignProduct);
$em->flush();
}
THE OTHER WAY
The only way I think I can do is do everything in the first foreach loop, however that way I am getting an error when I try to get the ids of the products, because they are not objects, but arrays...
if ($session->has('cart') && count($session->get('cart')) > 0) {
// if the session is good create the new campaign
$campaign = New CampaignList();
$campaign->setUserId($user->getId());
$campaign->setName('Karpedeal');
$campaign->setState(1);
$em->persist($campaign);
$em->flush();
foreach ($cart as $id => $quantity) {
// store the product ids in an array
$productIds[] = $id;
//get all the products based on the id array
$product = $em->getRepository('MpShopBundle:Product')->findById($productIds);
$campaignProduct = New CampaignProduct();
$campaignProduct->setCampaignId($campaign->getId());
$campaignProduct->setProductId($product->getId()); // the error here because $product is an array not object
$campaignProduct->setSellingPrice($item->getPrice());
$campaignProduct->setStock($product->getStockAvailable());
$campaignProduct->setReserved($quantity); // PROBLEM how to get the quantity from the session??
$em->persist($campaignProduct);
$em->flush();
}
Any ideas?
By looking at your code I guess your second answer is best, but instead of getting all products with an array of product ids, just get one product every run which results in your product to be an instance of MpShopBundle:Product.
tl;dr
changing this
$product = $em->getRepository('MpShopBundle:Product')->findById($productIds);
into this
$product = $em->getRepository('MpShopBundle:Product')->find($id);
Should work
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>";
}
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.
... It's not as silly as it sounds...
I have the following code, which is used by my ajax table script to display database stuff on the page in a table.
foreach($ct->data as $key => $value){
$ct->data[$key][2]=''.$ct->data[$key][2].'';
$ct->data[$key][3]=''.$ct->data[$key][3].'';
if($ct->data[$key][4] == "" || $ct->data[$key][4] == null)
$ct->data[$key][4]='Edit Charge.';
else
$ct->data[$key][4]=''.$ct->data[$key][4].'';
$Total =$Total+ $ct->data[$key][3];
$freight =$freight+ $ct->data[$key][4];
}
And as you can see, in the foreach loop, I am trying to add up the contents of 2 columns.
The $Total column or, $ct->data[$key][3] lists the Prices for each row of products, and the $freight column does the same for each row of Freight charges.
And inside the foreach loop, I am trying to add together the total amount of prices, and Freight charges.
I'm not sure if I'm doing it the right way, because when I check the database, it just adds '0' (without the quotes). So it's not adding up!
For example, if there are a total of 3 rows in the table, and each product is 1 (dollar), it should add up to 3, right? And same goes for the $freight ones.
Can someone please tell me what I'm doing wrong here?
You are setting data[$key][3] equal to some HTML hyper link. Its not something that can be "totalled"
Is line 3 not setting the value you're adding to $Total to a string?
$ct->data[$key][3]=''.$ct->data[$key][3].'';
and then
$Total =$Total+ $ct->data[$key][3];
If you remove the first one, the second might work better.