How to unobtrusively add new Validation methods to Magento checkout? - ajax

I want to prevent customers entering PO Boxes into the shipping address for selected Shipping Methods (UPS specifically in this case). I could override js/prototype/validation.js to insert a new validation pattern, but I don't want to fork such a key file.
Is there a mechanism to unobtrusively validate the customer's shipping address AFTER they select a shipping method via Javascript without overriding core files?
I see that Validation.add is used inside the validation.js, so it may be possible to add a new validation method outside of the core file?
The regex that I want to apply is:
\b([P|p](OST|ost)?\.?\s?[O|o|0](ffice|FFICE)?\.?\s)?([B|b][O|o|0][X|x])\s(\d+)
If the validation cannot be performed elegantly in the JS, I would be interested in an Observer on the controller_action_predispatch_onepage_saveShippingMethod that inspects the data and performs an Ajax redirect back to the shipping address form if necessary.

The library used is Really Easy Field Validation and that page does explain how to extend it. I guess you will need something like this:
Validation.add('address', 'Error message text', {
pattern : /\b([P|p](OST|ost)?\.?\s?[O|o|0](ffice|FFICE)?\.?\s)?([B|b][O|o|0][X|x])\s(\d+)/
});

As a brief look into it without debugging the checkout
# Unfortunately Magento 1.3.2.3 - Find real postcode from debugging checkout
public function saveShippingAction()
{
$this->_expireAjax();
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost('shipping', array());
$customerAddressId = $this->getRequest()->getPost('shipping_address_id', false);
$result = $this->getOnepage()->saveShipping($data, $customerAddressId);
$preg_search = '\b([P|p](OST|ost)?\.?\s?[O|o|0](ffice|FFICE)?\.?\s)?([B|b][O|o|0][X|x])\s(\d+)';
$address = $this->getQuote()->getShippingAddress(); #find real postcode
if(preg_match($preg_search, $address['postcode']){
$result = array(
'error' => 1,
'message' => Mage::helper('checkout')->__('Invalid PO Box postcode');
);
}
else{
if (!isset($result['error'])) {
$result['goto_section'] = 'shipping_method';
$result['update_section'] = array(
'name' => 'shipping-method',
'html' => $this->_getShippingMethodsHtml()
);
}
}
$this->getResponse()->setBody(Zend_Json::encode($result));
}
}

Related

How to change the weight before sending to fedex magento?

In magento checkout page, after giving billing information and shipping information, i understand that these details are sending to fedex then the shipping rates are populating in chekout page, before sending theses details to fedex, i want to change the weight of the product, i Want to add additional weights for each products,
suppose user adding a product with weight of 2 pounds, i want to send
these weight to 2*5 = 10pounds, how can i do that in magento? please
help.
Not sure to understand what you want exactly but I'll give a try.
I think you can override Mage_Checkout_OnepageController::savePaymentAction method in your local pool and in your local method, dispatch your own new event 'save_payment_action_before' and pass your objects as parameters.
In your fedex module, create an observer, get your object and change the order weight before it's sent to fedex.
To create your custom event, check this post
Finally i find out that it is happening in the sales/quote/item.php file, there is a function called setProduct, here we need to add addititonal info while setting data.
public function setProduct($product)
{
$batchQty = Mage::getModel('catalog/product')->load($product->getId())->getBatchQty();
$roleId = Mage::getSingleton('customer/session')->getCustomerGroupId();
$userrole = Mage::getSingleton('customer/group')->load($roleId)->getData('customer_group_code');
$userrole = strtolower($userrole);
if ($this->getQuote()) {
$product->setStoreId($this->getQuote()->getStoreId());
$product->setCustomerGroupId($this->getQuote()->getCustomerGroupId());
}
if($userrole=="retailer" && $batchQty>0 ){
$this->setData('product', $product)
->setProductId($product->getId())
->setProductType($product->getTypeId())
->setSku($this->getProduct()->getSku())
->setName($product->getName())
->setWeight($this->getProduct()->getWeight()*$batchQty)
->setTaxClassId($product->getTaxClassId())
->setBaseCost($product->getCost())
->setIsRecurring($product->getIsRecurring());
} else {
$this->setData('product', $product)
->setProductId($product->getId())
->setProductType($product->getTypeId())
->setSku($this->getProduct()->getSku())
->setName($product->getName())
->setWeight($this->getProduct()->getWeight())
->setTaxClassId($product->getTaxClassId())
->setBaseCost($product->getCost())
->setIsRecurring($product->getIsRecurring());
}
if ($product->getStockItem()) {
$this->setIsQtyDecimal($product->getStockItem()->getIsQtyDecimal());
}
Mage::dispatchEvent('sales_quote_item_set_product', array(
'product' => $product,
'quote_item' => $this
));
return $this;
}

