Magento Order History Comments: Modify Date - magento

I am creating a script to add orders programmatically in Magento. I need help to change the date of the entries in the Comments History (quote, invoice, shipping, etc.). I can manipulate the date of the order itself (setCreatedAt) and some of the comments related to the creation of the order are correct (e.g. "Sep 29, 2008 8:59:25 AM|Pending Customer Notification Not Applicable"), but I cannot change the date of the comment when I use addStatusHistoryComment...
Here's a snippet of my code:
try {
if(!$order->canInvoice()) {
Mage::throwException(Mage::helper('core')->__('Cannot create an invoice.'));
}
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
if (!$invoice->getTotalQty()) {
Mage::throwException(Mage::helper('core')->__('Cannot create an invoice without products.'));
}
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_OFFLINE);
$invoice->setCreatedAt('2008-09-23 13:05:20');
$invoice->register();
$invoice->getOrder()->setCustomerNoteNotify(true);
$invoice->getOrder()->setIsInProcess(true);
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($invoice)
- >addObject($invoice->getOrder());
$transactionSave->save();
//END Handle Invoice
//START Handle Shipment
$shipment = $order->prepareShipment();
$shipment->setCreatedAt('2008-09-23 14:20:10');
$shipment->register();
$order->setIsInProcess(true);
$order->addStatusHistoryComment('Shipping message goes here...', true);
$shipment->setEmailSent(true);
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($shipment)
->addObject($shipment->getOrder())
->save();
$track = Mage::getModel('sales/order_shipment_track')
->setShipment($shipment)
->setData('title', 'Some tracking no.')
->setData('number', '111222333444')
->setData('carrier_code', 'fedex') //custom, fedex, ups, usps, dhl
->setData('order_id', $shipment->getData('order_id'))
->save();
//END Handle Shipment
}
catch (Mage_Core_Exception $ex) {
echo "Problem creating order invoice and/or shipment: ".$ex."\n";
}
Thanks in advance.

If I understand your question correctly, you just need to do this:
$comments = $order->getStatusHistoryCollection(true);
$comments now contains a collection of all the status history comments, and you can loop over them with whatever sort of criteria you like.
foreach ($comments as $c) {
if ( /* some stuff */ ) {
$c->setData('created_at',$new_date)->save();
}
}

So this is untested, but should work:
You need to create a new method based off addStatusHistoryComment:
/app/code/core/Mage/Sales/Model/Order.php
/*
* Add a comment to order
* Different or default status may be specified
*
* #param string $comment
* #param string $status
* #return Mage_Sales_Model_Order_Status_History
*/
public function addStatusHistoryComment($comment, $status = false)
{
if (false === $status) {
$status = $this->getStatus();
} elseif (true === $status) {
$status = $this->getConfig()->getStateDefaultStatus($this->getState());
} else {
$this->setStatus($status);
}
$history = Mage::getModel('sales/order_status_history')
->setStatus($status)
->setComment($comment)
->setEntityName($this->_historyEntityName);
->setCreatedAt('2008-09-23 14:20:10'); //I added this line
$this->addStatusHistory($history);
return $history;
}
Obviously you either need to rewrite this method, or refactor the code to do the same.

Related

get the values of custom options

