Override _prepareSpecificInformation method of \Magento\Payment\Block\Info\Cc class - magento2

I want to override _prepareSpecificInformation method of the Magento\Payment\Block\Info\Cc class
This is Core class.
vendor/magento/module-payment/Block/Info/Cc.php
<?php
namespace Magento\Payment\Block\Info;
/**
* Credit card generic payment info
*
* #api
* #since 100.0.2
*/
class Cc extends \Magento\Payment\Block\Info
{
protected function _prepareSpecificInformation($transport = null)
{
if (null !== $this->_paymentSpecificInformation) {
return $this->_paymentSpecificInformation;
}
$transport = parent::_prepareSpecificInformation($transport);
$data = [];
if ($ccType = $this->getCcTypeName()) {
$data[(string)__('Credit Card Type')] = $ccType;
}
if ($this->getInfo()->getCcLast4()) {
$data[(string)__('Credit Card Number')] = sprintf('xxxx-%s', $this->getInfo()->getCcLast4());
}
if (!$this->getIsSecureMode()) {
if ($ccSsIssue = $this->getInfo()->getCcSsIssue()) {
$data[(string)__('Switch/Solo/Maestro Issue Number')] = $ccSsIssue;
}
$year = $this->getInfo()->getCcSsStartYear();
$month = $this->getInfo()->getCcSsStartMonth();
if ($year && $month) {
$data[(string)__('Switch/Solo/Maestro Start Date')] = $this->_formatCardDate($year, $month);
}
}
return $transport->setData(array_merge($data, $transport->getData()));
}
Following is what I have done.
Muk/OrderEmail/etc/di.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Payment\Block\Info\Cc" type="Muk\OrderEmail\Block\Info\Cc"/>
</config>
My custom class
app/code/Muk/OrderEmail/Block/Info/Cc.php
<?php
declare(strict_types=1);
namespace Muk\OrderEmail\Block\Info;
use Magento\Framework\DataObject;
use Magento\Framework\Exception\LocalizedException;
class Cc extends \Magento\Payment\Block\Info\Cc
{
public function __construct
(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Payment\Model\Config $paymentConfig,
array $data = [])
{
parent::__construct($context, $paymentConfig, $data);
}
/**
* Prepare credit card related payment info
*
* #param DataObject|array $transport
* #return DataObject
* #throws LocalizedException
*/
protected function _prepareSpecificInformation($transport = null)
{
if (null !== $this->_paymentSpecificInformation) {
return $this->_paymentSpecificInformation;
}
$transport = parent::_prepareSpecificInformation($transport);
$data = [];
if ($ccType = $this->getCcTypeName()) {
$data[(string)__('Credit Card Type')] = $ccType;
}
if ($this->getInfo()->getCcLast4()) {
$data[(string)__('Credit Card Number')] = sprintf('xxxx-%s', $this->getInfo()->getCcLast4());
}
// Custom information
if ($ccType = $this->getCcTypeName()) {
$data[(string)__('Name on the Card:')] = $this->getInfo()->getCcOwner();
}
// End Custom information
if (!$this->getIsSecureMode()) {
if ($ccSsIssue = $this->getInfo()->getCcSsIssue()) {
$data[(string)__('Switch/Solo/Maestro Issue Number')] = $ccSsIssue;
}
$year = $this->getInfo()->getCcSsStartYear();
$month = $this->getInfo()->getCcSsStartMonth();
if ($year && $month) {
$data[(string)__('Switch/Solo/Maestro Start Date')] = $this->_formatCardDate($year, $month);
}
}
return $transport->setData(array_merge($data, $transport->getData()));
}
}
module.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Muk_OrderEmail">
<sequence>
<module name="Magento_Payment"/>
<module name="Magento_Backend"/>
<module name="Magento_Sales"/>
<module name="Magento_Quote"/>
<module name="Magento_Checkout"/>
</sequence>
</module>
</config>
registration.php
<?php
declare(strict_types=1);
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Muk_OrderEmail',
__DIR__
);
But this override is not working for me.