Magento billing address

I am using the one page checkout module from AheadWorks and I am trying to only retrieve billing addresses from logged in members.
Currently the dropdown menu for choosing their address to bill from shows all addresses created by a logged in member. Also shipping adresses.
I would like this to only show billingaddresses. Is there a way to do so?
I already took a look inside the block which should be used, but unfortunately, I don't understand.
public function getAddressesHtmlSelect($type)
{
if ($this->isCustomerLoggedIn()) {
$options = array();
foreach ($this->getCustomer()->getAddresses() as $address) {
$options[] = array(
'value' => $address->getId(),
'label' => $address->format('oneline')
);
}
$addressDetails = Mage::getSingleton('checkout/session')->getData('aw_onestepcheckout_form_values');
if (isset($addressDetails[$type.'_address_id'])) {
if (empty($addressDetails[$type.'_address_id'])) {
$addressId = 0;
} else {
$addressId = $addressDetails[$type.'_address_id'];
}
} else {
$addressId = $this->getQuote()->getBillingAddress()->getCustomerAddressId();
}
if (empty($addressId) && $addressId !== 0) {
$address = $this->getCustomer()->getPrimaryBillingAddress();
if ($address) {
$addressId = $address->getId();
}
}
$select = $this->getLayout()->createBlock('core/html_select')
->setName($type.'_address_id')
->setId($type.'-address-select')
->setClass('address-select')
->setValue($addressId)
->setOptions($options);
return $select->getHtml();
}
return '';
}
Simple answer is no, you can't do that. In principle magento has customer entity and customer address entity. Customer address can have type which is billing or shipping but this only applies for quote and order. But when the address is saved in customer addresses it has no indication which one it is so you can use it for both steps.
Long answer. To achieve what you need you would have to extend magento customer address entity and put this division inside the entity itself. This would however require to rewrite some portion of the code which is to broad to give exact answer here.
Alternatively you could try to determine if an address is billing or shipping by going through previous orders of the user and checking which type it was there.
I was looking for this as well, here is something that I found, try it out: http://www.magebuzz.com/blog/disable-shipping-address-in-magento-checkout/

Symfony2: Questions about forms and validation