I'm trying to alter a price based on some custom options set. Therefore I'm trying to get the value a customer has entered, not the default values set in the backend. To do this I'm using the event catalog_product_get_final_price used in Mage_Bundle_Model_Product_Price. I have registered the following observer:
public function observer_callback($evt_obs)
{
$event = $evt_obs->getEvent();
$data = $event->getData();
/* #var $collection Mage_Catalog_Model_Resource_Product_Collection */
$collection = $data['collection'];
$items = $collection->getItems();
/* #var $item Mage_Catalog_Model_Product */
foreach ($items as $item) {
if ( $item->getName() == 'Bundel Test2') {
$options = $item->getCustomOptions();
/* #var $option Mage_Catalog_Model_Product_Option */
foreach ($options as $option) {
// Here I'm trying to get the value given by the user/customer
var_dump($option->getData());
}
}
}
return $this;
}
It is a custom option from a bundle type. So the product can't be configurable.
I'm new to magento so I'm probably missing something.
Can anyone help me?
Hope this piece of code can help you:
public function productFinalPrice($observer){
$product = $observer->getEvent()->getProduct();
$productType=$product->getTypeID();
if($productType == 'your_product_type')
{
$option = $product->getCustomOptions();
$searchedOption = null;
//search for your option;
foreach ($product->getOptions() as $o) {
if($o->getTitle()=="your_attribute_title" && $o->getType()=="your_type_of_option(eg. area"){
$optionId = $o->getOptionId();//got your searched optionId
break;
}
}
foreach($option as $key => $o) {
if($key == "option_".$optionId) {
$searchedOption = $o;
//here you get the option object with the values in it
}
}
$articleNumber = $searchedOption->getData('value'); // getthe value of your option
//calculate final price like you need it
$product->setFinalPrice($finalPrice);
}
return $this;
}
best regards

Send shipment email programmatically for the completed orders in magento

