Magento: What is the url for creating a new order for a customer and store in the admin area? - magento

I've created a button within the Admin theme, which is named 'Create order for Johnsons'
Basically on this button I want to point it to the new create order screen for customerid 3 and store 2. Something like this:
$key=Mage::getSingleton('adminhtml/url')->getSecretKey("sales_order_create","index");
echo $COUrl=Mage::helper("adminhtml")->getUrl("adminhtml/sales_order/new/",array("customer_id"=>"3","key"=>$key));
Please can anybody help me?

You don't need to specify the key, getUrl does that for you when in an admin context.
echo $this->getUrl('*/sales_order_create/start', array('customer_id' => 3));
When using start like this it wipes all parameters except customer_id so a store cannot be specified. It will respect a store_id parameter if you change the URL to */sales_order_create/index but that does not start a new order so it would be problematic. To get that to work you will have to create a new controller and action for your own use and make it almost exactly like Mage_Adminhtml_Sales_Order_CreateController::startAction():
/**
* Start order create action
*/
public function startAction()
{
Mage::getSingleton('adminhtml/session_quote')->clear();
$this->_redirect('*/sales_order_create', array(
'customer_id' => $this->getRequest()->getParam('customer_id'),
'store_id' => $this->getRequest()->getParam('store_id')
));
}

If you want to create a new customer instead of choosing one upon creating a new order you have to set customer_id as false this way:
Mage::getModel('adminhtml/session_quote')->setData('customer_id',false);
Why? Because using
$this->getUrl('*/sales_order_create/any_action_controller', array(
'customer_id' => false
));
won't help for the reason of implementation in Sales/Order/CreateController
if ($customerId = $this->getRequest()->getParam('customer_id')) {
$this->_getSession()->setCustomerId((int) $customerId);
}
As you can see there's "int" there that will convert anything you send through and we need false to be set as customer_id since otherwise Magento will create grids first.

Related

Best method to check for duplicates in store function prior to saving

I have a team-based app where one database services multiple teams. We have a custom fields table which allows for each team to create their own custom fields they want to create in addition to the global fields universally available to every team. Each custom field record has a name, type, and church_id field in the create.blade input form. Now with the nature of having separate teams, we need a system where they could create their own custom field that might share the same name of a custom field created and connected to another church team. This has been done and works just fine.
The problem is that we need to also make it so that only one custom field by a specific name can be created within the same church team. We do not want duplicate fields within the same church team. And herein lies my question, what is the best way in the store function to keep duplicates from occurring within the same team-based records. I have looked at firstOrNew, firstOrCreate, and updateOrCreate but which one is best suited to my need.
As I said, the fields we have in the form are 'name', 'type', and 'church_id' and these correspond to the custom field DB fields as 'name', 'type', and 'created_by_team_id'. What I need to have happen is for the system to check to see if there is a record matching the input 'name' that shares the same 'created_by_team_id' as the input 'church_id. If there is a record by that 'name' which also shares a marching 'id' then the system recognizes that as a duplicate and does NOT create a new record in the DB. But, if there is a record that shares the same 'name' but does not share the same 'created_by_team_id/church_id' then the system goes ahead and creates that new record because it is not a duplicate.
This is my create function:
{
if (! Gate::allows('custom_field_create')) {
return abort(401);
}
if (auth()->user()->role->contains(1)) {
$churches = Team::all();
$churchArr = array('empty' => 'Please select a church...');
foreach ($churches as $church) {
$churchArr[$church->id] = $church->name;
}
$churches->created_by_id = auth()->user()->id;
$church_id = null;
} else {
$churches = false;
$church_id = auth()->user()->team_id;
$churchArr = [];
}
return view('admin.custom_fields.create', compact('churches', 'churchArr', 'church_id'));
And this is my store function:
{
if (! Gate::allows('custom_field_create')) {
return abort(401);
}
$custom_field = CustomField::create($request->all());
$custom_field->created_by_team_id = $request->input('church_id');
$custom_field->save();
return redirect()->route('admin.custom_fields.index');
As I stated, I have been looking at and trying the firstOrNew, firstOrCreate, and updateOrCreate methods but all my attempts have been a failure. What would be the proper way to implement one of these methods to achieve my goals using my fields and DB criteria to avoid creating duplicate fields by the same name within the same team-based id?
I found the workable solution to be updateOrCreate. This allows the use of both 'name' and 'type' to be needing to be found to match. If either one is found but not the other it will create a new record. If both are found it just updates the record, which by nature avoids the duplicate creation. This allows the 'church_id' field to just added on as a filler rather than using it as one of the fields keyed on to.
$custom_field = CustomField::updateOrCreate(['name' => $request->input('name'), 'type' => $request->input('type')]);
$custom_field->created_by_team_id = $request->input('church_id');
$custom_field->save();

Laravel - Multiple models in one controller

I have the following database structure:
Enquiries
id
total_widgets
total_amount
customer_id
Customers
id,
first_name,
last_name
Using the form when you are creating an Enquiry you can enter the Customers details into the section and this will store using firstOrCreate and then get the id in order to link to Enquiry to the Customer
Now, the issue is that this is all done inside the store method within the Customers controller, like the following:
public function store(Request $request)
{
$rules = array(
"first_name" => "required",
"last_name" => "required",
"total_widgets" => "required"
);
// Handle validation
// Create customer
$customer = \App\Customers::firstOrCreate(['first_name' => $request-
>get('first_name')]);
$enquiry = new \App\Enquiries();
$enquiry->customer_id = $customer->id;
$enquiry->save();
}
The issue with doing it like this is that it's not separated out and that if the process of creating a customer changes, then I would need to change this a lot of times. (Everytime I have a section which requires a customer)..
Is there a better way to do this? For example, should the customer be created separately and then the id is passed into the $request?
Another way of doing this is :
1) In Enquiries form add button called "add new customer".
2) When you click on this button a modal will appear and then fill details click submit.
3) On clicking submit make an ajax call to Customercontroller and insert the data then return the last inserted id.
4) Now you can see the new user in drop down box(There will be some drop down for selecting the user) of enquirey form just select it and then press submit.
5) It will passed to the enquirey controller and and store it.
Hope this will help you.