I have multistage user signup and I seem to be missing something.
I have a user entity and some other data embedded in the form which I want to collect as well. For the sake of an example we will say User has name and email and these map to fields on the user entity. On the same form I also have device data as a hidden field.
On my User entity i have a validation group 'plan' so when I submit I do something like this:
<?php
$user = new User();
$form = $this->createFormBuilder($user, array('validation_groups' => array('plan'))
->add('name')
->add('email')
->getForm();
$form->handleRequest($request)
if ($form->isValid()) {
$user = $form->getData();
$em->persist($user);
$em->flush();
} else {
return $this->render('myform.html.twig', array('form' => $form->createView()));
}
This is mostly rough psuedocode but now when I call $form->getData() or $request->request->all(), device_data is stripped out and no where to be found. I can get around this by not passing $user into createFormBuilder as the first argument but then my validation group doesn't seem to happen because it is bound to the user entity. Is there a way around this?
So it looks like the problem wasn't exactly as I descried, the correct solution which I had known beforehand is ->add('fieldname', null, array( 'mapped' => false )), however this was not working for me due to an implementation detail and using the DomCrawler.
You can then access the unmapped fields via the request object.
$request->request->get('form[fieldname]')
Andrew's answer is good but if you want to perform "direct validation" (through $form->isValid() method) you would prefer to use something like this
$form = $this->createFormBuilder($user, array('validation_groups' => array('plan'))
->add('name')
->add('email')
->add('agree','checkbox', array('mapped' => false, 'constraints' => array(new NotBlank()))
->getForm();
where agree field, for instance, that is a checkbox that you have to check like "accept terms and conditions" to move on.
mapped => false is telling to createFormBuilder to don't associate that field with an entity field as it will not be present

Magento - Indicate on credit memo whether items were returned to stock

I need to customize the Credit Memo page to store whether or not an item was returned to stock.
I've identified the Observer in:
app\code\core\Mage\CatalogInventory\Model\Observer.php
refundOrderInventory()
which gets triggered when the admin submits the credit memo with the 'Return to Stock' checkbox ticked. So I know I can add my own observer to write/save something.
But I cant figure out how to add an extra attribute to the Credit Memo product items.
Could anyone give me some pointers?
UPDATE:
I can also add the extra Returned to Stock table cell by editing:
app\design\adminhtml\default\default\template\sales\order\creditmemo\view\items.phtml
and
app\design\adminhtml\default\default\template\sales\order\creditmemo\view\items\renderer\default.phtml
To give me this:
I've hardcoded the "YES" value you see in there. I need to find some way of making this a writeable/readable credit-memo product attribute.
You will want to add the attribute and column to your creditmemo item entity, in an install script. Make sure to have your setup class to be Mage_Eav_Model_Entity_Setup as there is no addAttribute() function in Mage_Core_Model_Resource_Setup.
$installer->addAttribute('creditmemo_item', 'returned_to_stock', array('type' => 'int', 'grid' => true, 'source' => 'adminhtml/system_config_source_yesno'));
$installer->getConnection()->addColumn($installer->getTable('sales/creditmemo_item'), 'returned_to_stock', 'TINYINT(1) unsigned DEFAULT 0');
Then, in your observer (please don't modify the observer you listed there), set the value to be true, like so (I just copied the function you listed, and modified it slightly to demonstrate my point):
public function refundOrderInventory($observer)
{
$creditmemo = $observer->getEvent()->getCreditmemo();
$items = array();
foreach ($creditmemo->getAllItems() as $item) {
$return = false;
if ($item->hasBackToStock()) {
if ($item->getBackToStock() && $item->getQty()) {
$return = true;
}
} elseif (Mage::helper('cataloginventory')->isAutoReturnEnabled()) {
$return = true;
}
if ($return) {
$item->setReturnedToStock(1);
}
}
}

codeigniter uri/router checking

I am using codeigniter and have a controller in which I assign some search criteria's to be stored in session like this:
$srchCriteria = array(
'stockCode'=>$this->input->post('srchScode'),
'qty'=>$this->input->post('srchQty'),
'class' => $this->router->fetch_class(),
'method' => $this->router->fetch_method(),
);
$this->session->set_userdata('srchCriteria',$srchCriteria);
And on basis of this criteria output is generated. Now I need to clear this criteria if the user navigates to another page other than this page. i.e every time the user visits the search page the search criteria should be cleared except for pagination. For this purpose I checked the class and method variables in core controller like this:
$srchCriteria = $this->session->userdata('srchCriteria');
$className = $this->router->fetch_class();
$methodName = $this->router->fetch_method();
if(!empty( $srchCriteria['class'] ) && !empty( $srchCriteria['method'] )){
if( ($srchCriteria['method'] != $methodName){
$this->session->set_userdata('srchCriteria',array());
}
}
But it is not working please guide me in right way. What is my mistake here?
Try $this->session->unset_userdata('srchCriteria'); instead of $this->session->set_userdata('srchCriteria',array());

Resources