I am using magento default shipment from the admin side.
so its working fine and sending email to the customers perfectly.
I want to create one script that can send email with the shipment details for all the completed orders in magento. This will be only for certain orders coming through CSV.
My script working fine when we are using the order_id of the processing orders but its not working for the completed orders . and not sending the Order items details in the email
please suggest me any solution for it..
Thanks a lot.
I am using the below script to do so :
function completeShipment($orderIncrementId,$shipmentTrackingNumber,$shipmentCarrierCode){
$shipmentCarrierTitle = $shipmentCarrierCode;
$customerEmailComments = '';
$order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
if (!$order->getId()) {
Mage::throwException("Order does not exist, for the Shipment process to complete");
}
try {
$shipment = Mage::getModel('sales/service_order', $order)->prepareShipment(_getItemQtys($order));
$arrTracking = array(
'carrier_code' => isset($shipmentCarrierCode) ? $shipmentCarrierCode : $order->getShippingCarrier()->getCarrierCode(),
'title' => isset($shipmentCarrierTitle) ? $shipmentCarrierTitle : $order->getShippingCarrier()->getConfigData('title'),
'number' => $shipmentTrackingNumber,
);
$track = Mage::getModel('sales/order_shipment_track')->addData($arrTracking);
$shipment->addTrack($track);
$shipment->register();
_saveShipment($shipment, $order, $customerEmailComments);
}catch (Exception $e) {
throw $e;
}
return $save;
}
function _getItemQtys(Mage_Sales_Model_Order $order){
$qty = array();
foreach ($order->getAllItems() as $_eachItem) {
if ($_eachItem->getParentItemId()) {
$qty[$_eachItem->getParentItemId()] = $_eachItem->getQtyOrdered();
} else {
$qty[$_eachItem->getId()] = $_eachItem->getQtyOrdered();
}
}
return $qty;
}
function _saveShipment(Mage_Sales_Model_Order_Shipment $shipment, Mage_Sales_Model_Order $order, $customerEmailComments = ''){
$shipment->getOrder()->setIsInProcess(true);
$transactionSave = Mage::getModel('core/resource_transaction')
->addObject($shipment)->addObject($order)->save();
//$emailSentStatus = $shipment->getData('email_sent');
$ship_data = $shipment->getOrder()->getData();
$customerEmail = $ship_data['customer_email'];
$emailSentStatus = $ship_data['email_sent'];
if (!is_null($customerEmail)) {
$shipment->sendEmail(true, $customerEmailComments);
$shipment->setEmailSent(true);
}
return $this;
}
Thanks a lot dagfr...! the below code works for me to get done my task:
function completeShipment($orderIncrementId,$shipmentIncreamentId){
$order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
$ship_data = $order->getData();
$customerEmail = $ship_data['customer_email'];
$shipment = Mage::getModel('sales/order_shipment')->loadByIncrementId($shipmentIncreamentId);
$customerEmailComments = '';
$sent = 0;
if (!is_null($customerEmail)) {
$sent = $shipment->sendEmail(true, $customerEmailComments);
$shipment->setEmailSent(true);
}
return $sent;
}
Your script tries to create the shipment then send the email.
For completed orders the shipment is already created and you can't create it again, so your try fails before the email sending.
Just before :
try {
$shipment = Mage::getModel('sales/service_order', $order)->prepareShipment(_getItemQtys($order));
Check the status of the order, if it's complete, just need to get the shipment and send the mail
$shipment->sendEmail(true, $customerEmailComments);
$shipment->setEmailSent(true);
Else you can perform your script.
I found success using the order_shipment_api instead of the service_order model.
If you want to include the tracking number in the shipment email, make sure you add the tracking first and then use Mage::getModel('sales/order_shipment_api')->sendInfo($shipmentIncrementId).
Code Snippet:
$shipmentApi = Mage::getModel('sales/order_shipment_api');
//pass false for email, unless you want Magento to send the shipment email without any tracking info
//could also be written as $shipmentIncrementId = $shipmentApi->create($order->getIncrementId());
$shipmentIncrementId = $shipmentApi->create($order->getIncrementId(), array(), '' , false, 0);
//add tracking info ($shippingCarrier is case sensitive)
$shipmentApi->addTrack($shipmentIncrementId, $shippingCarrier, $shippingTitle, $trackingNumber);
//send shipment email with tracking info
$shipmentApi->sendInfo($shipmentIncrementId);
See app\code\core\Mage\Sales\Model\Order\Shipment\Api.php for all methods.
You can(should) also perform checks first:
//check for existing shipments if you want
if ($order->getShipmentsCollection()->count() == 0){
}
// and/or
if($order->canShip()){
}

Creating categories and sub-categories in Magento Extension

I am new to Magento Extension Development and wondering which is the best way to create categories and sub-categories from within an extension. The Extension I am working on is synchronizing product-data from an ERP-System. The extension is operating with a System->Configuration Dialog which holds the data for the connection to the server (user/pwd/etc.) Now I am wondering, if it is better to connect via Ajax request or use a Soap call. Ajax seems very slow in this case for about 700 Products. So what do you suggest?
Furthermore, I am a little stuck by creating categories and sub-categories. Is there simple way to do that. I found some stuff on creating a category and then use the ->move() function. Moreover I am wondering if the 'path' of the category is essential on creating sub-categories.
You should use magento models:
Create category with subcategory:
/**
* After installation system has two categories: root one with ID:1 and Default category with ID:2
*/
/** #var $category1 Mage_Catalog_Model_Category */
$category1 = Mage::getModel('catalog/category');
$category1->setName('Category 1')
->setParentId(2)
->setLevel(2)
->setAvailableSortBy('name')
->setDefaultSortBy('name')
->setIsActive(true)
->setPosition(1)
->save();
/** #var $category2 Mage_Catalog_Model_Category */
$category2 = Mage::getModel('catalog/category');
$category2->setName('Category 1.1')
->setParentId($category1->getId()) // set parent category which was created above
->setLevel(3)
->setAvailableSortBy('name')
->setDefaultSortBy('name')
->setIsActive(true)
->setIsAnchor(true)
->setPosition(1)
->save();
public static function addCatalogCategory($item, $id, $storeId = 0) {
/*
* resource for checking category exists
* http://fishpig.co.uk/blog/load-a-category-or-product-by-an-attribute.html
*/
$categories = Mage::getResourceModel('catalog/category_collection');
// Select which fields to load into the category
// * will load all fields but it is possible to pass an array of
// select fields to load
$categories->addAttributeToSelect('*');
// Ensure the category is active
$categories->addAttributeToFilter('is_active', 1);
// Add Name filter
$categories->addAttributeToFilter('name', $item->GROUP_NAME);
// Limit the collection to 1 result
$categories->setCurPage(1)->setPageSize(1);
// Load the collection
$categories->load();
if ($categories->getFirstItem()->getId()) {
$category = $categories->getFirstItem();
return $category->getId();
}
/* get category object model */
$category = Mage::getModel('catalog/category');
$category->setStoreId($storeId);
$data = array();
/* if the node is root */
if (Heliumv_Synchronization_Helper_Data::xml_attribute($item, 'type') == 'root') {
$data['category']['parent'] = 2; // 2 top level id
} else {
/* is node/leaf */
$data['category']['parent'] = $id;
}
$data['general']['path'] = $item->PARENT_ID;
$data['general']['name'] = $item->GROUP_NAME;
$data['general']['meta_title'] = "";
$data['general']['meta_description'] = "";
$data['general']['is_active'] = "1";
$data['general']['url_key'] = "";
$data['general']['display_mode'] = "PRODUCTS";
$data['general']['is_anchor'] = 0;
/* add data to category model */
$category->addData($data['general']);
if (!$category->getId()) {
$parentId = $data['category']['parent'];
if (!$parentId) {
if ($storeId) {
$parentId = Mage::app()->getStore($storeId)->getRootCategoryId();
} else {
$parentId = Mage_Catalog_Model_Category::TREE_ROOT_ID;
}
}
$parentCategory = Mage::getModel('catalog/category')->load($parentId);
$category->setPath($parentCategory->getPath());
}
$category->setAttributeSetId($category->getDefaultAttributeSetId());
try {
$category->save();
return $category->getId();
} catch (Exception $e) {
echo Mage::log($e->getMessage());
}
}
I hope this helps someone. cheers

Get Full Billing Address for Paypal Express [Magento]

The paypal module tries to map the billing information that is returned (usually nothing) from Paypal over the billing information entered by the user during the checkout process. I've fond the code that does this in NVP.php model.
/**
* Create billing and shipping addresses basing on response data
* #param array $data
*/
protected function _exportAddressses($data)
{
$address = new Varien_Object();
Varien_Object_Mapper::accumulateByMap($data, $address, $this->_billingAddressMap);
$address->setExportedKeys(array_values($this->_billingAddressMap));
$this->_applyStreetAndRegionWorkarounds($address);
$this->setExportedBillingAddress($address);
// assume there is shipping address if there is at least one field specific to shipping
if (isset($data['SHIPTONAME'])) {
$shippingAddress = clone $address;
Varien_Object_Mapper::accumulateByMap($data, $shippingAddress, $this->_shippingAddressMap);
$this->_applyStreetAndRegionWorkarounds($shippingAddress);
// PayPal doesn't provide detailed shipping name fields, so the name will be overwritten
$shippingAddress->addData(array(
'prefix' => null,
'firstname' => $data['SHIPTONAME'],
'middlename' => null,
'lastname' => null,
'suffix' => null,
));
$this->setExportedShippingAddress($shippingAddress);
}
}
/**
* Adopt specified address object to be compatible with Magento
*
* #param Varien_Object $address
*/
protected function _applyStreetAndRegionWorkarounds(Varien_Object $address)
{
// merge street addresses into 1
if ($address->hasStreet2()) {
$address->setStreet(implode("\n", array($address->getStreet(), $address->getStreet2())));
$address->unsStreet2();
}
// attempt to fetch region_id from directory
if ($address->getCountryId() && $address->getRegion()) {
$regions = Mage::getModel('directory/country')->loadByCode($address->getCountryId())->getRegionCollection()
->addRegionCodeFilter($address->getRegion())
->setPageSize(1)
;
foreach ($regions as $region) {
$address->setRegionId($region->getId());
$address->setExportedKeys(array_merge($address->getExportedKeys(), array('region_id')));
break;
}
}
}
Has anyone had any success modifying this process to get back fuller billing information. We need to be able to send "Paid" invoices to customers who pay with Paypal, so we need to capture this information.
i have hacked a workaround for that problem. It is not the cleanest way but i can save the billing address data in the order after paying with PayPal. I spent 2 days working on it and at the end i coded only a few lines. I marked my workaround with the comment #103.
Override method of class Mage_Paypal_Model_Api_Nvp:
protected function _importAddresses(array $to)
{
// Original Code
//$billingAddress = ($this->getBillingAddress()) ? $this->getBillingAddress() : $this->getAddress();
// Workaround #103
if ($this->getBillingAddress())
{
$billingAddress = $this->getBillingAddress();
}
else
{
$chkout = Mage::getSingleton('checkout/session');
$quote = $chkout->getQuote();
$billingAddress = $quote->getBillingAddress();
$billingAddress->setData($billingAddress->getOrigData());
$session = Mage::getSingleton("core/session", array("name"=>"frontend"));
$session->setData("syn_paypal_original_billing_address", serialize($billingAddress->getOrigData()));
}
$shippingAddress = $this->getAddress();
$to = Varien_Object_Mapper::accumulateByMap($billingAddress, $to, array_flip($this->_billingAddressMap));
if ($regionCode = $this->_lookupRegionCodeFromAddress($billingAddress)) {
$to['STATE'] = $regionCode;
}
if (!$this->getSuppressShipping()) {
$to = Varien_Object_Mapper::accumulateByMap($shippingAddress, $to, array_flip($this->_shippingAddressMap));
if ($regionCode = $this->_lookupRegionCodeFromAddress($shippingAddress)) {
$to['SHIPTOSTATE'] = $regionCode;
}
$this->_importStreetFromAddress($shippingAddress, $to, 'SHIPTOSTREET', 'SHIPTOSTREET2');
$this->_importStreetFromAddress($billingAddress, $to, 'STREET', 'STREET2');
$to['SHIPTONAME'] = $shippingAddress->getName();
}
$this->_applyCountryWorkarounds($to);
return $to;
}
And override method in Mage_Paypal_Model_Express_Checkout:
public function returnFromPaypal($token)
{
$this->_getApi();
$this->_api->setToken($token)
->callGetExpressCheckoutDetails();
// import billing address
$billingAddress = $this->_quote->getBillingAddress();
$exportedBillingAddress = $this->_api->getExportedBillingAddress();
// Workaround #103
$session = Mage::getSingleton("core/session", array("name"=>"frontend"));
$dataOrg = unserialize($session->getData("syn_paypal_original_billing_address"));
if (true === is_object($billingAddress))
{
foreach ($exportedBillingAddress->getExportedKeys() as $key) {
if (array_key_exists($key, $dataOrg))
{
$billingAddress->setData($key, $dataOrg[$key]);
}
}
$this->_quote->setBillingAddress($billingAddress);
}
// import shipping address
$exportedShippingAddress = $this->_api->getExportedShippingAddress();
if (!$this->_quote->getIsVirtual()) {
$shippingAddress = $this->_quote->getShippingAddress();
if ($shippingAddress) {
if ($exportedShippingAddress) {
foreach ($exportedShippingAddress->getExportedKeys() as $key) {
$shippingAddress->setDataUsingMethod($key, $exportedShippingAddress->getData($key));
}
$shippingAddress->setCollectShippingRates(true);
}
// import shipping method
$code = '';
if ($this->_api->getShippingRateCode()) {
if ($code = $this->_matchShippingMethodCode($shippingAddress, $this->_api->getShippingRateCode())) {
// possible bug of double collecting rates :-/
$shippingAddress->setShippingMethod($code)->setCollectShippingRates(true);
}
}
$this->_quote->getPayment()->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_SHIPPING_METHOD, $code);
}
}
$this->_ignoreAddressValidation();
// import payment info
$payment = $this->_quote->getPayment();
$payment->setMethod($this->_methodType);
Mage::getSingleton('paypal/info')->importToPayment($this->_api, $payment);
$payment->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_PAYER_ID, $this->_api->getPayerId())
->setAdditionalInformation(self::PAYMENT_INFO_TRANSPORT_TOKEN, $token)
;
$this->_quote->collectTotals()->save();
}