It turned out that I was overriding a wrong file. Because the \Magento\Payment\Block\Info\Cc was already overridden by a custom module.
After correcting the preference it worked for me.
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="VendorName\Paymetric\Block\Xiintercept\Info\Iframe" type="Muk\OrderEmail\Block\Info\Cc"/>
</config>

After investigating in this, we have found solution for this. You can not override _prepareSpecificInformation method directly because this method is overided into another class that name is Magento\Paypal\Block\Payment\Info.
You have to override this class into custom module than you can do whatever changes into function that you want do.
Please refer this content for more info:
https://itcruncher.blogspot.com/2020/11/override-preparespecificinformation.html
If you like please give kund

Related

How to render product list in my custom widget

I am creating my custom module for magento 2.3 and I've faced an issue with widget.
I have created my widget type and when I include it to homepage I have to see product list of products I've selected to render.
I want to use .../magento/vendor/magento/module-catalog/view/frontend/templates/product/list.phtml as a template
The problem is that Widget class has to Extend Magento\Framework\View\Element\Template class, and to render ProductList I have to extend Magento\Catalog\Block\Product\ListProduct.
Maybe someone could give me a piece of advice how to solve this problem.
Here is a part of my code
file my-vendor/my-module/Block/Widget/MyWidget.php
class PromotedWidget extends Template implements BlockInterface
{
public function __construct(
Context $context,
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
array $data = []
)
{
$this->productCollectionFactory = $productCollectionFactory;
parent::__construct($context, $data);
}
public function getLoadedProductCollection()
{
$collection = $this->productCollectionFactory->create();
$collection->addAttributeToSelect('*');
$collection->addAttributeToFilter('necessary_attribute', ['necessary_attribute' => 'attr_value']);
return $collection;
}
public function toHtml()
{
$this->setTemplate('Magento_Catalog::product/list.phtml');
return parent::_toHtml();
}
}
I think it is not good practice to extend Magento\Catalog\Block\Product\ListProduct class. If you want to load custom product collection and want it to work it same as product listing page, then I suggest you to create a plugin for Magento\CatalogSearch\Model\Search\IndexBuilder class in your custom widget as follows:
Namespace\Modulename\etc\di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\CatalogSearch\Model\Search\IndexBuilder">
<plugin name="Namespace_Modulename::custom_collection" type="Namespace\Modulename\Plugin\CatalogSearch\Model\Search\IndexBuilder" />
</type>
</config>
Namespace\Modulename\Plugin\CatalogSearch\Model\Search\IndexBuilder.php
<?php
namespace Namespace\Modulename\Plugin\CatalogSearch\Model\Search;
use Magento\Framework\Search\RequestInterface;
class IndexBuilder {
protected $_request;
protected $_categoryHelper;
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
\Magento\Catalog\Helper\Category $categoryHelper,
\Magento\Framework\App\Request\Http $request
) {
$this->_productCollectionFactory = $productCollectionFactory;
$this->_categoryHelper = $categoryHelper;
$this->_request = $request;
}
public function aroundBuild($subject, callable $proceed, RequestInterface $request) {
$select = $proceed($request);
$collection = $this->_productCollectionFactory->create();
$collection->addAttributeToSelect('*');
$collection->addAttributeToFilter('necessary_attribute', ['necessary_attribute' => 'attr_value']);
$getProductAllIds = $collection->getAllIds();
$productUniqueIds = array_unique($getProductAllIds);
$select->where("search_index.entity_id IN ('" . join("','", $productUniqueIds) . "')");
return $select;
}
}
In addition, you can refer this link for more details.

How to add additional attachments in the workflow?