Dependent Multidrop down in Yii Framework

I want to make two drop down
Select Group
Select Members (multi Drop Down)
When user select the first drop down (Group), i want to populate the Members Multidropdowen with the members of selected Group dynamically.
Select Members is a multidropdown and User can select more then One members.
I am able to accomplish dependent drop-down, or an independent Multidropdown, but i am not able to integrate these two.
I have tried the extensions http://www.yiiframework[dot]com/extension/emultiselect and http://www.yiiframework[dot]com/extension/echmultiselect.
You to implement an ajax update for the first dropdown to update the 2nd one:
echo CHtml::dropDownList('country_id','', array(1=>'USA',2=>'France',3=>'Japan'),
array(
'ajax' => array(
'type'=>'POST', //request type
'url'=>CController::createUrl('currentController/dynamiccities'), //url to call.
//Style: CController::createUrl('currentController/methodToCall')
'update'=>'#city_id', //selector to update
//'data'=>'js:javascript statement'
//leave out the data key to pass all form values through
)));
//empty since it will be filled by the other dropdown
echo CHtml::dropDownList('city_id','', array());
and in your controller you can have :
public function actionDynamiccities()
{
$data=Location::model()->findAll('parent_id=:parent_id',
array(':parent_id'=>(int) $_POST['country_id']));
$data=CHtml::listData($data,'id','name');
foreach($data as $value=>$name)
{
echo CHtml::tag('option',
array('value'=>$value),CHtml::encode($name),true);
}
}
Source:
http://www.yiiframework.com/wiki/24/

Attribute Options/Labels sorting define on Site View Level?