Magento unique TaxVat atrribute for every customer

.Hi,
I'm trying to make the attribute taxvat unique for every customer. (especially for users that i create from the backend). i.e no duplicates.
Just like the email attribute, if the email is already used, user gets notified to use another email.
I tried from the eav_attribute to change "is_unique" to "1" but nothing happened..
Can you please help me how to achieve this..?
Thanks
ok, i found the solution..
Find file /app/code/core/Mage/Customer/Model/Form.php (Don't forget to override instead..)
in "public function validateData(array $data)"
add the code inside the
foreach ($this->getAttributes() as $attribute)
foreach ($this->getAttributes() as $attribute) {
...
...
//## code to add
if ($attribute->getIsUnique()) {
$cid = $this->getEntity()->getData('entity_id'); //get current customer id
$cli = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToFilter($attribute->getAttributeCode(), $data[$attribute->getAttributeCode()]);
//->addFieldToFilter('customer_id', array('neq' => $cid)); //exclude current user from results //###### not working......
$flag=0;
foreach ($cli as $customer) {
$dataid=$customer->getId();
if ($dataid != $cid) //if the value is from another customer_id
$flag |= 1; //we found a dup value
}
if ($flag) {
$label = $attribute->getStoreLabel();
$errors = array_merge($errors, Mage::helper('customer')->__('"%s" already used!',$label));
}
}
//## End of code to add
}
I've modified what Karpa wrote to make it better
if ($attribute->getIsUnique()) {
$cid = $this->getEntity()->getData('entity_id'); //get current customer id
$cli = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToFilter($attribute->getAttributeCode(), $data[$attribute->getAttributeCode()])
->addFieldToFilter('entity_id', array('neq' => $cid)); //exclude current user from results //###### not working......
if (count($cli)>0) {
$label = $attribute->getStoreLabel();
$errors = array_merge($errors, array(Mage::helper('customer')->__('"%s" already used!',$label)));
}
I was looking for this solution for some time. But I noticed that the form.php file that you reference is the 1.5 version of magento. In version 1.6 the file is different ... Where to put this code in version 1.6? Thank you.
I found the file. It is in /app/code/core/Mage/Eav/Model/form.php.
But I put the code and did not work here ... I keep trying a solution.
You can create an event :
<customer_save_before>
<observers>
<mymodule_customer_save_before>
<class>mymodule/observer</class>
<method>checkUniqueAttribute</method>
</mymodule_customer_save_before>
</observers>
</customer_save_before>
And in your observer :
/**
* Check customer attribute which must be unique
*
* #param Varien_Event_Observer $observer
* #return $this
* ##see customer_save_before
*/
public function checkUniqueAttribute(Varien_Event_Observer $observer)
{
/** #var Mage_Customer_Model_Customer $customer */
$customer = $observer->getEvent()->getCustomer();
foreach ($customer->getAttributes() as $attribute) {
if ($attribute->getIsUnique()) {
$collection = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToFilter($attribute->getAttributeCode(), $customer->getData($attribute->getAttributeCode()))
->addFieldToFilter('entity_id', array('neq' => $customer->getId()));
if ($collection->getSize()) {
Mage::throwException(sprintf(
'The value %s for %s is already used',
$customer->getData($attribute->getAttributeCode()),
$attribute->getStoreLabel()
));
}
}
}
return $this;

Resources