In my document management process it is often necessary to provide some additional documents (e.g. list of comments, list of differences, some screenshot, etc).
These additional documents would be convenient to add in the Activiti forms. I would like to be able to add documents at the initiation stage of a business process and at the stage of the revise.
For this, I added an aspect with associations in the workflow-model.xml (relevant part):
...
<type name="mswf:activitiRevise">
...
<mandatory-aspects>
...
<aspect>mswf:attachments</aspect>
</mandatory-aspects>
</type>
...
<aspect name="mswf:attachments">
<associations>
<association name="mswf:package">
<source>
<mandatory>false</mandatory>
<many>true</many>
</source>
<target>
<class>cm:content</class>
<mandatory>false</mandatory>
<many>true</many>
</target>
</association>
</associations>
</aspect>
...
etc
In share-config-custom.xml I have the following (relevant part):
...
<config evaluator="task-type" condition="bpm:startTask">
<forms>
<form id="workflow-details">
<field-visibility>
...
<show id="mswf:package" />
</field-visibility>
<appearance>
...
<set id="attachments" appearance="title" label-id="Additional docs" />
<field id="mswf:package" set="attachments" />
</appearance>
</form>
<form>
<field-visibility>
<show id="mswf:package" />
...
</field-visibility>
<appearance>
<set id="attachments" appearance="title" label-id="Additional docs" />
<field id="mswf:package" set="attachments" />
...
</appearance>
</form>
</forms>
</config>
...
etc
Now I have an additional field where I can choose the appropriate documents.
It works - I added some documents and can see them at all of the stages of the document management process.
The problem occurs when I try to change a set of initially selected files. For example, when I try to add a new one. If I add a new one (or remove) - changes are not saved and in the next task, I see the same documents that were selected at the beginning.
To get control of this behavior, I developed WebScript, in which I try to manage properties. I call the WebScript from Share in the getAddedItems() method:
/**
* Returns items that have been added to the current value
*
* #method getAddedItems
* #return {array}
*/
getAddedItems: function ObjectFinder_getAddedItems() {
var addedItems = [],
currentItems = Alfresco.util.arrayToObject(this.options.currentValue.split(","));
for (var item in this.selectedItems) {
if (this.selectedItems.hasOwnProperty(item)) {
if (!(item in currentItems)) {
addedItems.push(item);
}
}
}
...
// here the call to the WebScript
return addedItems;
},
Part of my Java-backed WebScript:
...
public class WorkflowAttachmentsManipulator extends DeclarativeWebScript {
private static final String WORKFLOW_MODEL_URI = "...";
private WorkflowService workflowService;
#Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
Map<String, Object> model = new HashMap<>();
String taskId = req.getParameter("taskId");
String addedItem = req.getParameter("addedItem");
WorkflowTask workflowTask = workflowService.getTaskById(taskId);
Map<QName, Serializable> taskProperties = workflowTask.getProperties();
...
taskProperties.replace(
QName.createQName(WORKFLOW_MODEL_URI, "package"), oldValue, addedItem);
workflowService.updateTask(taskId, taskProperties, null, null);
...
I'm trying to replace the selected files with some arbitrary and the replace(...) method returns true. In alfrescotomcat-stdout.2017-09-06.log I also see that the property has been replaced:
Before calling the WebScript (two files in the package):
key: {WORKFLOW_MODEL_URI_HERE}package
value: [workspace://SpacesStore/7f980005-2a1b-49a5-a8ff-ce9dff31a98a,
workspace://SpacesStore/30d9122f-4467-451b-aeab-ca8b164f7769]
After calling the WebScript (one file in the package):
key: {WORKFLOW_MODEL_URI_HERE}package
value: workspace://SpacesStore/1a0b110f-1e09-4ca2-b367-fe25e4964a4e
After updating the form at the current task I see my new file.
But the value is not saved (lost) after revise / review and in the next task I see the same files. Let's say, the task ID for the current user was activiti$204587, then it became equals activiti$204647...
I added some debugging code to the BPMN diagram and found that the contents of mswf_package did not change after the calling the WebScript.
In 'Submit', main config:
for(var i = 0; i < mswf_package.size(); i++) {
logger.log(mswf_package.get(i).nodeRef);
}
Output:
DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/7f980005-2a1b-49a5-a8ff-ce9dff31a98a
DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/30d9122f-4467-451b-aeab-ca8b164f7769
In 'Review Task', listeners of the create and complete events:
for(var i = 0; i < mswf_package.size(); i++) {
logger.log(mswf_package.get(i).nodeRef);
}
Output:
DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/7f980005-2a1b-49a5-a8ff-ce9dff31a98a
DEBUG [repo.jscript.ScriptLogger] [http-apr-8080-exec-9] workspace://SpacesStore/30d9122f-4467-451b-aeab-ca8b164f7769
How to add additional attachments in the workflow? Is it possible?
A set of strings with NodeRefs can be passed to the following WebScript, for example:
public class WorkflowAttachmentsManipulator extends DeclarativeWebScript {
private static final String WORKFLOW_MODEL_URI = "...";
private WorkflowService workflowService;
#Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status) {
Map<String, Object> model = new HashMap<>();
String taskId = req.getParameter("taskId");
String addedItems = req.getParameter("addedItems");
String oldValue = "";
WorkflowTask workflowTask = workflowService.getTaskById(taskId);
Map<QName, Serializable> taskProperties = workflowTask.getProperties();
Iterator taskIterator = taskProperties.entrySet().iterator();
while(taskIterator.hasNext()) {
Map.Entry taskPair = (Map.Entry)taskIterator.next();
Object key = taskPair.getKey();
if(key != null &&
key.toString().equalsIgnoreCase("{" + WORKFLOW_MODEL_URI + "}package")) {
if(taskPair.getValue() != null) {
oldValue = taskPair.getValue().toString();
if(!oldValue.equals("[]")) {
oldValue = oldValue.replaceAll("[\\[\\]]", "");
addedItems = "[" + oldValue + "," + addedItems + "]";
} else {
if(addedItems.indexOf(",") > 0) {
addedItems = "[" + addedItems + "]";
}
}
}
taskProperties.replace(
QName.createQName(WORKFLOW_MODEL_URI, "package"),
oldValue,
addedItems);
workflowService.updateTask(workflowTask.getId(),
taskProperties, null, null);
break;
}
}
...
}
public WorkflowService getWorkflowService() {
return workflowService;
}
public void setWorkflowService(WorkflowService workflowService) {
this.workflowService = workflowService;
}
}
This code overrides attachments for the certain task.
Additional files need to differentiate from those that are involved in the document management process. It can be done, for example, as follows:
/**
* Returns items that have been added to the current value
*
* #method getAddedItems
* #return {array}
*/
getAddedItems: function ObjectFinder_getAddedItems() {
var addedItems = [],
currentItems = Alfresco.util.arrayToObject(this.options.currentValue.split(","));
var attachments = [];
for (var item in this.selectedItems) {
if (this.selectedItems.hasOwnProperty(item)) {
if (!(item in currentItems)) {
// modified for differentiation
if (this.options.displayMode == "items") {
attachments.push(item);
} else {
addedItems.push(item);
}
}
}
}
...
// call to the WebScript with attachments
// modified for merge
return addedItems.concat(attachments);
},
For saving the overridden attachments in the process variable it is necessary to define the listener of the complete event.
Moreover, it is possible to "pass" files by the chain from task to task (with changes) by using this technique:
Listener of the complete event:
public class TaskCompleteListener implements TaskListener {
#Override
public void notify(DelegateTask delegateTask) {
DelegateExecution execution = delegateTask.getExecution();
execution.setVariable("mswf_package", delegateTask.getVariable("mswf_package"));
}
}
Listener of the create event:
public class TaskCreateListener implements TaskListener {
#Override
public void notify(DelegateTask delegateTask) {
DelegateExecution execution = delegateTask.getExecution();
delegateTask.setVariable("mswf_package", execution.getVariable("mswf_package"));
}
}
This solved my issue.

Magento2 Export Button (CSv) in custom grid

How to add CSV export button in Custom grid in magento2. I have created a grid and form. Need to add csv export function in magento2.
create your controller
<?php
namespace Yourpackage\Yourmodule\Controller\Adminhtml\Sample;
class ExportCsv extends \Magento\Backend\App\Action
{
protected $_fileFactory;
protected $_response;
protected $_view;
protected $directory;
protected $converter;
protected $resultPageFactory ;
protected $directory_list;
public function __construct( \Magento\Backend\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
}
public function execute()
{
$fileName = 'yourfilename.csv';
$resultPage = $this->resultPageFactory ->create();
$content = $resultPage->getLayout()->getBlock('yourblockname')->getCsv();;
$this->_sendUploadResponse($fileName, $content);
}
protected function _sendUploadResponse($fileName, $content, $contentType='application/octet-stream') {
$this->_response->setHttpResponseCode(200)
->setHeader('Pragma', 'public', true)
->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true)
->setHeader('Content-type', $contentType, true)
->setHeader('Content-Length', strlen($content), true)
->setHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"', true)
->setHeader('Last-Modified', date('r'), true)
->setBody($content)
->sendResponse();
die;
}
}
create your layout xml
yourmodule_yourcontroller_exportcsv
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<update handle="yourmodule_yourcontroller_grid"/>
</page>
Just by adding this line under listingToolbar opening tag did the trick for me
<listingToolbar name="listing_top">
<exportButton name="export_button"/>
Since I couldn't found complete answers. Here is how you should proceed so you can filter data from admin grid.
Pls remove unwanted lines from execute method. I was in the middle of working on this code when I so this question
First create your UI Component
<listingToolbar name="listing_top">
<exportButton class="Magento\Ui\Component\ExportButton" component="Magento_Ui/js/grid/export" displayArea="dataGridActions">
<settings>
<options>
<option name="cvs" xsi:type="array">
<item name="value" xsi:type="string">csv</item>
<item name="label" xsi:type="string" translate="true">CSV</item>
<item name="url" xsi:type="string">controller/results/export</item>
</option>
<option name="xml" xsi:type="array">
<item name="value" xsi:type="string">xml</item>
<item name="label" xsi:type="string" translate="true">Excel XML</item>
<item name="url" xsi:type="string">skininc/results/export</item>
</option>
</options>
</settings>
</exportButton>
</listingToolbar>
Next create your controller for skininc/results/export
<?php
/**
* #category Magento 2 Module
* #package Theiconnz\Frontendflow
* #author Don Nuwinda
*/
namespace MyModule\Frontendflow\Controller\Adminhtml\Results;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\WriteInterface;
use Magento\Ui\Component\MassAction\Filter;
use Magento\Ui\Model\Export\ConvertToCsv;
use Magento\Framework\App\Response\Http\FileFactory;
use MyModule\Frontendflow\Model\ResourceModel\MyData\CollectionFactory;
class Export extends \Magento\Backend\App\Action
{
/**
* #var \Magento\Backend\Model\View\Result\ForwardFactory
*/
protected $resultForwardFactory;
/**
* Massactions filter
*
* #var Filter
*/
protected $filter;
/**
* #var MetadataProvider
*/
protected $metadataProvider;
/**
* #var WriteInterface
*/
protected $directory;
/**
* #var ConvertToCsv
*/
protected $converter;
/**
* #var FileFactory
*/
protected $fileFactory;
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory,
Filter $filter,
Filesystem $filesystem,
ConvertToCsv $converter,
FileFactory $fileFactory,
\Magento\Ui\Model\Export\MetadataProvider $metadataProvider,
\MyModule\Frontendflow\Model\ResourceModel\MyData $resource,
CollectionFactory $collectionFactory
) {
$this->resources = $resource;
$this->filter = $filter;
$this->_connection = $this->resources->getConnection();
$this->directory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
$this->metadataProvider = $metadataProvider;
$this->converter = $converter;
$this->fileFactory = $fileFactory;
parent::__construct($context);
$this->resultForwardFactory = $resultForwardFactory;
$this->collectionFactory = $collectionFactory;
}
/**
* export.
*
* #return \Magento\Backend\Model\View\Result\Forward
*/
public function execute()
{
$collection = $this->filter->getCollection($this->collectionFactory->create());
$component = $this->filter->getComponent();
$this->filter->prepareComponent($component);
$dataProvider = $component->getContext()->getDataProvider();
$dataProvider->setLimit(0, false);
$ids = [];
foreach ($collection as $document) {
$ids[] = (int)$document->getId();
}
$searchResult = $component->getContext()->getDataProvider()->getSearchResult();
$fields = $this->metadataProvider->getFields($component);
$options = $this->metadataProvider->getOptions();
$name = md5(microtime());
$file = 'export/'. $component->getName() . $name . '.csv';
$this->directory->create('export');
$stream = $this->directory->openFile($file, 'w+');
$stream->lock();
$stream->writeCsv($this->metadataProvider->getHeaders($component));
foreach ($searchResult->getItems() as $document) {
if( in_array( $document->getId(), $ids ) ) {
$this->metadataProvider->convertDate($document, $component->getName());
$stream->writeCsv($this->metadataProvider->getRowData($document, $fields, $options));
}
}
$stream->unlock();
$stream->close();
return $this->fileFactory->create('export.csv', [
'type' => 'filename',
'value' => $file,
'rm' => true // can delete file after use
], 'var');
}
}
Below Is a Default Class it only Export that Data which are show in your Admin Grid not Export your whole data
FIND in your grid column,
and add only this code in ui contactus_grid.xml or any other.
<exportButton class="Magento\Ui\Component\ExportButton" component="Magento_Ui/js/grid/export" displayArea="dataGridActions">
<settings>
<options>
<option name="csv" xsi:type="array">
<item name="value" xsi:type="string">csv</item>
<item name="label" xsi:type="string" translate="true">CSV</item>
<item name="url" xsi:type="string">mui/export/gridToCsv</item>
</option>
<option name="xml" xsi:type="array">
<item name="value" xsi:type="string">xml</item>
<item name="label" xsi:type="string" translate="true">Excel XML</item>
<item name="url" xsi:type="string">mui/export/gridToXml</item>
</option>
</options>
</settings>
</exportButton>
To Do Export in grid using UI Components in magento2
Under Container tag add following lines in ui listing component xml
<exportButton name="export_button">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="selectProvider" xsi:type="string">vendor_listing.vendor_listing.example_blog_columns.ids</item>
</item>
</argument>
</exportButton>
This will generate csv for loaded collection in grid in magento2
Below Is a Default Class it only Export that Data which are show in your Admin Grid not Export your whole data
<exportButton class="Magento\Ui\Component\ExportButton">
If you want all Data you have create a Custom Export Button that export your all data.
edit in your Ui-Component file where Admin Grid Show
[vendor_name] \ [module_name] \view\adminhtml\ui_component
Add this code to add Button into Admin Grid
Ui-ComponentFIleName.xml
<item name="buttons" xsi:type="array">
<item name="import" xsi:type="array">
<item name="name" xsi:type="string">import</item>
<item name="label" xsi:type="string" translate="true">Import</item>
<item name="class" xsi:type="string">secondary</item>
<item name="url" xsi:type="string">*/*/importdata</item>
<item name="sortOrder" xsi:type="number">20</item>
</item>
<item name="export" xsi:type="array">
<item name="name" xsi:type="string">export</item>
<item name="label" xsi:type="string" translate="true">Export</item>
<item name="class" xsi:type="string">secondary</item>
<item name="url" xsi:type="string">*/*/exportdata</item>
<item name="sortOrder" xsi:type="number">30</item>
</item>
</item>
Now create a File that Export or Import Data. File Name must be same as you define in Ui-Component file
<item name="url" xsi:type="string">*/*/exportdata</item>
<item name="url" xsi:type="string">*/*/importdata</item>
File path must be like this
[vendor_name] \ [module_name] \ Controller \ Adminhtml \ [Controller_name] \ Exportdata.php
Exportdata.php
<?php
namespace [vendor_name]\[module_name]\Controller\Adminhtml\[Controller_name];
use Magento\Framework\App\Filesystem\DirectoryList;
class Exportdata extends \Magento\Backend\App\Action
{
protected $uploaderFactory;
protected $_locationFactory;
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
\Magento\Framework\Filesystem $filesystem,
\[vendor_name]\[module_name]\Model\locatorFactory $locationFactory // This is returns Collaction of Data
) {
parent::__construct($context);
$this->_fileFactory = $fileFactory;
$this->_locationFactory = $locationFactory;
$this->directory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); // VAR Directory Path
parent::__construct($context);
}
public function execute()
{
$name = date('m-d-Y-H-i-s');
$filepath = 'export/export-data-' .$name. '.csv'; // at Directory path Create a Folder Export and FIle
$this->directory->create('export');
$stream = $this->directory->openFile($filepath, 'w+');
$stream->lock();
//column name dispay in your CSV
$columns = ['Col-1-name','Col-2-name','Col-3-name','Col-4-name','Col-5-name','Col-6-name','Col-7-name','Col-8-name','Col-9-name',];
foreach ($columns as $column)
{
$header[] = $column; //storecolumn in Header array
}
$stream->writeCsv($header);
$location = $this->_locationFactory->create();
$location_collection = $location->getCollection(); // get Collection of Table data
foreach($location_collection as $item){
$itemData = [];
// column name must same as in your Database Table
$itemData[] = $item->getData('col-1-name');
$itemData[] = $item->getData('col-2-name');
$itemData[] = $item->getData('col-3-name');
$itemData[] = $item->getData('col-4-name');
$itemData[] = $item->getData('col-5-name');
$itemData[] = $item->getData('col-6-name');
$itemData[] = $item->getData('col-7-name');
$itemData[] = $item->getData('col-8-name');
$itemData[] = $item->getData('col-9-name');
$stream->writeCsv($itemData);
}
$content = [];
$content['type'] = 'filename'; // must keep filename
$content['value'] = $filepath;
$content['rm'] = '1'; //remove csv from var folder
$csvfilename = 'locator-import-'.$name.'.csv';
return $this->_fileFactory->create($csvfilename, $content, DirectoryList::VAR_DIR);
}
}
Now you can Click on the Export Button and See your .csv file Downloaded below.
I Hope This Helps You.
create your controller
<?php
namespace Yourpackage\Yourmodule\Controller\Adminhtml\Report;
use Magento\Framework\App\Filesystem\DirectoryList;
class ExportCsv extends \Magento\Backend\App\Action {
protected $resultPageFactory;
protected $fileFactory;
/**
*
* #param \Magento\Backend\App\Action\Context $context
* #param \Magento\Framework\View\Result\PageFactory $resultPageFactory
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
$this->resultPageFactory = $resultPageFactory;
$this->fileFactory = $fileFactory;
parent::__construct($context);
}
/**
*
* #return type
*/
public function execute() {
$fileName = 'salesreport.csv';
$content = $this->_view->getLayout()->createBlock(
\Ktpl\RepresentativeReport\Block\Adminhtml\Salesdata\Grid::class
)->getCsvFile();
return $this->fileFactory->create($fileName, $content, DirectoryList::VAR_DIR);
}
}
Add CSV export button to your grid block layout (XML):
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="your.grid.container">
<block class="Yourpackage\Yourmodule\Block\Adminhtml\Sample\Grid" name="sample.grid" as="grid">
<!-- Arguments or blocks -->
<!-- Export Widget -->
<block class="Magento\Backend\Block\Widget\Grid\Export" name="sample.grid.export" as="grid.export">
<arguments>
<argument name="exportTypes" xsi:type="array">
<item name="csv" xsi:type="array">
<item name="urlPath" xsi:type="string">*/*/exportCsv</item>
<item name="label" xsi:type="string" translate="true">CSV</item>
</item>
</argument>
</arguments>
</block>
<!-- Columns block -->
</block>
</referenceBlock>
</body>
</page>
Create your controller:
<?php
namespace Yourpackage\Yourmodule\Controller\Adminhtml\Sample;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
class ExportCsv extends \Yourpackage\Yourmodule\Controller\Adminhtml\Sample
{
/**
* Export data grid to CSV format
*
* #return ResponseInterface
*/
public function execute()
{
$this->_view->loadLayout();
$fileName = 'sample_data.csv';
$content = $this->_view->getLayout()->getChildBlock('sample.grid', 'grid.export');
return $this->_fileFactory->create(
$fileName,
$content->getCsvFile($fileName),
DirectoryList::VAR_DIR
);
}
}

