I have created my own payment method by taking reference of another method. I wannt to store my payment gateway's transaction id to order payment details (sales/order_payment) on successful payment action.
How can I store transaction id to this table ?
1) Add an SQL install script to your module, where we will add a new attribute to the order object
$installer = new Mage_Sales_Model_Mysql4_Setup;
$attribute = array(
'type' => 'text',
'backend_type' => 'text',
'frontend_input' => 'text',
'is_user_defined' => true,
'label' => 'Transaction Code',
'visible' => true,
'required' => false,
'user_defined' => false,
'searchable' => false,
'filterable' => false,
'comparable' => false,
'default' => ''
);
$installer->addAttribute('order', 'new_transaction_id', $attribute);
$installer->endSetup();
you could then add a observer to hook the payment event, so you would need to add code to yoru config.xml to enable your observer to hook onto the event:
<events>
<sales_order_payment_pay>
<observers>
<my_observer>
<type>singleton</type>
<class>mymodule/observer</class>
<method>save_transaction</method>
</my_observer>
</observers>
</sales_order_payment_pay>
</events>
You would then add an observer model to your module:
<?php
class Company_Mymodule_Model_Observer
{
public function save_transaction($event)
{
$order = $event->getInvoice()->getOrder(); // Mage_Sales_Model_Order
/**
* You would need to have your tranaction id from your gateway
* which would depend on how you have made your module..
* ....
*/
try {
$order->setNewTransactionId($transactionId);
$order->save();
}
catch(Exception $e) {
// do something nice
}
return $this;
}
}
While the above answer works I think there may be a better way to store the information.
Add the following method to your payment modules model.
public function assignData($data)
{
if (!($data instanceof Varien_Object)) {
$data = new Varien_Object($data);
}
$info = $this->getInfoInstance();
$info->setYourCustomTransactionId($data->getYourCustomTransactionId());
return $this;
}
While this would work. I would suggest using adding another method to your payment module. setAdditionalInformation and set the data via the assignData method. I'm not sure this method is already there if your payment method is derived from another magento payment class.
public function setAdditionalInformation($key, $value)
{
if (is_object($value)) {
Mage::throwException(Mage::helper('paypal')->__('Payment transactions disallow storing objects.'));
}
$info = $this->_getData('additional_information');
if (!$info) {
$info = array();
}
$info[$key] = $value;
return $this->setData('additional_information', $info);
}
Then you would do this in assign data.
public function assignData($data)
{
if (!($data instanceof Varien_Object)) {
$data = new Varien_Object($data);
}
$info = $this->getInfoInstance();
$info->setAdditionalInformation(array(
'trans_id' => $data->getYourCustomTransactionId()
));
return $this;
}
This may not work for your implementation, but I think it might be a little cleaner way of storing the info.
In my case I've sorted this Issue doing the following:
Change the function capture() at app/code/local/SecurePay/Sxml/Model/Sxml.php to something like that:
if($approved)
{
$transaction_id = $sxml->getResult('transaction_id');
$xmlResponse = $sxml->getResult('response');
$response = simplexml_load_string(htmlspecialchars_decode($xmlResponse))->children();
$payment->setAdditionalInformation('txnID', (string) $response->Payment->TxnList->Txn->txnID);
$payment->setAdditionalInformation('purchaseOrderNo', (string) $response->Payment->TxnList->Txn->purchaseOrderNo);
$payment->setCcTransId(''.$transaction_id);
That is all.
Related
In Magento, there's a column in Product Grid/Table which is Name.
It only accepts or filter the table if you put the exact word/s.
Sample is "What Happened Last Night" (just an example)
If you put "What" it will filter correctly, if you add "Happened" it will still filter correctly but if you input "What Last" it will return 0 records unless there's a "What Last" record.
I have this code in the core itself.
$this->addColumn('name',
array(
'header'=> Mage::helper('catalog')->__('Name'),
'index' => 'name',
'filter_condition_callback' => array($this, '_customNameFilter'),
));
$store = $this->_getStore();
if ($store->getId()) {
$this->addColumn('name_search', array(
'header'=> Mage::helper('catalog')->__('Name in %s', $store->getName()),
'type' => 'text',
'filter_condition_callback' => array($this, '_customNameFilter'),
));
}
Based on this link, Grid filter for columns with complex values
I need to remove the index and adjust something or some files in which I'm totally lost as the author did not mention the file paths used.
Can anyone guide me on what file should I adjust or create if needed.
The Code above has the file path of
app\code\core\Mage\Adminhtml\Block\Catalog\Product\Grid.php
What other files/modules should I adjust an what lines of code should I'd be looking at to attain this result.
I could not thank you enough for assisting me.
here is a working solution for your case
protected function _customNameFilter($collection, $column)
{
if (!$value = $column->getFilter()->getValue()) {
return $this;
} else if (preg_match('/\s+/', $value)) {
$tokens = explode(' ', $value);
foreach($tokens as $token) {
$this->getCollection()->addAttributeToFilter($column->getData('index'), array('like' => '%'.$token.'%'));
}
} else {
$this->getCollection()->addAttributeToFilter($column->getData('index'), array('like' => '%'.$value.'%'));
}
return $this;
}
this space tokenizer filter will also work with any other grid field.
Atwix example will not solve the problem you described. If you want to make a filter smart enough to be on-the-fly tokenizer you will have to split the search string by spaces and add each token to where part of the query with "OR LIKE %'.$token.'%"
Solution
you will have to rewrite Mage_Adminhtml_Block_Catalog_Product_Grid in a local Module with following xml:
/app/code/local/Your/Module/etc/config.xml
<global>
<blocks>
<adminhtml>
<rewrite>
<catalog_product_grid>Your_Module_Block_Adminhtml_Catalog_Product_Grid</catalog_product_grid>
</rewrite>
</adminhtml>
</blocks>
</global>
and add following methods into class
/app/code/local/Your/Module/Block/Adminhtml/Catalog/Product/Grid.php
class Your_Module_Block_Adminhtml_Catalog_Product_Grid extends Mage_Adminhtml_Block_Catalog_Product_Grid {
protected function _prepareColumns()
{
$this->addColumn('name_search', array(
'header'=> Mage::helper('catalog')->__('Name in %s', $store->getName()),
'type' => 'text',
'filter_condition_callback' => array($this, '_customNameFilter'),
));
return parent::_prepareColumns();
}
protected function _customNameFilter($collection, $column)
{
if (!$value = $column->getFilter()->getValue()) {
return $this;
}
$tokens = explode(' ', $value);
$where = "LIKE '%".$value."%'";
foreach($tokens as $token) {
$where .= " OR LIKE '%".$token."%'";
}
$this->getCollection()->getSelect()->where(
"(at_name.value ?)"
, $where);
return $this;
}
}
And dont forget to rename Your_Module with your own namespace and add module description xml to /app/etc/modules/
you're welcome
I am getting my ajax callback in normal custom form, but on form alter its not working.
function sample_ajax_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if ($form_id === 'node_sampleajax_form' || $form_id === 'node_sampleajax_edit_form') {
$form['field_nametrain']= array(
'#title' => t('training name'),
'#type' => 'select',
'#options' => _load_training(),
'#required' => FALSE,
'#ajax' => [
'callback' => [$this, 'changeOptionsAjax'],
// 'callback' => '::changeOptionsAjax',
'wrapper' => 'second_field_wrapper',
],
);
$form['field_namedomain'] = [
'#type' => 'select',
'#title' => t('Domain program'),
'#options' => $this->getOptions($form_state),
'#prefix' => '<div id="second_field_wrapper">',
'#suffix' => '</div>',
];
return $form;
}
}
function _load_training() {
$training = array('- Select domain training -');
$query = db_select("node__field_trainingname", "a");
$query->fields("a", array('field_trainingname_value', 'entity_id'));
$query->orderBy("a.field_trainingname_value");
$result = $query->execute();
while($row = $result->fetchObject()){
$training[$row->entity_id] = $row->field_trainingname_value;
}
return $training;
}
function changeOptionsAjax(array &$form, FormStateInterface $form_state) {
return $form['field_namedomain'];
}
function getOptions(array &$form, FormStateInterface $form_state) {
$cvvv = $form_state->getValue('field_nametrain');
<!-- return ["shgsh", $form_state->get(['field_nametrain'])]; -->
$options = array('- Select subdomain category -');
$query = db_select("node__field_trainingname", "a");
$query->fields("a", array('field_trainingname_value', 'entity_id'));
$query = db_select("node__field_cms", "b");
$query->fields("b", array('field_cms_value', 'entity_id'));
$query->join("node__field_trainingname", "b", "b.entity_id=a.entity_id");
$query->condition("a.entity_id", $cvvv);
$result = $query->execute();
while($row = $result->fetchObject()){
$options[$row->entity_id] = $row->field_cms_value;
}
return $options;
}
On using $this->getOptions($form_state) it represent the error log it is not an object and throws website encounter error in front end. But on custom form no error came only in formalter it throws error.
Kindly suggest me ideas to apply in form_alter of Drupal 8
The .module file, where your form alter hook is located, is not a class, therefore there is no $this. Your custom form however is a class (usually in your_module/src/Form/YourForm.php), that's why it works there but not in the .module file.
Further reading: http://www.php.net/manual/en/language.oop5.basic.php
and What does the variable $this mean in PHP?
In your case you should be able to just call
'#options' => getOptions($form, $form_state),
And more on a side note: I would strongly recommend to do some code refactoring.
In your custom submit handler, firt get the form object from the form state.
$formObj = $formState->getFormObject();
then call submitForm() on the form object and pass the form and form state variables.
$formObj->submitForm($form, $formState);
and finally, you just need to simply trigger the save() function on the object.
$formObj->save($form, $formState);
So the whole solution is something like
function YOR_CUSTOM_SUBMIT_HANLDLER(array $form, FormStateInterface $form_state) {
/** #var Drupal\user\RegisterForm $entity */
$formObj = $form_state->getFormObject();
$formObj->submitForm($form, $form_state);
$formObj->save($form, $form_state);
}
I have created a custom attribute is_buyer for user which will be set to 1 after order post event.
Now I want to set 'is_buyer' to 1 for old users which have at least one order.
I can do this using foreach loop but I want to do this with a single query.
Any body knows how to write query for mentioned task using magento.
I have already written one time script using loop.
<?php
set_time_limit(0);
$customers = Mage::getModel('customer/customer')
->getCollection()
->addAttributeToSelect('entity_id')
->addAttributeToFilter(array(array('attribute' => 'is_buyer', 'null' => true)), '', 'left');
$orders = Mage::getSingleton('sales/order')->getCollection()
->addAttributeToSelect('customer_id');
foreach ($customers as $customer) {
$orders->addFieldToFilter('customer_id', $customer->getId());
if ($orders->count() > 0) {
$customer->setData('is_buyer', 1);
} else {
$customer->setData('is_buyer', 0);
}
$customer->save();
}
You can use this slow approach to set the old users one time. And use an observer
to set the customer information ad hoc for new orders. So you only need to run the above script once. You can actually do some performance tuning...save and load in foreach is bad practice, but as you only need to run the script one it might not matter...
$customers = Mage::getModel('customer/customer)->getCollection();
foreach ($customers as $_customer){
$_orders = Mage::getModel('sales/order')->getCollection()->addFieldToFilter('customer_id',$_customer->getId());
if ($_orders->count()){
$customer->setIsBuyer();
$customer->save();
}
}
The event is:
<sales_order_place_after>
<observers>
<your_observer>
<type>singleton</type>
<class>YOUR_CLASS</class>
<method>YOUR_METHOD</method>
</your_observer>
</observers>
</sales_order_place_after>
The actual observer method (proof of concept but slow):
public static function YOUR_METHOD($observer) {
$event = $observer->getEvent();
$order = $event->getOrder();
$order->getCustomerId();
$customer = Mage::getModel('customer/customer')->load($order->getCustomerId());
$customer->setIsBuyer();
$customer->save();
}
So here is installer code which can do this in one query instead of loop.
/** #var Mage_Customer_Model_Entity_Setup $setup */
$setup = $this;
$setup->startSetup();
$setup->addAttribute('customer', 'is_buyer', array(
'type' => 'int',
'input' => 'boolean',
'label' => 'Is Buyer',
'global' => 1,
'visible' => 1,
'required' => 0,
'user_defined' => 0,
'default' => '0',
'visible_on_front' => 0,
'position' => 200
));
$attributeId = $this->getAttributeId('customer', 'is_buyer');
$setup->run("
INSERT INTO customer_entity_int (`entity_type_id`, `attribute_id`, `entity_id`, `value`)
SELECT 1, {$attributeId}, c.entity_id, 1
FROM customer_entity c
WHERE c.entity_id IN (
SELECT s.customer_id FROM sales_flat_order s
WHERE s.customer_id IS NOT NULL
GROUP BY s.customer_id
)
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);
");
Because of how my application is built, I need to create event handlers for beforeSaveAssociated and afterSaveAssociated. To allow for this, I've updated AppModel.php to contain the following relevant code:
public function saveAssociated(array $data = null, array $options = array()) {
$this->after_save_options = NULL;
$event = new CakeEvent('Model.beforeSaveAssociated', $this, array(&$data, &$options));
$this->after_save_options = NULL;
$this->getEventManager()->dispatch($event);
if (parent::saveAssociated($data, $options)) {
if (is_array($this->after_save_options)) {
$curData = $this->data;
$this->data = $this->_tempData;
$event = new CakeEvent('Model.afterSaveAssociated', $this, $this->after_save_options);
$this->after_save_options = NULL;
$this->getEventManager()->dispatch($event);
$this->data = $curData;
}
if ($this->_tempData) {
$this->_tempData = FALSE;
}
return TRUE;
}
return FALSE;
}
public function implementedEvents() {
return array_merge(parent::implementedEvents(), array(
'Model.beforeSaveAssociated' => array(
'callable' => 'beforeSaveAssociated',
'passParams' => TRUE,
),
'Model.afterSaveAssociated' => array(
'callable' => 'afterSaveAssociated',
'passParams' => TRUE,
),
));
}
Although this works fine for any beforeSaveAssociated defined within a model class, whenever I define it in a behaviour, it doesn't get triggered. If I update saveAssociated above to trigger Model.beforeSave (a built-in event), it does work, so as far as I can tell, it's not an issue with the behaviour not being properly attached.
Any help is greatly appreciated,
I think this is because the BehaviorCollection is just listening to these events (taken from the class):
public function implementedEvents() {
return array(
'Model.beforeFind' => 'trigger',
'Model.afterFind' => 'trigger',
'Model.beforeValidate' => 'trigger',
'Model.afterValidate' => 'trigger',
'Model.beforeSave' => 'trigger',
'Model.afterSave' => 'trigger',
'Model.beforeDelete' => 'trigger',
'Model.afterDelete' => 'trigger'
);
}
Not the behaviors listen to the events but the collection and triggers them on behaviors. Not 100% sure about that without looking it up but I think that's how it works.
What you could try to do is to make the behavior that needs to receive these events directly to listen the event.
I think the problem is caused because the behaviors extend ModelBehavior and those classes doesn't know about the new methods you created in your AppModel
I'm creating a module that allows the user to choose the website during creating a role permission (System -> Permission -> Role -> Add New role -> Role Resource). I'm using an observer to achieve this, however I cannot get the form object.
Observer.php
class Mymodule_Mycompany_Model_Observer
{
public function appendCustomRow(Varien_Event_Observer $observer)
{
$block = $observer->getEvent()->getBlock();
if (!isset($block)) {
return $this;
}
if ($block->getType() == 'adminhtml/permissions_editroles') {
//get form instance
$form = $observer->getEvent()->getForm();
//create new custom fieldset 'website'
$fieldset = $form->addFieldset('website', array(
'legend' => 'Website Extras',
'class' => 'fieldset-wide'
)
);
//add new field
$fieldset->addField('website', 'text', array(
'name' => 'website',
'label' => Mage::helper('adminhtml')->__('Website'),
'title' => Mage::helper('adminhtml')->__('Website'),
'disabled' => false,
));
}
}
}
Mymodule/Mycompany/etc/config.xml
<adminhtml>
<events>
<core_block_abstract_prepare_layout_before>
<observers>
<Event_column_append>
<type>model</type>
<class>Mymodule_Mycompany_Model_Observer</class>
<method>appendCustomColumn</method>
</Event_column_append>
</observers>
</core_block_abstract_prepare_layout_before>
</events>
</adminhtml>
I worked it out. Here is the modified piece of code that works
public function appendCustomColumn(Varien_Event_Observer $observer)
{
$block = $observer->getEvent()->getBlock();
if (!isset($block)) {
return $this;
}
if ($block->getType() == 'adminhtml/permissions_tab_roleinfo') {
//get form instance
$form = $block->getForm();
//create new custom fieldset 'website'
$fieldset = $form->addFieldset(
'website_field',
array(
'legend' => 'Website Extras',
'class' => 'fieldset-wide'
)
);
//add new field
$fieldset->addField('website', 'text', array(
'name' => 'website',
'label' => Mage::helper('adminhtml')->__('Website'),
'title' => Mage::helper('adminhtml')->__('Website'),
'disabled' => false,
));
}
}
XML Configuration:
<events>
<adminhtml_block_html_before>
<observers>
<Event_column_append>
<type>model</type>
<class>Mymodule_Mycompany_Model_Observer</class>
<method>appendCustomColumn</method>
</Event_column_append>
</observers>
</adminhtml_block_html_before>
</events>
You need to use the event 'adminhtml_block_html_before' as the event which you were using did not even create the form object. That is why you were nt able to access the form object.
The block that is creating this form elements was 'adminhtml/permissions_tab_roleinfo'.
The method you were using was the not same one in the observer.
Hope that helps :)...
Cheers,
Swapna