I using Magento 1.6.2.
Is there any way to set the position for Attribute Option Labels on a Site View Level and not on a global level?
Reason: Here the Values for Color in English and German
Black / Schwarz
Clear / Transparent
Copper / Kupfer
Yellow / Gelb
It is obvious that the sorting is different for different languages.
Overriding the position value and sorting the values in the frontpage code is not possible because there are options where alphanumeric sorting doesn't make sense:
i.e. Small Medium Large
Please help
Yes, this is very possible. But it's a fairly deep change, depending on what you would like to accomplish with this. This will get you started:
You want to first add a new column to eav/attribute_option_value table. Here is the setup script for that:
$installer = $this;
$installer->startSetup();
$installer->run("
ALTER TABLE `{$this->getTable('eav/attribute_option_value')}` ADD COLUMN `sort_order` INT UNSIGNED NULL DEFAULT 0;
");
$installer->endSetup();
Next, you need to rewrite Mage_Eav_Model_Mysql4_Entity_Attribute_Option_Collection. When performing the join for the store filter, you need to add your sort_order there:
public function setStoreFilter($storeId=null, $useDefaultValue=true)
{
if (is_null($storeId)) {
$storeId = Mage::app()->getStore()->getId();
}
$sortBy = 'store_default_value';
if ($useDefaultValue) {
$this->getSelect()
->join(array('store_default_value'=>$this->_optionValueTable),
'store_default_value.option_id=main_table.option_id',
array('default_value'=>'value'))
->joinLeft(array('store_value'=>$this->_optionValueTable),
'store_value.option_id=main_table.option_id AND '.$this->getConnection()->quoteInto('store_value.store_id=?', $storeId),
array('store_value'=>'value',
'value' => new Zend_Db_Expr('IF(store_value.value_id>0, store_value.value,store_default_value.value)',
'sort_order'))) // ADDED
->where($this->getConnection()->quoteInto('store_default_value.store_id=?', 0));
}
else {
$sortBy = 'store_value';
$this->getSelect()
->joinLeft(array('store_value'=>$this->_optionValueTable),
'store_value.option_id=main_table.option_id AND '.$this->getConnection()->quoteInto('store_value.store_id=?', $storeId),
'value',
'sort_order') // ADDED
->where($this->getConnection()->quoteInto('store_value.store_id=?', $storeId));
}
$this->setOrder("store_value.sort_order", 'ASC'); // CHANGED
return $this;
}
To show what is going on: each attribute has a source model. The source model is responsible for providing the values in a frontend dropdown-type list (select, multiselect). If the source model is Mage_Eav_Model_Entity_Attribute_Source_Table, which it will be by default if the attribute type is select or multiselect, then this code retrieves the values:
$collection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setPositionOrder('asc')
->setAttributeFilter($this->getAttribute()->getId())
->setStoreFilter($this->getAttribute()->getStoreId())
->load();
As you can see, we are rewriting the setStoreFilter() function. This is the last one called. You might want to add an unshiftOrder('main_table.sort_order', 'ASC') at the beginning of the rewritten function, just for good measure that the `main_table.sort_order does not get in the way.
I'll leave it to you to make the necessary adjustments to the admin panel to provide the option for setting the sort order matrix.

Adding a custom field to Magento's subscription module

The newsletter subscription module in Magento has only one field (email) by default. After I add an extra field to the form (say country), how can I get the form data to show up in the Magento back-end and be sent as an email to a preset recipient? Thanks.
If you want to add some custom fields for Magento newsletter subscriber (for example subscriber_name), you should do the following:
Add new column for newsletter_subscriber table
Add text input to newsletter template
Create observer for newsletter_subscriber_save_before event
In the observer you can get your custom field's value from request and assign it to subscriber's object:
public function newsletterSubscriberSave(Varien_Event_Observer $observer)
{
$subscriber = $observer->getEvent()->getSubscriber();
$name = Mage::app()->getRequest()->getParam('subscriber_name');
$subscriber->setSubscriberName($name);
return $this;
}
UPDATE:
Here is the detailed article explaining how to add Country field
Also, I have created a free module, it is available on the GitHub
There are a few things that you need to take care of to make this work:
Add a new column for your data to the appropriate database table
Make sure that Magento saves your new field to the database
Present the data in the admin backend
Record the data when you get a new newsletter subscription
Here's how you can do all those things:
Ad. 1)
Using phpMyAdmin, MySQL command line, or whatever is your preferred DB manipulation method, add a new column "country" as, say, varchar(100) to the newsletter_subscriber table.
Ad. 2)
Magento will automatically give you access to the new field through the getCountry() and setCountry() methods on the Mage_Newsletter_Model_Subscriber object. The only thing it won't do is save your field back to the DB after it has been changed with code somewhere in the system. To get it saved you need to modify _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber) function found in Mage_Newsletter_Model_Mysql4_Subscriber (app/code/core/Mage/Newsletter/Model/Mysql4/Subscriber.php). Be sure to make a local copy of the file first and not modify the core file. Here's what you need to add:
protected function _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber)
{
$data = array();
$data['customer_id'] = $subscriber->getCustomerId();
$data['store_id'] = $subscriber->getStoreId()?$subscriber->getStoreId():0;
$data['subscriber_status'] = $subscriber->getStatus();
$data['subscriber_email'] = $subscriber->getEmail();
$data['subscriber_confirm_code'] = $subscriber->getCode();
//ADD A NEW FIELD START
//note that the string index for the $data array
//must match the name of the column created in step 1
$data['country'] = $subscriber->getCountry();
//ADD A NEW FIELD END
(...)
}
Ad. 3)
You will need to modify (a local copy of) the file app/code/core/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php. The method you are looking for is called _prepareColumns(). In there you will see a series of calls to $this->addColumn(). You need to add a corresponding call for your "Country" field with the following code:
$this->addColumn('country', array(
'header' => Mage::helper('newsletter')->__('Country'),
//the index must match the name of the column created in step 1
'index' => 'country',
'default' => '----'
));
If you want the field to appear at the end of the grid (as the last column) add it as the last call, otherwise, squeeze it between the existing calls exactly where you want it to end up in the admin.
Ad. 4)
This is a part I did not have to do in my customization of the Magento newsletter, so it will be mostly theoretical. The subscription occurs in the controller located at app/code/core/Mage/Newsletter/controllers/SubscriberController.php. Here's the code of the newAction method with my proposed changes:
public function newAction()
{
if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
$session = Mage::getSingleton('core/session');
$email = (string) $this->getRequest()->getPost('email');
try {
if (!Zend_Validate::is($email, 'EmailAddress')) {
Mage::throwException($this->__('Please enter a valid email address'));
}
$status = Mage::getModel('newsletter/subscriber')->subscribe($email);
if ($status == Mage_Newsletter_Model_Subscriber::STATUS_NOT_ACTIVE) {
$session->addSuccess($this->__('Confirmation request has been sent'));
}
else {
$session->addSuccess($this->__('Thank you for your subscription'));
}
//ADD COUNTRY INFO START
//at this point we may safly assume that subscription record was created
//let's retrieve this record and add the additional data to it
$subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
//assuming that the input's id is "country"
$subscriber->setCountry((string) $this->getRequest()->getPost('country'));
//don't forget to save the subscriber!
$subscriber->save();
//ADD COUNTRY INFO END
}
catch (Mage_Core_Exception $e) {
$session->addException($e, $this->__('There was a problem with the subscription: %s', $e->getMessage()));
}
catch (Exception $e) {
$session->addException($e, $this->__('There was a problem with the subscription'));
}
}
$this->_redirectReferer();
}
Going through the above steps should take care of the most part of your problem. Let me know how that last part worked out, as I did not have a chance to test it.
Once you have your additional field in the Subscriber object you can do whatever you want with it. I did not really get what you mean by
be sent as an email to a preset recipient
If you can explain that I will try to help you out with this part too.
Edit - how to send a mail when someone subscribes
Just add the following code to the controller after the part which adds country to a subscriber object.
$mail = new Zend_Mail();
$mail->setBodyHtml("New subscriber: $email <br /><br />Country: ".$this->getRequest()->getPost('country'));
$mail->setFrom("youremail#email.com")
->addTo("admin#mysite.com")
->setSubject("Your Subject here");
$mail->send();
Adding to the accepted answer, you can also get away with this a little easier if you're adding a date, datetime, or timestamp-type column.
In my case, I wanted to add a "Subscribed at Date" to my grid. To do this, I wrote my upgrade script, column type being TIMESTAMP and the default value being CURRENT_TIMESTAMP. This way, when the row is added, the current date/time is recorded.
Then, all you have to do is add your block customizations. I'd suggest doing it by extending Magento's grid block rather than doing the local codepool override though. This way, you only need to override _prepareColumns();
Old thread but if someone has the same question, there is a free extension, that adds fields for gender, firstname and lastname and makes it available in the backend grid for export via xml/csv: http://www.magentocommerce.com/magento-connect/extended-newsletter-subscription-for-guests.html
Perhaps you can extend the code to fit your needs.
This is a warning for anyone who's installed the Ebizmarts_MailChimp extension.
It's a great extension. But it adds subscriber_firstname and subscriber_lastname to the newsletter_subscriber table.
If you intend to create these fields, you should either "require" the Ebizmarts_MailChimp extension or check the fields don't exist before your extension creates them.
In the opposite, where you've created them and want to install the the Ebizmarts_MailChimp extension after you've created these fields, you will have to comment out the addColumn code for these two fields during installation.

Resources