Credit card payment on delivery

In magento checkout page i want Credit card payment on delivery like the cash on delivery
Is anyone implemented this Credit card payment on delivery please help me
Also please provide links for reffering
Thanks in advance
Just code, yes it's possible do that.
basically you just need a model like these:
The basic structure to payment module is (i'll show example with basic payment with 1 additional information field:
Module
------->Block
------------->Form
------------------->Pay.php
------------->Info
------------------->Pay.php
------->etc
------------->config.xml
------------->system.xml
------->Model
------------->Paymentmethodmodel.php
Important things about this module:
Yourpaymentmodule_Block_Form_Pay
This block make the frontend view. The code:
<?php
class YourPaymentModule_Block_Form_Pay extends Mage_Payment_Block_Form
{
protected function _construct(){
parent::_construct();
$this->setTemplate('yourpaymentmodule/form/pay.phtml');
}
}
The other one is Yourpaymentmodule_Block_Info_Pay, this one make the view from Admin Order Details.
<?php
class YourPaymentModule_Block_Info_Pay extends Mage_Payment_Block_Info
{
protected function _construct(){
parent::_construct();
$this->setTemplate('yourpaymentmodule/form/pay.phtml');
}
protected function _prepareSpecificInformation($transport = null)
{
if (null !== $this->_paymentSpecificInformation) {
return $this->_paymentSpecificInformation;
}
$info = $this->getInfo();
$transport = new Varien_Object();
$transport = parent::_prepareSpecificInformation($transport);
$transport->addData(array(
Mage::helper('payment')->__('Additional Information') => $info->getAdditional(),
));
return $transport;
}
}
And finally on your model:
<?php
class PPaymentModuleName_Model_PaymentModuleName extends Mage_Payment_Model_Method_Abstract
{
protected $_code = 'custompaymentmodule';
protected $_formBlockType = 'custompaymentmodule/form_pay';
protected $_infoBlockType = 'custompaymentmodule/info_pay';
protected $_canUseInternal = true;
protected $_canOrder = true;
public function assignData($data)
{
if (!($data instanceof Varien_Object)) {
$data = new Varien_Object($data);
}
$info = $this->getInfoInstance();
$info->setAdditionalINformation($data->getAdditionalINformation());
return $this;
}
public function canUseForCountry($country)
{
return true;
}
public function canUseForCurrency($currencyCode){
return true;
}
}
?>
On your phtml files you make the design, just simple field or something.
Other important thing is in your etc/modules/CustomPaymentModule.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<CustomPaymentModule>
<active>true</active>
<codePool>community</codePool>
<depends>
<Mage_Payment />
</depends>
</CustomPaymentModule>
</modules>
</config>
And this is it.

Where should I locate logic related to layout in Zend Framework?

I need to customize the attributes of my body tag. Where should I locate the logic? In a Base Controller, view Helper ?
This should be the layout
<?=$this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
...
</head>
<body<?=$this->bodyAttrs?>> <!-- or <?=$this->bodyAttrs()?> -->
...
</body>
</html>
And this should be the variables declaration in controllers
class Applicant_HomeController extends Zend_Controller_Action
{
public function indexAction()
{
$this->idBody = "someId1";
$this->classesBody = array("wide","dark");
}
public function loginAction()
{
$this->idBody = "someId2";
$this->classesBody = array();
}
public function signUpAction()
{
$this->idBody = "someId3";
$this->classesBody = array("no-menu","narrow");
}
}
This is the function where the attributes are concatenated.
/**
* #param string $idBody id Attribute
* #param array $classesBody class Attribute (array of strings)
*/
protected function _makeBodyAttribs($idBody,$classesBody)
{
$id = isset($idBody)?' id="'.$idBody.'"':'';
$hasClasses = isset($classesBody)&&count($classesBody);
$class = $hasClasses?' class="'.implode(' ',$classesBody).'"':'';
return $id.$class;
}
I need the last glue code.
Got one better for ya:
<?php
class My_View_Helper_Attribs extends Zend_View_Helper_HtmlElement
{
public function attribs($attribs) {
if (!is_array($attribs)) {
return '';
}
//flatten the array for multiple values
$attribs = array_map(function($item) {
if (is_array($item) {
return implode(' ', $item)
}
return $item;
}, $attribs);
//the htmlelemnt has the build in function for the rest
return $this->_htmlAttribs($attribs)
}
}
in your controller:
public function indexAction()
{
//notice it is $this->view and not just $this
$this->view->bodyAttribs= array('id' => 'someId', 'class' => array("wide","dark"));
}
public function loginAction()
{
$this->view->bodyAttribs['id'] = "someId2";
$this->view->bodyAttribs['class'] = array();
}
in your view script:
<body <?= $this->attribs($this->bodyAtrribs) ?>>