From 01818e0987542e528e1cb11ab9f555d7a3401d41 Mon Sep 17 00:00:00 2001 From: thuanlq Date: Mon, 29 Jul 2019 20:24:01 +0700 Subject: [PATCH] add module files --- Api/Data/FileIconInterface.php | 77 ++++ Api/Data/FileIconSearchResultsInterface.php | 45 +++ Api/Data/ProductAttachmentTableInterface.php | 131 +++++++ Api/FileIconRepositoryInterface.php | 83 +++++ Api/ProductAttachmentInterface.php | 68 ++++ Block/Adminhtml/FileIcon/Edit/BackButton.php | 58 +++ .../Adminhtml/FileIcon/Edit/DeleteButton.php | 64 ++++ .../Adminhtml/FileIcon/Edit/GenericButton.php | 67 ++++ .../FileIcon/Edit/SaveAndContinueButton.php | 52 +++ Block/Adminhtml/FileIcon/Edit/SaveButton.php | 50 +++ Block/Adminhtml/ProductAttachment.php | 66 ++++ Block/Adminhtml/ProductAttachment/Edit.php | 157 ++++++++ .../Adminhtml/ProductAttachment/Edit/Form.php | 60 +++ .../ProductAttachment/Edit/Tab/Main.php | 281 ++++++++++++++ .../ProductAttachment/Edit/Tab/Products.php | 268 ++++++++++++++ .../Adminhtml/ProductAttachment/Edit/Tabs.php | 47 +++ Block/Adminhtml/ProductAttachment/Grid.php | 204 +++++++++++ .../ProductAttachment/Renderer/FileIcon.php | 83 +++++ .../Renderer/FileIconAdmin.php | 118 ++++++ Block/Attachment.php | 334 +++++++++++++++++ Block/Order/Attachment.php | 156 ++++++++ Block/Order/AttachmentItems.php | 326 +++++++++++++++++ .../ProductAttachmentLoader.php | 86 +++++ .../ProductAttachmentLoaderInterface.php | 42 +++ Controller/AbstractController/View.php | 77 ++++ Controller/Adminhtml/FileIcon.php | 62 ++++ Controller/Adminhtml/FileIcon/Delete.php | 89 +++++ Controller/Adminhtml/FileIcon/Edit.php | 90 +++++ Controller/Adminhtml/FileIcon/Index.php | 71 ++++ Controller/Adminhtml/FileIcon/InlineEdit.php | 101 ++++++ Controller/Adminhtml/FileIcon/NewAction.php | 71 ++++ Controller/Adminhtml/FileIcon/Save.php | 119 ++++++ Controller/Adminhtml/FileIcon/Upload.php | 89 +++++ Controller/Adminhtml/Index/Delete.php | 95 +++++ Controller/Adminhtml/Index/DeleteFile.php | 106 ++++++ Controller/Adminhtml/Index/Edit.php | 150 ++++++++ Controller/Adminhtml/Index/Grid.php | 47 +++ Controller/Adminhtml/Index/Index.php | 88 +++++ Controller/Adminhtml/Index/MassDelete.php | 87 +++++ Controller/Adminhtml/Index/NewAction.php | 73 ++++ .../Adminhtml/Index/PostDataProcessor.php | 87 +++++ Controller/Adminhtml/Index/Products.php | 80 ++++ Controller/Adminhtml/Index/ProductsGrid.php | 80 ++++ Controller/Adminhtml/Index/Save.php | 146 ++++++++ Controller/Index/Index.php | 80 ++++ Controller/Order/Attachment.php | 13 + Helper/Data.php | 343 ++++++++++++++++++ Model/Config/Source/Status.php | 42 +++ Model/FileIcon.php | 100 +++++ Model/FileIcon/DataProvider.php | 113 ++++++ Model/FileIconRepository.php | 190 ++++++++++ Model/ImageUploader.php | 289 +++++++++++++++ Model/ProductAttachment.php | 97 +++++ Model/ProductAttachmentTable.php | 201 ++++++++++ Model/ProductAttachmentWebApi.php | 231 ++++++++++++ Model/ResourceModel/FileIcon.php | 43 +++ Model/ResourceModel/FileIcon/Collection.php | 46 +++ Model/ResourceModel/ProductAttachment.php | 45 +++ .../ProductAttachment/Collection.php | 48 +++ Plugin/ProductGet.php | 63 ++++ README.md | 107 ++++++ Setup/InstallSchema.php | 204 +++++++++++ Ui/Component/Listing/Column/CustomerGroup.php | 82 +++++ Ui/Component/Listing/Column/Download.php | 93 +++++ Ui/Component/Listing/Column/File.php | 69 ++++ Ui/Component/Listing/Column/FileIcon.php | 98 +++++ .../Listing/Column/FileIconActions.php | 98 +++++ .../Column/ProductAttachmentActions.php | 106 ++++++ Ui/Component/Listing/Column/Status.php | 83 +++++ Ui/Component/Listing/Column/Store.php | 83 +++++ composer.json | 35 ++ etc/acl.xml | 22 ++ etc/adminhtml/menu.xml | 8 + etc/adminhtml/routes.xml | 8 + etc/adminhtml/system.xml | 37 ++ etc/config.xml | 14 + etc/di.xml | 28 ++ etc/extension_attributes.xml | 6 + etc/frontend/di.xml | 4 + etc/frontend/routes.xml | 8 + etc/module.xml | 4 + etc/webapi.xml | 39 ++ i18n/en_US.csv | 1 + registration.php | 7 + .../productattachment_fileicon_edit.xml | 9 + .../productattachment_fileicon_index.xml | 9 + .../layout/productattachment_fileicon_new.xml | 4 + .../layout/productattachment_index_edit.xml | 31 ++ .../layout/productattachment_index_index.xml | 9 + .../layout/productattachment_index_new.xml | 5 + .../productattachment_index_products.xml | 14 + .../productattachment_index_productsgrid.xml | 6 + .../productattachment_fileicon_form.xml | 84 +++++ .../productattachment_fileicon_index.xml | 121 ++++++ .../productattachment_grid_index.xml | 177 +++++++++ view/adminhtml/web/images/csv.png | Bin 0 -> 1353 bytes view/adminhtml/web/images/doc.png | Bin 0 -> 1410 bytes view/adminhtml/web/images/exe.png | Bin 0 -> 1347 bytes view/adminhtml/web/images/gif.png | Bin 0 -> 1233 bytes view/adminhtml/web/images/jpg.png | Bin 0 -> 1353 bytes view/adminhtml/web/images/mov.png | Bin 0 -> 1328 bytes view/adminhtml/web/images/mp3.png | Bin 0 -> 1302 bytes view/adminhtml/web/images/pdf.png | Bin 0 -> 1323 bytes view/adminhtml/web/images/png.png | Bin 0 -> 1299 bytes view/adminhtml/web/images/tgz.png | Bin 0 -> 1270 bytes view/adminhtml/web/images/txt.png | Bin 0 -> 1055 bytes view/adminhtml/web/images/unknown.png | Bin 0 -> 542 bytes view/adminhtml/web/images/zip.png | Bin 0 -> 1270 bytes .../web/template/grid/cells/thumbnail.html | 1 + .../adminhtml/web/template/image-preview.html | 29 ++ view/frontend/layout/catalog_product_view.xml | 15 + .../productattachment_order_attachment.xml | 39 ++ ...tattachment_order_attachment_renderers.xml | 14 + .../layout/sales_order_info_links.xml | 21 ++ view/frontend/templates/attachment.phtml | 34 ++ .../frontend/templates/order/attachment.phtml | 13 + .../templates/order/attachment_items.phtml | 44 +++ view/frontend/templates/order/items.phtml | 53 +++ view/frontend/web/images/csv.png | Bin 0 -> 1293 bytes view/frontend/web/images/doc.png | Bin 0 -> 473 bytes view/frontend/web/images/gif.png | Bin 0 -> 708 bytes view/frontend/web/images/jpg.png | Bin 0 -> 942 bytes view/frontend/web/images/link.png | Bin 0 -> 677 bytes view/frontend/web/images/mov.png | Bin 0 -> 658 bytes view/frontend/web/images/pdf.png | Bin 0 -> 1006 bytes view/frontend/web/images/png.png | Bin 0 -> 677 bytes view/frontend/web/images/tgz.png | Bin 0 -> 1293 bytes view/frontend/web/images/txt.png | Bin 0 -> 425 bytes view/frontend/web/images/unknown.png | Bin 0 -> 344 bytes view/frontend/web/images/xls.png | Bin 0 -> 1263 bytes view/frontend/web/images/zip.png | Bin 0 -> 1293 bytes 131 files changed, 8651 insertions(+) create mode 100644 Api/Data/FileIconInterface.php create mode 100644 Api/Data/FileIconSearchResultsInterface.php create mode 100644 Api/Data/ProductAttachmentTableInterface.php create mode 100644 Api/FileIconRepositoryInterface.php create mode 100644 Api/ProductAttachmentInterface.php create mode 100644 Block/Adminhtml/FileIcon/Edit/BackButton.php create mode 100644 Block/Adminhtml/FileIcon/Edit/DeleteButton.php create mode 100644 Block/Adminhtml/FileIcon/Edit/GenericButton.php create mode 100644 Block/Adminhtml/FileIcon/Edit/SaveAndContinueButton.php create mode 100644 Block/Adminhtml/FileIcon/Edit/SaveButton.php create mode 100644 Block/Adminhtml/ProductAttachment.php create mode 100644 Block/Adminhtml/ProductAttachment/Edit.php create mode 100644 Block/Adminhtml/ProductAttachment/Edit/Form.php create mode 100644 Block/Adminhtml/ProductAttachment/Edit/Tab/Main.php create mode 100644 Block/Adminhtml/ProductAttachment/Edit/Tab/Products.php create mode 100644 Block/Adminhtml/ProductAttachment/Edit/Tabs.php create mode 100644 Block/Adminhtml/ProductAttachment/Grid.php create mode 100644 Block/Adminhtml/ProductAttachment/Renderer/FileIcon.php create mode 100644 Block/Adminhtml/ProductAttachment/Renderer/FileIconAdmin.php create mode 100644 Block/Attachment.php create mode 100644 Block/Order/Attachment.php create mode 100644 Block/Order/AttachmentItems.php create mode 100644 Controller/AbstractController/ProductAttachmentLoader.php create mode 100644 Controller/AbstractController/ProductAttachmentLoaderInterface.php create mode 100644 Controller/AbstractController/View.php create mode 100644 Controller/Adminhtml/FileIcon.php create mode 100644 Controller/Adminhtml/FileIcon/Delete.php create mode 100644 Controller/Adminhtml/FileIcon/Edit.php create mode 100644 Controller/Adminhtml/FileIcon/Index.php create mode 100644 Controller/Adminhtml/FileIcon/InlineEdit.php create mode 100644 Controller/Adminhtml/FileIcon/NewAction.php create mode 100644 Controller/Adminhtml/FileIcon/Save.php create mode 100644 Controller/Adminhtml/FileIcon/Upload.php create mode 100644 Controller/Adminhtml/Index/Delete.php create mode 100644 Controller/Adminhtml/Index/DeleteFile.php create mode 100644 Controller/Adminhtml/Index/Edit.php create mode 100644 Controller/Adminhtml/Index/Grid.php create mode 100644 Controller/Adminhtml/Index/Index.php create mode 100644 Controller/Adminhtml/Index/MassDelete.php create mode 100644 Controller/Adminhtml/Index/NewAction.php create mode 100644 Controller/Adminhtml/Index/PostDataProcessor.php create mode 100644 Controller/Adminhtml/Index/Products.php create mode 100644 Controller/Adminhtml/Index/ProductsGrid.php create mode 100644 Controller/Adminhtml/Index/Save.php create mode 100644 Controller/Index/Index.php create mode 100644 Controller/Order/Attachment.php create mode 100644 Helper/Data.php create mode 100644 Model/Config/Source/Status.php create mode 100644 Model/FileIcon.php create mode 100644 Model/FileIcon/DataProvider.php create mode 100644 Model/FileIconRepository.php create mode 100644 Model/ImageUploader.php create mode 100644 Model/ProductAttachment.php create mode 100644 Model/ProductAttachmentTable.php create mode 100644 Model/ProductAttachmentWebApi.php create mode 100644 Model/ResourceModel/FileIcon.php create mode 100644 Model/ResourceModel/FileIcon/Collection.php create mode 100644 Model/ResourceModel/ProductAttachment.php create mode 100644 Model/ResourceModel/ProductAttachment/Collection.php create mode 100644 Plugin/ProductGet.php create mode 100644 README.md create mode 100644 Setup/InstallSchema.php create mode 100644 Ui/Component/Listing/Column/CustomerGroup.php create mode 100644 Ui/Component/Listing/Column/Download.php create mode 100644 Ui/Component/Listing/Column/File.php create mode 100644 Ui/Component/Listing/Column/FileIcon.php create mode 100644 Ui/Component/Listing/Column/FileIconActions.php create mode 100644 Ui/Component/Listing/Column/ProductAttachmentActions.php create mode 100644 Ui/Component/Listing/Column/Status.php create mode 100644 Ui/Component/Listing/Column/Store.php create mode 100644 composer.json create mode 100644 etc/acl.xml create mode 100644 etc/adminhtml/menu.xml create mode 100644 etc/adminhtml/routes.xml create mode 100644 etc/adminhtml/system.xml create mode 100644 etc/config.xml create mode 100644 etc/di.xml create mode 100644 etc/extension_attributes.xml create mode 100644 etc/frontend/di.xml create mode 100644 etc/frontend/routes.xml create mode 100644 etc/module.xml create mode 100644 etc/webapi.xml create mode 100644 i18n/en_US.csv create mode 100644 registration.php create mode 100644 view/adminhtml/layout/productattachment_fileicon_edit.xml create mode 100644 view/adminhtml/layout/productattachment_fileicon_index.xml create mode 100644 view/adminhtml/layout/productattachment_fileicon_new.xml create mode 100644 view/adminhtml/layout/productattachment_index_edit.xml create mode 100644 view/adminhtml/layout/productattachment_index_index.xml create mode 100644 view/adminhtml/layout/productattachment_index_new.xml create mode 100644 view/adminhtml/layout/productattachment_index_products.xml create mode 100644 view/adminhtml/layout/productattachment_index_productsgrid.xml create mode 100644 view/adminhtml/ui_component/productattachment_fileicon_form.xml create mode 100644 view/adminhtml/ui_component/productattachment_fileicon_index.xml create mode 100644 view/adminhtml/ui_component/productattachment_grid_index.xml create mode 100644 view/adminhtml/web/images/csv.png create mode 100644 view/adminhtml/web/images/doc.png create mode 100644 view/adminhtml/web/images/exe.png create mode 100644 view/adminhtml/web/images/gif.png create mode 100644 view/adminhtml/web/images/jpg.png create mode 100644 view/adminhtml/web/images/mov.png create mode 100644 view/adminhtml/web/images/mp3.png create mode 100644 view/adminhtml/web/images/pdf.png create mode 100644 view/adminhtml/web/images/png.png create mode 100644 view/adminhtml/web/images/tgz.png create mode 100644 view/adminhtml/web/images/txt.png create mode 100644 view/adminhtml/web/images/unknown.png create mode 100644 view/adminhtml/web/images/zip.png create mode 100644 view/adminhtml/web/template/grid/cells/thumbnail.html create mode 100644 view/adminhtml/web/template/image-preview.html create mode 100644 view/frontend/layout/catalog_product_view.xml create mode 100644 view/frontend/layout/productattachment_order_attachment.xml create mode 100644 view/frontend/layout/productattachment_order_attachment_renderers.xml create mode 100644 view/frontend/layout/sales_order_info_links.xml create mode 100644 view/frontend/templates/attachment.phtml create mode 100644 view/frontend/templates/order/attachment.phtml create mode 100644 view/frontend/templates/order/attachment_items.phtml create mode 100644 view/frontend/templates/order/items.phtml create mode 100644 view/frontend/web/images/csv.png create mode 100644 view/frontend/web/images/doc.png create mode 100644 view/frontend/web/images/gif.png create mode 100644 view/frontend/web/images/jpg.png create mode 100644 view/frontend/web/images/link.png create mode 100644 view/frontend/web/images/mov.png create mode 100644 view/frontend/web/images/pdf.png create mode 100644 view/frontend/web/images/png.png create mode 100644 view/frontend/web/images/tgz.png create mode 100644 view/frontend/web/images/txt.png create mode 100644 view/frontend/web/images/unknown.png create mode 100644 view/frontend/web/images/xls.png create mode 100644 view/frontend/web/images/zip.png diff --git a/Api/Data/FileIconInterface.php b/Api/Data/FileIconInterface.php new file mode 100644 index 0000000..e7a4e80 --- /dev/null +++ b/Api/Data/FileIconInterface.php @@ -0,0 +1,77 @@ + __('Back'), + 'on_click' => sprintf("location.href = '%s';", $this->getBackUrl()), + 'class' => 'back', + 'sort_order' => 10 + ]; + } + + /** + * Get URL for back (reset) button + * + * @return string + */ + public function getBackUrl() + { + return $this->getUrl('*/*/'); + } +} diff --git a/Block/Adminhtml/FileIcon/Edit/DeleteButton.php b/Block/Adminhtml/FileIcon/Edit/DeleteButton.php new file mode 100644 index 0000000..c8b5773 --- /dev/null +++ b/Block/Adminhtml/FileIcon/Edit/DeleteButton.php @@ -0,0 +1,64 @@ +getModelId()) { + $data = [ + 'label' => __('Delete File Icon'), + 'class' => 'delete', + 'on_click' => 'deleteConfirm(\'' . __( + 'Are you sure you want to do this?' + ) . '\', \'' . $this->getDeleteUrl() . '\')', + 'sort_order' => 20, + ]; + } + return $data; + } + + /** + * Get URL for delete button + * + * @return string + */ + public function getDeleteUrl() + { + return $this->getUrl('*/*/delete', ['fileicon_id' => $this->getModelId()]); + } +} diff --git a/Block/Adminhtml/FileIcon/Edit/GenericButton.php b/Block/Adminhtml/FileIcon/Edit/GenericButton.php new file mode 100644 index 0000000..32a54f3 --- /dev/null +++ b/Block/Adminhtml/FileIcon/Edit/GenericButton.php @@ -0,0 +1,67 @@ +context = $context; + } + + /** + * Return model ID + * + * @return int|null + */ + public function getModelId() + { + return $this->context->getRequest()->getParam('fileicon_id'); + } + + /** + * Generate url by route and parameters + * + * @param string $route + * @param array $params + * @return string + */ + public function getUrl($route = '', $params = []) + { + return $this->context->getUrlBuilder()->getUrl($route, $params); + } +} diff --git a/Block/Adminhtml/FileIcon/Edit/SaveAndContinueButton.php b/Block/Adminhtml/FileIcon/Edit/SaveAndContinueButton.php new file mode 100644 index 0000000..77e331a --- /dev/null +++ b/Block/Adminhtml/FileIcon/Edit/SaveAndContinueButton.php @@ -0,0 +1,52 @@ + __('Save and Continue Edit'), + 'class' => 'save', + 'data_attribute' => [ + 'mage-init' => [ + 'button' => ['event' => 'saveAndContinueEdit'], + ], + ], + 'sort_order' => 80, + ]; + } +} diff --git a/Block/Adminhtml/FileIcon/Edit/SaveButton.php b/Block/Adminhtml/FileIcon/Edit/SaveButton.php new file mode 100644 index 0000000..00ba086 --- /dev/null +++ b/Block/Adminhtml/FileIcon/Edit/SaveButton.php @@ -0,0 +1,50 @@ + __('Save File Icon'), + 'class' => 'save primary', + 'data_attribute' => [ + 'mage-init' => ['button' => ['event' => 'save']], + 'form-role' => 'save', + ], + 'sort_order' => 90, + ]; + } +} diff --git a/Block/Adminhtml/ProductAttachment.php b/Block/Adminhtml/ProductAttachment.php new file mode 100644 index 0000000..02ffbca --- /dev/null +++ b/Block/Adminhtml/ProductAttachment.php @@ -0,0 +1,66 @@ +_controller = 'adminhtml_productattach'; + $this->_blockGroup = 'Ecomteck_ProductAttachment'; + $this->_headerText = __('Product Attachments'); + $this->_addButtonLabel = __('Add New Attachment'); + parent::_construct(); + if ($this->_isAllowedAction('Ecomteck_ProductAttachment::save')) { + $this->buttonList->update('add', 'label', __('Add New Attachment')); + } else { + $this->buttonList->remove('add'); + } + } + + /** + * Check permission for passed action + * + * @param string $resourceId + * @return bool + */ + public function _isAllowedAction($resourceId) + { + return $this->_authorization->isAllowed($resourceId); + } +} diff --git a/Block/Adminhtml/ProductAttachment/Edit.php b/Block/Adminhtml/ProductAttachment/Edit.php new file mode 100644 index 0000000..ad9cb61 --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Edit.php @@ -0,0 +1,157 @@ +_coreRegistry = $registry; + parent::__construct($context, $data); + } + + /** + * Initialize cms page edit block + * + * @return void + */ + protected function _construct() + { + $this->_objectId = 'productattach_id'; + $this->_blockGroup = 'Ecomteck_ProductAttachment'; + $this->_controller = 'adminhtml_productAttachment'; + + parent::_construct(); + + if ($this->_isAllowedAction('Ecomteck_ProductAttachment::save')) { + $this->buttonList->update('save', 'label', __('Save Attachment')); + $this->buttonList->add( + 'saveandcontinue', + [ + 'label' => __('Save and Continue Edit'), + 'class' => 'save', + 'data_attribute' => [ + 'mage-init' => [ + 'button' => ['event' => 'saveAndContinueEdit', 'target' => '#edit_form'], + ], + ] + ], + -100 + ); + } else { + $this->buttonList->remove('save'); + } + + if ($this->_isAllowedAction('Ecomteck_ProductAttachment::delete')) { + $this->buttonList->update('delete', 'label', __('Delete Product Attachment')); + } else { + $this->buttonList->remove('delete'); + } + } + + /** + * Retrieve text for header element depending on loaded page + * + * @return string + */ + public function getHeaderText() + { + if ($this->_coreRegistry->registry('productattachment')->getId()) { + return __( + "Edit Product Attachment '%1'", + $this->escapeHtml($this->_coreRegistry->registry('productattachment')->getTitle()) + ); + } else { + return __('New Product Attachment'); + } + } + + /** + * Check permission for passed action + * + * @param string $resourceId + * @return bool + */ + public function _isAllowedAction($resourceId) + { + return $this->_authorization->isAllowed($resourceId); + } + + /** + * Getter of url for "Save and Continue" button + * tab_id will be replaced by desired by JS later + * + * @return string + */ + public function _getSaveAndContinueUrl() + { + return $this->getUrl( + 'productattachment/*/save', + ['_current' => true, 'back' => 'edit', 'active_tab' => '{{tab_id}}'] + ); + } + + /** + * Prepare layout + * + * @return \Magento\Framework\View\Element\AbstractBlock + */ + public function _prepareLayout() + { + $this->_formScripts[] = " + function toggleEditor() { + if (tinyMCE.getInstanceById('page_content') == null) { + tinyMCE.execCommand('mceAddControl', false, 'page_content'); + } else { + tinyMCE.execCommand('mceRemoveControl', false, 'page_content'); + } + }; + "; + return parent::_prepareLayout(); + } +} diff --git a/Block/Adminhtml/ProductAttachment/Edit/Form.php b/Block/Adminhtml/ProductAttachment/Edit/Form.php new file mode 100644 index 0000000..346d6a5 --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Edit/Form.php @@ -0,0 +1,60 @@ +_formFactory->create( + [ + 'data' => [ + 'id' => 'edit_form', + 'action' => $this->getData('action'), + 'method' => 'post', + 'enctype' => 'multipart/form-data' + ] + ] + ); + $form->setUseContainer(true); + $this->setForm($form); + return parent::_prepareForm(); + } +} diff --git a/Block/Adminhtml/ProductAttachment/Edit/Tab/Main.php b/Block/Adminhtml/ProductAttachment/Edit/Tab/Main.php new file mode 100644 index 0000000..b812f98 --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Edit/Tab/Main.php @@ -0,0 +1,281 @@ +systemStore = $systemStore; + $this->customerCollection = $customerCollection; + parent::__construct($context, $registry, $formFactory, $data); + } + + /** + * Prepare form + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function _prepareForm() + { + + $model = $this->_coreRegistry->registry('productattach'); + + /* + * Checking if user have permissions to save information + */ + if ($this->_isAllowedAction('Ecomteck_ProductAttachment::save')) { + $isElementDisabled = false; + } else { + $isElementDisabled = true; + } + + /** @var \Magento\Framework\Data\Form $form */ + $form = $this->_formFactory->create(); + + $form->setHtmlIdPrefix('productattachment_main_'); + + $fieldset = $form->addFieldset( + 'base_fieldset', + ['legend' => __('Attachment Information')] + ); + + $customerGroup = $this->customerCollection->toOptionArray(); + + if ($model->getId()) { + $fieldset->addField('productattach_id', 'hidden', ['name' => 'productattach_id']); + } + + $fieldset->addField( + 'name', + 'text', + [ + 'name' => 'name', + 'label' => __('Attachment Name'), + 'title' => __('Attachment Name'), + 'required' => true, + 'disabled' => $isElementDisabled + ] + ); + + $fieldset->addField( + 'description', + 'textarea', + [ + 'name' => 'description', + 'label' => __('Description'), + 'title' => __('Description'), + 'disabled' => $isElementDisabled + ] + ); + + $fieldset->addField( + 'files', + 'file', + [ + 'name' => 'file', + 'label' => __('File'), + 'title' => __('File'), + 'required' => false, + 'note' => 'File size must be less than 5 Mb.', // TODO: show ACCTUAL file-size + 'disabled' => $isElementDisabled + ] + ); + + $fieldset->addType( + 'uploadedfile', + \Ecomteck\ProductAttachment\Block\Adminhtml\ProductAttachment\Renderer\FileIconAdmin::class + ); + + $fieldset->addField( + 'file', + 'uploadedfile', + [ + 'name' => 'uploadedfile', + 'label' => __('Uploaded File'), + 'title' => __('Uploaded File'), + + ] + ); + + $fieldset->addField( + 'url', + 'text', + [ + 'name' => 'url', + 'label' => __('URL'), + 'title' => __('URL'), + 'required' => false, + 'disabled' => $isElementDisabled, + 'note' => 'Upload file or Enter url' + ] + ); + + $fieldset->addField( + 'visible_scope', + 'select', + [ + 'name' => 'visible-scope', + 'label' => __('Visible to people who have not purchased this item'), + 'title' => __('Visible to people who have not purchased this item'), + 'value' => 0, + 'options' => ['1' => __('Yes'), '0' => __('No')], + 'disabled' => $isElementDisabled + ] + ); + + $fieldset->addField( + 'customer_group', + 'multiselect', + [ + 'name' => 'customer_group[]', + 'label' => __('Customer Group'), + 'title' => __('Customer Group'), + 'required' => true, + 'value' => [0,1,2,3], // todo: preselect ALL customer groups, not just 0-3 + 'values' => $customerGroup, + 'disabled' => $isElementDisabled + ] + ); + + $fieldset->addField( + 'store', + 'multiselect', + [ + 'name' => 'store[]', + 'label' => __('Store'), + 'title' => __('Store'), + 'required' => true, + 'value' => [0], + 'values' => $this->systemStore->getStoreValuesForForm(false, true), + 'disabled' => $isElementDisabled + ] + ); + + $fieldset->addField( + 'active', + 'select', + [ + 'name' => 'active', + 'label' => __('Active'), + 'title' => __('Active'), + 'value' => 1, + 'options' => ['1' => __('Yes'), '0' => __('No')], + 'disabled' => $isElementDisabled + ] + ); + + $this->_eventManager->dispatch('adminhtml_productattachment_edit_tab_main_prepare_form', ['form' => $form]); + + if ($model->getId()) { + $form->setValues($model->getData()); + } + + $this->setForm($form); + + return parent::_prepareForm(); + } + + /** + * Prepare label for tab + * + * @return string + */ + public function getTabLabel() + { + return __('Attachment Information'); + } + + /** + * Prepare title for tab + * + * @return string + */ + public function getTabTitle() + { + return __('Attachment Information'); + } + + /** + * {@inheritdoc} + */ + public function canShowTab() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function isHidden() + { + return false; + } + + /** + * Check permission for passed action + * + * @param string $resourceId + * @return bool + */ + public function _isAllowedAction($resourceId) + { + return $this->_authorization->isAllowed($resourceId); + } +} diff --git a/Block/Adminhtml/ProductAttachment/Edit/Tab/Products.php b/Block/Adminhtml/ProductAttachment/Edit/Tab/Products.php new file mode 100644 index 0000000..b053c5a --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Edit/Tab/Products.php @@ -0,0 +1,268 @@ +contactFactory = $contactFactory; + $this->productCollectionFactory = $productCollectionFactory; + $this->registry = $registry; + $this->attachModel = $attachModel; + parent::__construct($context, $backendHelper, $data); + } + + /** + * _construct + * @return void + */ + public function _construct() + { + parent::_construct(); + $this->setId('productsGrid'); + $this->setDefaultSort('entity_id'); + $this->setDefaultDir('DESC'); + $this->setSaveParametersInSession(true); + $this->setUseAjax(true); + if ($this->getRequest()->getParam('productattach_id')) { + $this->setDefaultFilter(['in_product' => 1]); + } + } + + /** + * @param \Magento\Backend\Block\Widget\Grid\Column $column + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function _addColumnFilterToCollection($column) + { + if ($column->getId() == 'in_product') { + $productIds = $this->_getSelectedProducts(); + + if (empty($productIds)) { + $productIds = 0; + } + if ($column->getFilter()->getValue()) { + $this->getCollection()->addFieldToFilter('entity_id', ['in' => $productIds]); + } else { + if ($productIds) { + $this->getCollection()->addFieldToFilter('entity_id', ['nin' => $productIds]); + } + } + } else { + parent::_addColumnFilterToCollection($column); + } + + return $this; + } + + /** + * prepare collection + */ + public function _prepareCollection() + { + $collection = $this->productCollectionFactory->create(); + $collection->addAttributeToSelect('name'); + $collection->addAttributeToSelect('sku'); + $collection->addAttributeToSelect('price'); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + /** + * @return $this + * @throws \Exception + */ + public function _prepareColumns() + { + + $model = $this->attachModel; + + $this->addColumn( + 'in_product', + [ + 'header_css_class' => 'a-center', + 'type' => 'checkbox', + 'name' => 'in_product', + 'align' => 'center', + 'index' => 'entity_id', + 'values' => $this->_getSelectedProducts(), + ] + ); + + $this->addColumn( + 'entity_id', + [ + 'header' => __('Product ID'), + 'type' => 'number', + 'index' => 'entity_id', + 'header_css_class' => 'col-id', + 'column_css_class' => 'col-id', + ] + ); + $this->addColumn( + 'names', + [ + 'header' => __('Name'), + 'index' => 'name', + 'class' => 'xxx', + 'width' => '50px', + ] + ); + $this->addColumn( + 'sku', + [ + 'header' => __('Sku'), + 'index' => 'sku', + 'class' => 'xxx', + 'width' => '50px', + ] + ); + $this->addColumn( + 'price', + [ + 'header' => __('Price'), + 'type' => 'currency', + 'index' => 'price', + 'width' => '50px', + ] + ); + + return parent::_prepareColumns(); + } + + /** + * @return string + */ + public function getGridUrl() + { + return $this->getUrl('*/*/productsgrid', ['_current' => true]); + } + + /** + * @param object $row + * @return string + */ + public function getRowUrl($row) + { + return ''; + } + + public function _getSelectedProducts() + { + $contact = $this->getContact(); + return $contact->getProducts($contact); + } + + /** + * Retrieve selected products + * + * @return array + */ + public function getSelectedProducts() + { + $contact = $this->getContact(); + $selected = $contact->getProducts($contact); + + if (!is_array($selected)) { + $selected = []; + } + return $selected; + } + + public function getContact() + { + $contactId = $this->getRequest()->getParam('productattach_id'); + $contact = $this->contactFactory->create(); + if ($contactId) { + $contact->load($contactId); + } + return $contact; + } + + /** + * {@inheritdoc} + */ + public function canShowTab() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function isHidden() + { + return true; + } +} diff --git a/Block/Adminhtml/ProductAttachment/Edit/Tabs.php b/Block/Adminhtml/ProductAttachment/Edit/Tabs.php new file mode 100644 index 0000000..44666b4 --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Edit/Tabs.php @@ -0,0 +1,47 @@ +setId('page_tabs'); + $this->setDestElementId('edit_form'); + $this->setTitle(__('Attachment Information')); + } +} diff --git a/Block/Adminhtml/ProductAttachment/Grid.php b/Block/Adminhtml/ProductAttachment/Grid.php new file mode 100644 index 0000000..b38486f --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Grid.php @@ -0,0 +1,204 @@ +collectionFactory = $collectionFactory; + $this->productattach = $productattach; + parent::__construct($context, $backendHelper, $data); + } + + /** + * @return void + */ + public function _construct() + { + parent::_construct(); + $this->setId('productattachGrid'); + $this->setDefaultSort('productattach_id'); + $this->setDefaultDir('ASC'); + $this->setUseAjax(true); + $this->setSaveParametersInSession(true); + } + + /** + * Prepare collection + * + * @return \Magento\Backend\Block\Widget\Grid + */ + public function _prepareCollection() + { + $collection = $this->collectionFactory->create(); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + /** + * Prepare columns + * + * @return \Magento\Backend\Block\Widget\Grid\Extended + * @throws \Exception + */ + public function _prepareColumns() + { + $this->addColumn('productattach_id', [ + 'header' => __('ID'), + 'index' => 'productattach_id', + ]); + + $this->addColumn( + 'name', + [ + 'header' => __('Name'), + 'index' => 'name' + ] + ); + + $this->addColumn( + 'description', + [ + 'header' => __('Description'), + 'index' => 'description' + ] + ); + + $this->addColumn( + 'file', + [ + 'header' => __('File'), + 'index' => 'file', + 'renderer' => 'Ecomteck\ProductAttachment\Block\Adminhtml\ProductAttachment\Renderer\FileIcon' + ] + ); + + $this->addColumn( + 'customer_group', + [ + 'header' => __('Customer Group'), + 'index' => 'customer_group', + 'renderer' => 'Ecomteck\ProductAttachment\Block\Adminhtml\ProductAttachment\Renderer\Group' + ] + ); + + $this->addColumn( + 'store', + [ + 'header' => __('Store '), + 'index' => 'store', + 'renderer' => 'Ecomteck\ProductAttachment\Block\Adminhtml\ProductAttachment\Renderer\Store' + ] + ); + + $this->addColumn( + 'active', + [ + 'header' => __('Active'), + 'index' => 'active', + 'renderer' => 'Ecomteck\ProductAttachment\Block\Adminhtml\ProductAttachment\Renderer\Active' + ] + ); + + $this->addColumn( + 'action', + [ + 'header' => __('Edit'), + 'type' => 'action', + 'getter' => 'getId', + 'actions' => [ + [ + 'caption' => __('Edit'), + 'class' => 'action-secondary', + 'url' => [ + 'base' => '*/*/edit', + 'params' => ['store' => $this->getRequest()->getParam('store')] + ], + 'field' => 'productattach_id' + ] + ], + 'sortable' => false, + 'filter' => false, + 'css_class' => 'scalable action-secondary', + 'header_css_class' => 'col-action', + 'column_css_class' => 'col-action' + ] + ); + + return parent::_prepareColumns(); + } + + /** + * Row click url + * + * @param \Magento\Framework\Object $row + * @return string + */ + public function getRowUrl($row) + { + return false; + } + + /** + * Get grid url + * + * @return string + */ + public function getGridUrl() + { + return $this->getUrl('*/*/grid', ['_current' => true]); + } +} diff --git a/Block/Adminhtml/ProductAttachment/Renderer/FileIcon.php b/Block/Adminhtml/ProductAttachment/Renderer/FileIcon.php new file mode 100644 index 0000000..f4ede37 --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Renderer/FileIcon.php @@ -0,0 +1,83 @@ +dataHelper = $dataHelper; + $this->assetRepo = $assetRepo; + } + + /** + * get customer group name + * @param DataObject $row + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function render(DataObject $row) + { + $file = $row->getFile(); + $fileExt = pathinfo($file, PATHINFO_EXTENSION); + if ($fileExt) { + $iconImage = $this->assetRepo->getUrl('Ecomteck_ProductAttachment::images/'.$fileExt.'.png'); + $fileIcon = " + "; + } else { + $iconImage = $this->assetRepo->getUrl('Ecomteck_ProductAttachment::images/unknown.png'); + $fileIcon = ""; + } + + return $fileIcon; + } +} diff --git a/Block/Adminhtml/ProductAttachment/Renderer/FileIconAdmin.php b/Block/Adminhtml/ProductAttachment/Renderer/FileIconAdmin.php new file mode 100644 index 0000000..22c643e --- /dev/null +++ b/Block/Adminhtml/ProductAttachment/Renderer/FileIconAdmin.php @@ -0,0 +1,118 @@ +dataHelper = $dataHelper; + $this->assetRepo = $assetRepo; + $this->helper = $helper; + $this->urlBuilder = $urlBuilder; + $this->coreRegistry = $registry; + } + + /** + * get customer group name + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getElementHtml() + { + $fileIcon = '

No File Uploaded

'; + $file = $this->getValue(); + if ($file) { + $fileExt = pathinfo($file, PATHINFO_EXTENSION); + if ($fileExt) { + $iconImage = $this->assetRepo->getUrl( + 'Ecomteck_ProductAttachment::images/'.$fileExt.'.png' + ); + $url = $this->dataHelper->getBaseUrl().'/'.$file; + $fileIcon = " + +
OPEN FILE
"; + } else { + $iconImage = $this->assetRepo->getUrl('Ecomteck_ProductAttachment::images/unknown.png'); + $fileIcon = ""; + } + $attachId = $this->coreRegistry->registry('productattach_id'); + $fileIcon .= " $attachId])."'> +
DELETE FILE
"; + } + return $fileIcon; + } +} diff --git a/Block/Attachment.php b/Block/Attachment.php new file mode 100644 index 0000000..62ec052 --- /dev/null +++ b/Block/Attachment.php @@ -0,0 +1,334 @@ +customerSession =$customerSession; + $this->orderModel = $orderModel; + $this->productattachCollectionFactory = $productattachCollectionFactory; + $this->fileIconCollectionFactory = $fileIconCollectionFactory; + $this->dataHelper = $dataHelper; + $this->scopeConfig = $context->getScopeConfig(); + $this->registry = $registry; + $this->httpContext = $httpContext; + parent::__construct( + $context, + $data + ); + } + + /** + * Check module is enable or not + */ + public function isEnable() + { + return $this->getConfig('productattachment/general/enable'); + } + + public function fileExists($attachment) + { + try { + $this->getFileSize($attachment); + return true; + } catch (\Magento\Framework\Exception\FileSystemException $e) { + + } + + return false; + } + + /** + * Retrieve productattach collection + * + * @return \Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment\Collection + */ + public function getCollection() + { + $collection = $this->productattachCollectionFactory->create(); + return $collection; + } + + /** + * Filter productattach collection by product Id + * + * @param $productId + * @return \Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment\Collection + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getAttachment($productId) + { + $isBought = false; + $customerId = $this->customerSession->getCustomerId(); + $orders = $this->orderModel->getCollection() + ->addFieldToFilter("customer_id", $customerId) + ->addFieldToFilter("status", \Magento\Sales\Model\Order::STATE_COMPLETE); + + foreach ($orders as $order) { + foreach ($order->getAllVisibleItems() as $item) { + if($item->getProductId() == $productId){ + $isBought = true; + break; + } + } + } + + $collection = $this->getCollection(); + + $collection->addFieldToFilter( + 'customer_group', + [ + ['null' => true], + ['finset' => $this->getCustomerId()] + ] + ); + + $collection->addFieldToFilter( + 'store', + [ + ['eq' => 0], + ['finset' => $this->dataHelper->getStoreId()] + ] + ); + + $collection->getSelect()->where( + "FIND_IN_SET(".$productId.", replace(products , '&', ',')) > 0" + ); + + if(!$isBought){ + $collection->addFieldToFilter( + 'visible_scope', + [ + ['eq' => 1], + ] + ); + } + + return $collection; + } + + /** + * Retrive attachment url by attachment + * + * @param $attachment + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getAttachmentUrl($attachment) + { + $url = $this->dataHelper->getBaseUrl().$attachment; + return $url; + } + + /** + * Retrive current product id + * + * @return number + */ + public function getCurrentId() + { + $product = $this->registry->registry('current_product'); + return $product->getId(); + } + + /** + * Retrive current customer id + * + * @return number + */ + public function getCustomerId() + { + $isLoggedIn = $this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH); + if(!$isLoggedIn) { + return 0; + } + + $customerId = $this->customerSession->getCustomer()->getGroupId(); + return $customerId; + } + + /** + * Retrieve file icon image + * + * @param string $fileExt + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getFileIcon($fileExt) + { + $fileExt = \strtolower($fileExt); + + if ($fileExt) { + $iconExt = $this->getIconExt($fileExt); + if ($iconExt) { + $mediaUrl = $this->dataHelper->getMediaUrl(); + $iconImage = $mediaUrl.'fileicon/tmp/icon/'.$iconExt; + } else { + $iconImage = $this->getViewFileUrl('Ecomteck_ProductAttachment::images/'.$fileExt.'.png'); + } + } else { + $iconImage = $this->getViewFileUrl('Ecomteck_ProductAttachment::images/unknown.png'); + } + return $iconImage; + } + + /** + * Retrive icon ext name + * + * @param $fileExt + * @return string + */ + public function getIconExt($fileExt) + { + $iconCollection = $this->fileIconCollectionFactory->create(); + $iconCollection->addFieldToFilter('icon_ext',$fileExt); + $icon = $iconCollection->getFirstItem()->getIconImage(); + return $icon; + } + + /** + * Retrive link icon image + * + * @return string + */ + public function getLinkIcon() + { + $iconImage = $this->getViewFileUrl('Ecomteck_ProductAttachment::images/link.png'); + return $iconImage; + } + + /** + * Retrive file size by attachment + * + * @param $attachment + * @return number + */ + public function getFileSize($attachment) + { + $attachmentPath = \Ecomteck\ProductAttachment\Helper\Data::MEDIA_PATH.$attachment; + $fileSize = $this->dataHelper->getFileSize($attachmentPath); + return $fileSize; + } + + /** + * Retrive config value + * @param $config + * @return mixed + */ + public function getConfig($config) + { + return $this->scopeConfig->getValue( + $config, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + } + + /** + * Retrive Tab Name + */ + public function getTabName() + { + $tabName = __($this->getConfig('productattachment/general/tabname')); + return $tabName; + } +} diff --git a/Block/Order/Attachment.php b/Block/Order/Attachment.php new file mode 100644 index 0000000..e425c54 --- /dev/null +++ b/Block/Order/Attachment.php @@ -0,0 +1,156 @@ +_paymentHelper = $paymentHelper; + $this->httpContext = $httpContext; + $this->_coreRegistry = $registry; + parent::__construct($context, $data); + $this->_isScopePrivate = true; + } + + /** + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function _prepareLayout() + { + $this->pageConfig->getTitle()->set(__('Order # %1', $this->getOrder()->getRealOrderId())); + $infoBlock = $this->_paymentHelper->getInfoBlock($this->getOrder()->getPayment(), $this->getLayout()); + $this->setChild('payment_info', $infoBlock); + } + + /** + * @return string + */ + public function getPaymentInfoHtml() + { + return $this->getChildHtml('payment_info'); + } + + /** + * Retrieve current order model instance + * + * @return \Magento\Sales\Model\Order + */ + public function getOrder() + { + return $this->_coreRegistry->registry('current_order'); + } + + /** + * Return back url for logged in and guest users + * + * @return string + */ + public function getBackUrl() + { + if ($this->httpContext->getValue(Context::CONTEXT_AUTH)) { + return $this->getUrl('*/*/history'); + } + return $this->getUrl('*/*/form'); + } + + /** + * Return back title for logged in and guest users + * + * @return \Magento\Framework\Phrase + */ + public function getBackTitle() + { + if ($this->httpContext->getValue(Context::CONTEXT_AUTH)) { + return __('Back to My Orders'); + } + return __('View Another Order'); + } + + /** + * @param object $order + * @return string + */ + public function getViewUrl($order) + { + return $this->getUrl('*/*/view', ['order_id' => $order->getId()]); + } + + /** + * @param object $order + * @return string + */ + public function getShipmentUrl($order) + { + return $this->getUrl('*/*/shipment', ['order_id' => $order->getId()]); + } + + /** + * @param object $order + * @return string + */ + public function getCreditmemoUrl($order) + { + return $this->getUrl('*/*/creditmemo', ['order_id' => $order->getId()]); + } + + /** + * @param object $invoice + * @return string + */ + public function getPrintInvoiceUrl($invoice) + { + return $this->getUrl('*/*/printInvoice', ['invoice_id' => $invoice->getId()]); + } + + /** + * @param object $order + * @return string + */ + public function getPrintAllInvoicesUrl($order) + { + return $this->getUrl('*/*/printInvoice', ['order_id' => $order->getId()]); + } +} diff --git a/Block/Order/AttachmentItems.php b/Block/Order/AttachmentItems.php new file mode 100644 index 0000000..d5fac21 --- /dev/null +++ b/Block/Order/AttachmentItems.php @@ -0,0 +1,326 @@ +customerSession =$customerSession; + $this->orderModel = $orderModel; + $this->productAttachCollectionFactory = $productAttachCollectionFactory; + $this->fileIconCollectionFactory = $fileIconCollectionFactory; + $this->dataHelper = $dataHelper; + $this->scopeConfig = $context->getScopeConfig(); + $this->registry = $registry; + $this->httpContext = $httpContext; + parent::__construct( + $context, + $data + ); + } + + /** + * Check module is enable or not + */ + public function isEnable() + { + return $this->getConfig('productattachment/general/enable'); + } + + public function fileExists($attachment) + { + try { + $this->getFileSize($attachment); + return true; + } catch (\Magento\Framework\Exception\FileSystemException $e) { + + } + + return false; + } + + /** + * Retrieve productattach collection + * + * @return \Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment\Collection + */ + public function getCollection() + { + $collection = $this->productAttachCollectionFactory->create(); + return $collection; + } + + public function getOrderAttachment() + { + $currentOrder = $this->getOrder(); + if($currentOrder->getStatus() != \Magento\Sales\Model\Order::STATE_COMPLETE){ + return null; + } + + $currentOrderItems = $currentOrder->getAllVisibleItems(); + + $collection = $this->getCollection(); +// +// $collection->addFieldToFilter( +// 'customer_group', +// [ +// ['null' => true], +// ['finset' => $this->getCustomerId()] +// ] +// ); + + $collection->addFieldToFilter( + 'store', + [ + ['eq' => 0], + ['finset' => $this->dataHelper->getStoreId()] + ] + ); + + $condition = ''; + $count = count($currentOrderItems); + $index = 0; + foreach($currentOrderItems as $item){ + $index++; + $productId = $item->getProductId(); + if($index = $count){ + $condition .= "FIND_IN_SET(" . $productId . ", replace(products , '&', ',')) > 0"; + } + else { + $condition .= "FIND_IN_SET(" . $productId . ", replace(products , '&', ',')) > 0 OR "; + } + } + + $collection->getSelect()->where($condition); + + return $collection; + } + + /** + * Retrive attachment url by attachment + * + * @param $attachment + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getAttachmentUrl($attachment) + { + $url = $this->dataHelper->getBaseUrl().$attachment; + return $url; + } + + /** + * Retrive current product id + * + * @return number + */ + public function getCurrentId() + { + $product = $this->registry->registry('current_product'); + return $product->getId(); + } + + /** + * Retrive current customer id + * + * @return number + */ + public function getCustomerId() + { + $isLoggedIn = $this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_AUTH); + if(!$isLoggedIn) { + return 0; + } + + $customerId = $this->customerSession->getCustomer()->getGroupId(); + return $customerId; + } + + /** + * Retrieve file icon image + * + * @param string $fileExt + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getFileIcon($fileExt) + { + $fileExt = \strtolower($fileExt); + + if ($fileExt) { + $iconExt = $this->getIconExt($fileExt); + if ($iconExt) { + $mediaUrl = $this->dataHelper->getMediaUrl(); + $iconImage = $mediaUrl.'fileicon/tmp/icon/'.$iconExt; + } else { + $iconImage = $this->getViewFileUrl('Ecomteck_ProductAttachment::images/'.$fileExt.'.png'); + } + } else { + $iconImage = $this->getViewFileUrl('Ecomteck_ProductAttachment::images/unknown.png'); + } + return $iconImage; + } + + /** + * Retrive icon ext name + * + * @param $fileExt + * @return string + */ + public function getIconExt($fileExt) + { + $iconCollection = $this->fileIconCollectionFactory->create(); + $iconCollection->addFieldToFilter('icon_ext',$fileExt); + $icon = $iconCollection->getFirstItem()->getIconImage(); + return $icon; + } + + /** + * Retrive link icon image + * + * @return string + */ + public function getLinkIcon() + { + $iconImage = $this->getViewFileUrl('Ecomteck_ProductAttachment::images/link.png'); + return $iconImage; + } + + /** + * Retrive file size by attachment + * + * @param $attachment + * @return number + */ + public function getFileSize($attachment) + { + $attachmentPath = \Ecomteck\ProductAttachment\Helper\Data::MEDIA_PATH.$attachment; + $fileSize = $this->dataHelper->getFileSize($attachmentPath); + return $fileSize; + } + + /** + * Retrive config value + * @param $config + * @return mixed + */ + public function getConfig($config) + { + return $this->scopeConfig->getValue( + $config, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + } + + /** + * Retrive Tab Name + */ + public function getTabName() + { + $tabName = __($this->getConfig('productattachment/general/tabname')); + return $tabName; + } + + public function getOrder(){ + return $this->registry->registry('current_order'); + } +} diff --git a/Controller/AbstractController/ProductAttachmentLoader.php b/Controller/AbstractController/ProductAttachmentLoader.php new file mode 100644 index 0000000..378cbfa --- /dev/null +++ b/Controller/AbstractController/ProductAttachmentLoader.php @@ -0,0 +1,86 @@ +productattachFactory = $productAttachmentFactory; + $this->registry = $registry; + $this->url = $url; + } + + /** + * @param RequestInterface $request + * @param ResponseInterface $response + * @return bool + */ + public function load(RequestInterface $request, ResponseInterface $response) + { + $id = (int)$request->getParam('id'); + if (!$id) { + $request->initForward(); + $request->setActionName('noroute'); + $request->setDispatched(false); + return false; + } + + $productAttachment = $this->productattachFactory->create()->load($id); + $this->registry->register('current_productattach', $productAttachment); + return true; + } +} diff --git a/Controller/AbstractController/ProductAttachmentLoaderInterface.php b/Controller/AbstractController/ProductAttachmentLoaderInterface.php new file mode 100644 index 0000000..a5f5f6c --- /dev/null +++ b/Controller/AbstractController/ProductAttachmentLoaderInterface.php @@ -0,0 +1,42 @@ +productAttachmentLoader = $productAttachmentLoader; + $this->resultPageFactory = $resultPageFactory; + parent::__construct($context); + } + + + /** + * ProductAttachment view page + * + * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface|\Magento\Framework\View\Result\Page|void + */ + public function execute() + { + if (!$this->productAttachmentLoader->load($this->_request, $this->_response)) { + return; + } + + /** @var \Magento\Framework\View\Result\Page $resultPage */ + $resultPage = $this->resultPageFactory->create(); + return $resultPage; + } +} diff --git a/Controller/Adminhtml/FileIcon.php b/Controller/Adminhtml/FileIcon.php new file mode 100644 index 0000000..d3415c8 --- /dev/null +++ b/Controller/Adminhtml/FileIcon.php @@ -0,0 +1,62 @@ +_coreRegistry = $coreRegistry; + parent::__construct($context); + } + + /** + * Init page + * + * @param \Magento\Backend\Model\View\Result\Page $resultPage + * @return \Magento\Backend\Model\View\Result\Page + */ + public function initPage($resultPage) + { + $resultPage->setActiveMenu('Ecomteck_ProductAttachment::ecomteck_productattachment_fileicon') + ->addBreadcrumb(__('Ecomteck'), __('Ecomteck')) + ->addBreadcrumb(__('FileIcon'), __('FileIcon')); + return $resultPage; + } +} diff --git a/Controller/Adminhtml/FileIcon/Delete.php b/Controller/Adminhtml/FileIcon/Delete.php new file mode 100644 index 0000000..8edf4b4 --- /dev/null +++ b/Controller/Adminhtml/FileIcon/Delete.php @@ -0,0 +1,89 @@ +fileIconFactory = $fileIconFactory; + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::delete'); + } + + /** + * Delete action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + // check if we know what should be deleted + $id = $this->getRequest()->getParam('fileicon_id'); + if ($id) { + try { + // init model and delete + $model = $this->fileIconFactory->create(); + $model->load($id); + $model->delete(); + // display success message + $this->messageManager->addSuccessMessage(__('You deleted the FileIcon.')); + // go to grid + return $resultRedirect->setPath('*/*/'); + } catch (\Exception $e) { + // display error message + $this->messageManager->addErrorMessage($e->getMessage()); + // go back to edit form + return $resultRedirect->setPath('*/*/edit', ['fileicon_id' => $id]); + } + } + // display error message + $this->messageManager->addErrorMessage(__('We can\'t find a FileIcon to delete.')); + // go to grid + return $resultRedirect->setPath('*/*/'); + } +} diff --git a/Controller/Adminhtml/FileIcon/Edit.php b/Controller/Adminhtml/FileIcon/Edit.php new file mode 100644 index 0000000..2f3af2d --- /dev/null +++ b/Controller/Adminhtml/FileIcon/Edit.php @@ -0,0 +1,90 @@ +resultPageFactory = $resultPageFactory; + $this->fileIconFactory = $fileIconFactory; + parent::__construct($context, $coreRegistry); + } + + /** + * Edit action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + // 1. Get ID and create model + $id = $this->getRequest()->getParam('fileicon_id'); + $model = $this->fileIconFactory->create(); + + // 2. Initial checking + if ($id) { + $model->load($id); + if (!$model->getId()) { + $this->messageManager->addErrorMessage(__('This FileIcon no longer exists.')); + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + return $resultRedirect->setPath('*/*/'); + } + } + $this->_coreRegistry->register('prince_productattachment_fileicon', $model); + + // 5. Build edit form + /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ + $resultPage = $this->resultPageFactory->create(); + $this->initPage($resultPage)->addBreadcrumb( + $id ? __('Edit FileIcon') : __('New File Icon'), + $id ? __('Edit FileIcon') : __('New File Icon') + ); + $resultPage->getConfig()->getTitle()->prepend(__('FileIcons')); + $resultPage->getConfig()->getTitle()->prepend($model->getId() ? $model->getIconExt() : __('New File Icon')); + return $resultPage; + } +} diff --git a/Controller/Adminhtml/FileIcon/Index.php b/Controller/Adminhtml/FileIcon/Index.php new file mode 100644 index 0000000..b725d23 --- /dev/null +++ b/Controller/Adminhtml/FileIcon/Index.php @@ -0,0 +1,71 @@ +resultPageFactory = $resultPageFactory; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::manage'); + } + + /** + * Index action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + $resultPage = $this->resultPageFactory->create(); + $resultPage->getConfig()->getTitle()->prepend(__("File Icon")); + return $resultPage; + } +} diff --git a/Controller/Adminhtml/FileIcon/InlineEdit.php b/Controller/Adminhtml/FileIcon/InlineEdit.php new file mode 100644 index 0000000..89c0064 --- /dev/null +++ b/Controller/Adminhtml/FileIcon/InlineEdit.php @@ -0,0 +1,101 @@ +jsonFactory = $jsonFactory; + $this->fileIconFactory = $fileIconFactory; + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::save'); + } + + /** + * Inline edit action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + /** @var \Magento\Framework\Controller\Result\Json $resultJson */ + $resultJson = $this->jsonFactory->create(); + $error = false; + $messages = []; + + if ($this->getRequest()->getParam('isAjax')) { + $postItems = $this->getRequest()->getParam('items', []); + if (!count($postItems)) { + $messages[] = __('Please correct the data sent.'); + $error = true; + } else { + foreach (array_keys($postItems) as $modelid) { + /** @var \Ecomteck\ProductAttachment\Model\FileIcon $model */ + $model = $this->fileIconFactory->create()->load($modelid); + try { + $model->setData(array_merge($model->getData(), $postItems[$modelid])); + $model->save(); + } catch (\Exception $e) { + $messages[] = "[FileIcon ID: {$modelid}] {$e->getMessage()}"; + $error = true; + } + } + } + } + + return $resultJson->setData([ + 'messages' => $messages, + 'error' => $error + ]); + } +} diff --git a/Controller/Adminhtml/FileIcon/NewAction.php b/Controller/Adminhtml/FileIcon/NewAction.php new file mode 100644 index 0000000..1df936f --- /dev/null +++ b/Controller/Adminhtml/FileIcon/NewAction.php @@ -0,0 +1,71 @@ +resultForwardFactory = $resultForwardFactory; + parent::__construct($context, $coreRegistry); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::save'); + } + + /** + * New action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + /** @var \Magento\Framework\Controller\Result\Forward $resultForward */ + $resultForward = $this->resultForwardFactory->create(); + return $resultForward->forward('edit'); + } +} diff --git a/Controller/Adminhtml/FileIcon/Save.php b/Controller/Adminhtml/FileIcon/Save.php new file mode 100644 index 0000000..6cc731c --- /dev/null +++ b/Controller/Adminhtml/FileIcon/Save.php @@ -0,0 +1,119 @@ +dataPersistor = $dataPersistor; + $this->fileIconFactory = $fileIconFactory; + parent::__construct($context); + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::save'); + } + + /** + * Save action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + $data = $this->getRequest()->getPostValue(); + if ($data) { + $id = $this->getRequest()->getParam('fileicon_id'); + + $model = $this->fileIconFactory->create()->load($id); + if (!$model->getId() && $id) { + $this->messageManager->addErrorMessage(__('This FileIcon no longer exists.')); + return $resultRedirect->setPath('*/*/'); + } + + $data = $this->_filterFileIconData($data); + $model->setData($data); + + try { + $model->save(); + $this->messageManager->addSuccessMessage(__('You saved the FileIcon.')); + $this->dataPersistor->clear('ecomteck_productattachment_fileicon'); + + if ($this->getRequest()->getParam('back')) { + return $resultRedirect->setPath('*/*/edit', ['fileicon_id' => $model->getId()]); + } + return $resultRedirect->setPath('*/*/'); + } catch (LocalizedException $e) { + $this->messageManager->addErrorMessage($e->getMessage()); + } catch (\Exception $e) { + $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the FileIcon.')); + } + + $this->dataPersistor->set('prince_productattachment_fileicon', $data); + return $resultRedirect->setPath('*/*/edit', ['fileicon_id' => $this->getRequest()->getParam('fileicon_id')]); + } + return $resultRedirect->setPath('*/*/'); + } + + public function _filterFileIconData(array $rawData) + { + $data = $rawData; + if (isset($data['icon_image'][0]['name'])) { + $data['icon_image'] = $data['icon_image'][0]['name']; + } else { + $data['icon_image'] = null; + } + return $data; + } +} diff --git a/Controller/Adminhtml/FileIcon/Upload.php b/Controller/Adminhtml/FileIcon/Upload.php new file mode 100644 index 0000000..181c37f --- /dev/null +++ b/Controller/Adminhtml/FileIcon/Upload.php @@ -0,0 +1,89 @@ +imageUploader = $imageUploader; + } + + /** + * Check admin permissions for this controller + * + * @return boolean + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::save'); + } + + /** + * Upload file controller action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + try { + $result = $this->imageUploader->saveFileToTmpDir('icon_image'); + + $result['cookie'] = [ + 'name' => $this->_getSession()->getName(), + 'value' => $this->_getSession()->getSessionId(), + 'lifetime' => $this->_getSession()->getCookieLifetime(), + 'path' => $this->_getSession()->getCookiePath(), + 'domain' => $this->_getSession()->getCookieDomain(), + ]; + } catch (\Exception $e) { + $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()]; + } + return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setData($result); + } +} diff --git a/Controller/Adminhtml/Index/Delete.php b/Controller/Adminhtml/Index/Delete.php new file mode 100644 index 0000000..1c33452 --- /dev/null +++ b/Controller/Adminhtml/Index/Delete.php @@ -0,0 +1,95 @@ +attachModel = $attachModel; + parent::__construct($context); + } + + /** + * {@inheritdoc} + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::delete'); + } + + /** + * Delete action + * + * @return \Magento\Backend\Model\View\Result\Redirect + */ + public function execute() + { + // check if we know what should be deleted + $id = $this->getRequest()->getParam('productattach_id'); + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + if ($id) { + $title = ""; + try { + // init model and delete + $model = $this->attachModel; + $model->load($id); + $title = $model->getTitle(); + $model->delete(); + // display success message + $this->messageManager->addSuccess(__('The data has been deleted.')); + // go to grid + return $resultRedirect->setPath('*/*/'); + } catch (\Exception $e) { + // display error message + $this->messageManager->addError($e->getMessage()); + // go back to edit form + return $resultRedirect->setPath('*/*/edit', ['page_id' => $id]); + } + } + // display error message + $this->messageManager->addError(__('We can\'t find a data to delete.')); + // go to grid + return $resultRedirect->setPath('*/*/'); + } +} diff --git a/Controller/Adminhtml/Index/DeleteFile.php b/Controller/Adminhtml/Index/DeleteFile.php new file mode 100644 index 0000000..2fd7980 --- /dev/null +++ b/Controller/Adminhtml/Index/DeleteFile.php @@ -0,0 +1,106 @@ +attachModel = $attachModel; + $this->file = $file; + $this->fileSystem = $fileSystem; + parent::__construct($context); + } + + /** + * {@inheritdoc} + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::delete'); + } + + /** + * Delete action + * + * @return \Magento\Framework\Controller\Result\Redirect + */ + public function execute() + { + $id = $this->getRequest()->getParam('productattach_id'); + $resultRedirect = $this->resultRedirectFactory->create(); + if ($id) { + try { + $model = $this->attachModel; + $model->load($id); + $currentFile = $model->getFile(); + $mediaDirectory = $this->fileSystem + ->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + $fileRootDir = $mediaDirectory->getAbsolutePath().'productattach'; + if ($this->file->isExists($fileRootDir . $currentFile)) { + $this->file->deleteFile($fileRootDir . $currentFile); + $model->setFile(''); + $model->save(); + $this->messageManager->addSuccess(__('The file has been deleted.')); + } + return $resultRedirect->setPath('*/*/edit', ['productattach_id' => $id]); + } catch (\Exception $e) { + $this->messageManager->addError($e->getMessage()); + return $resultRedirect->setPath('*/*/edit', ['productattach_id' => $id]); + } + } + } +} diff --git a/Controller/Adminhtml/Index/Edit.php b/Controller/Adminhtml/Index/Edit.php new file mode 100644 index 0000000..165fda8 --- /dev/null +++ b/Controller/Adminhtml/Index/Edit.php @@ -0,0 +1,150 @@ +resultPageFactory = $resultPageFactory; + $this->coreRegistry = $registry; + $this->attachModel = $attachModel; + $this->backSession = $context->getSession(); + parent::__construct($context); + } + + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::manage'); + } + + /** + * Init actions + * + * @return \Magento\Backend\Model\View\Result\Page + */ + public function _initAction() + { + // load layout, set active menu and breadcrumbs + /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ + $resultPage = $this->resultPageFactory->create(); + $resultPage->setActiveMenu( + 'Ecomteck_ProductAttachment::productattachment_manage' + )->addBreadcrumb( + __('Attachment'), + __('Attachment') + )->addBreadcrumb( + __('Manage Attachment'), + __('Manage Attachment') + ); + return $resultPage; + } + + /** + * Edit CMS page + * + * @return \Magento\Backend\Model\View\Result\Page|\Magento\Framework\Controller\Result\Redirect + */ + public function execute() + { + // 1. Get ID and create model + $id = $this->getRequest()->getParam('productattach_id'); + $model = $this->attachModel; + + // 2. Initial checking + if ($id) { + $model->load($id); + if (!$model->getId()) { + $this->messageManager->addError(__('This Attachment no longer exists.')); + /** \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + return $resultRedirect->setPath('*/*/'); + } + $this->coreRegistry->register('productattach_id', $model->getId()); + } + + // 3. Set entered data if was error when we do save + $data = $this->backSession->getFormData(true); + if (!empty($data)) { + $model->setData($data); + } + + // 4. Register model to use later in blocks + $this->coreRegistry->register('productattach', $model); + + // 5. Build edit form + /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ + $resultPage = $this->_initAction(); + $resultPage->addBreadcrumb( + $id ? __('Edit Attachment') : __('New Attachment'), + $id ? __('Edit Attachment') : __('New Attachment') + ); + $resultPage->getConfig()->getTitle() + ->prepend($model->getId() ? $model->getName() : __('New Attachment')); + return $resultPage; + } +} diff --git a/Controller/Adminhtml/Index/Grid.php b/Controller/Adminhtml/Index/Grid.php new file mode 100644 index 0000000..b5c038b --- /dev/null +++ b/Controller/Adminhtml/Index/Grid.php @@ -0,0 +1,47 @@ +_view->loadLayout(false); + $this->_view->renderLayout(); + } +} diff --git a/Controller/Adminhtml/Index/Index.php b/Controller/Adminhtml/Index/Index.php new file mode 100644 index 0000000..88d7be5 --- /dev/null +++ b/Controller/Adminhtml/Index/Index.php @@ -0,0 +1,88 @@ +resultPageFactory = $resultPageFactory; + } + + /** + * Check the permission to run it + * + * @return bool + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::manage'); + } + + /** + * ProductAttachment List action + * + * @return \Magento\Backend\Model\View\Result\Page + */ + public function execute() + { + /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ + $resultPage = $this->resultPageFactory->create(); + $resultPage->setActiveMenu( + 'Ecomteck_ProductAttachment::productattachment_manage' + )->addBreadcrumb( + __('Attachment'), + __('Attachment') + )->addBreadcrumb( + __('Manage Attachment'), + __('Manage Attachment') + ); + $resultPage->getConfig()->getTitle()->prepend(__('Product Attachment')); + return $resultPage; + } +} diff --git a/Controller/Adminhtml/Index/MassDelete.php b/Controller/Adminhtml/Index/MassDelete.php new file mode 100644 index 0000000..3451283 --- /dev/null +++ b/Controller/Adminhtml/Index/MassDelete.php @@ -0,0 +1,87 @@ +filter = $filter; + $this->collectionFactory = $collectionFactory; + parent::__construct($context); + } + + /** + * {@inheritdoc} + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::delete'); + } + + public function execute() + { + try { + $logCollection = $this->filter->getCollection($this->collectionFactory->create()); + + $itemsDeleted = 0; + foreach ($logCollection as $item) { + $item->delete(); + $itemsDeleted++; + } + $this->messageManager->addSuccess(__('A total of %1 Attachment(s) were deleted.', $itemsDeleted)); + } catch (\Exception $e) { + $this->messageManager->addError($e->getMessage()); + } + $resultRedirect = $this->resultRedirectFactory->create(); + return $resultRedirect->setPath('productattachment/index'); + } +} diff --git a/Controller/Adminhtml/Index/NewAction.php b/Controller/Adminhtml/Index/NewAction.php new file mode 100644 index 0000000..c59989e --- /dev/null +++ b/Controller/Adminhtml/Index/NewAction.php @@ -0,0 +1,73 @@ +resultForwardFactory = $resultForwardFactory; + parent::__construct($context); + } + + /** + * {@inheritdoc} + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::save'); + } + + /** + * Forward to edit + * + * @return \Magento\Backend\Model\View\Result\Forward + */ + public function execute() + { + /** @var \Magento\Backend\Model\View\Result\Forward $resultForward */ + $resultForward = $this->resultForwardFactory->create(); + return $resultForward->forward('edit'); + } +} diff --git a/Controller/Adminhtml/Index/PostDataProcessor.php b/Controller/Adminhtml/Index/PostDataProcessor.php new file mode 100644 index 0000000..5e556d3 --- /dev/null +++ b/Controller/Adminhtml/Index/PostDataProcessor.php @@ -0,0 +1,87 @@ +dateFilter = $dateFilter; + $this->messageManager = $messageManager; + } + + /** + * Filtering posted data. Converting localized data if needed + * + * @param array $data + * @return array + */ + public function filter($data) + { + $inputFilter = new \Zend_Filter_Input( + ['published_at' => $this->dateFilter], + [], + $data + ); + $data = $inputFilter->getUnescaped(); + return $data; + } + + /** + * Validate post data + * + * @return bool Return FALSE if someone item is invalid + */ + public function validate() + { + $errorNo = true; + return $errorNo; + } +} diff --git a/Controller/Adminhtml/Index/Products.php b/Controller/Adminhtml/Index/Products.php new file mode 100644 index 0000000..777fe2e --- /dev/null +++ b/Controller/Adminhtml/Index/Products.php @@ -0,0 +1,80 @@ +resultLayoutFactory = $resultLayoutFactory; + } + + /** + * @return bool + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::manage'); + } + + /** + * Save action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + + $resultLayout = $this->resultLayoutFactory->create(); + $resultLayout->getLayout()->getBlock('productattach.edit.tab.products') + ->setInProducts($this->getRequest()->getPost('index_products', null)); + + return $resultLayout; + } +} diff --git a/Controller/Adminhtml/Index/ProductsGrid.php b/Controller/Adminhtml/Index/ProductsGrid.php new file mode 100644 index 0000000..2db4513 --- /dev/null +++ b/Controller/Adminhtml/Index/ProductsGrid.php @@ -0,0 +1,80 @@ +resultLayoutFactory = $resultLayoutFactory; + } + + /** + * @return bool + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::manage'); + } + + /** + * Save action + * + * @return \Magento\Framework\Controller\ResultInterface + */ + public function execute() + { + $resultLayout = $this->resultLayoutFactory->create(); + $resultLayout->getLayout()->getBlock('productattach.edit.tab.products') + ->setInBanner($this->getRequest()->getPost('index_products', null)); + + return $resultLayout; + } +} diff --git a/Controller/Adminhtml/Index/Save.php b/Controller/Adminhtml/Index/Save.php new file mode 100644 index 0000000..84f4642 --- /dev/null +++ b/Controller/Adminhtml/Index/Save.php @@ -0,0 +1,146 @@ +dataProcessor = $dataProcessor; + $this->attachModel = $attachModel; + $this->backSession = $context->getSession(); + $this->helper = $helper; + parent::__construct($context); + } + + /** + * @return bool + */ + public function _isAllowed() + { + return $this->_authorization->isAllowed('Ecomteck_ProductAttachment::save'); + } + + /** + * Save action + * + * @return void + */ + public function execute() + { + $data = $this->getRequest()->getPostValue(); + if ($data) { + $data = $this->dataProcessor->filter($data); + $customerGroup = $this->helper->getCustomerGroup($data['customer_group']); + $store = $this->helper->getStores($data['store']); + $data['customer_group'] = $customerGroup; + $data['store'] = $store; + $data['visible_scope'] = $data['visible-scope']; + + + $uploadedFile = ''; + $model = $this->attachModel; + $id = $this->getRequest()->getParam('productattach_id'); + + if ($id) { + $model->load($id); + $uploadedFile = $model->getFile(); + } + + $model->addData($data); + + if (!$this->dataProcessor->validate($data)) { + $this->_redirect('*/*/edit', ['productattach_id' => $model->getId(), '_current' => true]); + return; + } + + try { + $model = $this->helper->uploadFile('file', $model); + $model->save(); + $this->messageManager->addSuccess(__('Attachment has been saved.')); + $this->backSession->setFormData(false); + if ($this->getRequest()->getParam('back')) { + $this->_redirect('*/*/edit', ['productattach_id' => $model->getId(), '_current' => true]); + return; + } + $this->_redirect('*/*/'); + return; + } catch (\Magento\Framework\Model\Exception $e) { + $this->messageManager->addError($e->getMessage()); + } catch (\RuntimeException $e) { + $this->messageManager->addError($e->getMessage()); + } catch (\Exception $e) { + $this->messageManager->addException($e, __('Something went wrong while saving the attachment.')); + } + + $this->_getSession()->setFormData($data); + $this->_redirect('*/*/edit', ['productattach_id' => $this->getRequest()->getParam('productattach_id')]); + return; + } + $this->_redirect('*/*/'); + } +} diff --git a/Controller/Index/Index.php b/Controller/Index/Index.php new file mode 100644 index 0000000..aa89379 --- /dev/null +++ b/Controller/Index/Index.php @@ -0,0 +1,80 @@ +resultPageFactory = $resultPageFactory; + parent::__construct($context); + } + + /** + * @return \Magento\Framework\View\Result\Page + */ + public function execute() + { + $this->_view->loadLayout(); + $this->_view->getLayout()->initMessages(); + $this->_view->getPage()->getConfig()->getTitle()->set(__('Site Product Attachment')); + $listBlock = $this->_view->getLayout()->getBlock('productattach.list'); + + if ($listBlock) { + $currentPage = abs((int)($this->getRequest()->getParam('p'))); + if ($currentPage < 1) { + $currentPage = 1; + } + + $listBlock->setCurrentPage($currentPage); + } + + /** @var \Magento\Framework\View\Result\Page $resultPage */ + $resultPage = $this->resultPageFactory->create(); + return $resultPage; + } +} diff --git a/Controller/Order/Attachment.php b/Controller/Order/Attachment.php new file mode 100644 index 0000000..98706d8 --- /dev/null +++ b/Controller/Order/Attachment.php @@ -0,0 +1,13 @@ +backendUrl = $backendUrl; + $this->filesystem = $filesystem; + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->fileUploaderFactory = $fileUploaderFactory; + $this->storeManager = $storeManager; + parent::__construct($context); + } + + /** + * Upload image and return uploaded image file name or false + * + * @param string $scope the request key for file + * @param $model + * @return bool|string + * @throws \Exception + */ + public function uploadFile($scope, $model) + { + try { + $uploader = $this->fileUploaderFactory->create(['fileId' => $scope]); + $uploader->setAllowedExtensions($this->getAllowedExt()); + $uploader->setAllowRenameFiles(true); + $uploader->setFilesDispersion(true); + $uploader->setAllowCreateFolders(true); + + if ($uploader->save($this->getBaseDir())) { + $model->setFile($uploader->getUploadedFileName()); + $model->setFileExt($uploader->getFileExtension()); + } + + } catch (\Exception $e) { } + + return $model; + } + + /** + * Look on the file system if this file is present, according to the dispersion principle + * @param $fileName + * @return bool + */ + public function checkIfFileExists($fileName){ + return file_exists($this->getDispersionFolderAbsolutePath($fileName)."/".$fileName); + } + + /** + * Save file-content to the file on the file-system + * @param $filename + * @param $fileContent + * @return string + */ + public function saveFile($filename, $fileContent){ + if ($fileContent != "") { + try { + $folderAbsolutePath = $this->getDispersionFolderAbsolutePath($filename); + if (!file_exists($folderAbsolutePath)) { + //create folder + mkdir($folderAbsolutePath, 0777, true); + } + // create file + file_put_contents($folderAbsolutePath."/".$filename, base64_decode($fileContent)); + return true; + } catch (\Exception $e) { + return false; + } + }else{ + return false; + } + } + + /** + * Return the base media directory for ProductAttachment Item images + * + * @return string + */ + public function getBaseDir() + { + $path = $this->filesystem->getDirectoryRead( + DirectoryList::MEDIA + )->getAbsolutePath(self::MEDIA_PATH); + return $path; + } + + /** + * Return the Base URL for ProductAttachment Item images + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getBaseUrl() + { + return $this->storeManager->getStore()->getBaseUrl( + \Magento\Framework\UrlInterface::URL_TYPE_MEDIA + ) . self::MEDIA_PATH; + } + + /** + * Return the number of items per page + * + * @return int + */ + public function getProductAttachmentPerPage() + { + return abs((int)$this->getScopeConfig() + ->getValue(self::XML_PATH_ITEMS_PER_PAGE, \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ); + } + + /** + * Return current store Id + * + * @return Int + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getStoreId() + { + return $this->storeManager->getStore()->getId(); + } + + public function getProductsGridUrl() + { + return $this->backendUrl->getUrl('productattachment/index/products', ['_current' => true]); + } + + /** + * Return customer groups + * @param $customers + * @return string + */ + public function getCustomerGroup($customers) + { + $customers = implode(',', $customers); + return $customers; + } + + /** + * Return stores + * @param $store + * @return string + */ + public function getStores($store) + { + $store = implode(',', $store); + return $store; + } + + /** + * Return the path pof the file that will be save in the database + * @param string $fileName file name with file-extension + * @return string + */ + public function getFilePathForDB($fileName) + { + return $this->getFileDispersionPath($fileName) ."/". $fileName; + } + + /** + * Return the path to the file acording to the dispersion principle (first and second letter) + * Example file.tyt => f/i/file.txt + * @param $fileName + * @return string + */ + public function getFileDispersionPath($fileName) + { + return \Magento\MediaStorage\Model\File\Uploader::getDispretionPath($fileName); + } + + /** + * Delete the file in the folder media folder of product attachment + * @param $filepathInMediaFolder + */ + public function deleteFile($filepathInMediaFolder) + { + $exts = explode('.', $filepathInMediaFolder); + $ext = ""; + if(count($exts)){ + $ext = $exts[count($exts)-1]; + } + if( in_array($ext, $this->getAllowedExt()) && + strpos($filepathInMediaFolder,"..") === false ) { + $finalPath = $this->getProductAttachMediaFolderAbsolutePath()."/".$filepathInMediaFolder; + if(file_exists($finalPath)){ + unlink($finalPath); + } + } + } + + /** + * Return the media folder absolute path + * @return string + */ + private function getProductAttachMediaFolderAbsolutePath() + { + $mediaPath = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath(); + return $mediaPath . self::MEDIA_PATH; + } + + /** + * Return the dispersion folder absoluite path for the given filename + * @param $filename + * @return string + */ + public function getDispersionFolderAbsolutePath($filename) + { + return $this->getProductAttachMediaFolderAbsolutePath()."/".$this->getFileDispersionPath($filename); + } + + /** + * Return the allowed file extensions + * @return array + */ + public function getAllowedExt() + { + return ['pdf','pptx', 'xls', 'xlsx', 'flash', 'mp3', 'docx', 'doc', 'zip', 'jpg', 'jpeg', 'png', 'gif', 'ini', 'readme', 'avi', 'csv', 'txt', 'wma', 'mpg', 'flv', 'mp4']; + } + + /** + * Return mediaurl + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getMediaUrl() + { + $mediaUrl = $this->storeManager-> getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA ); + return $mediaUrl; + } + + /** + * Retrive file size by attachment + * + * @param $file + * @return number + */ + public function getFileSize($file) + { + $fileSize = $this->mediaDirectory->stat($file)['size']; + $readableSize = $this->convertToReadableSize($fileSize); + return $readableSize; + } + + /** + * Convert size into readable format + * @param $size + * @return string + */ + public function convertToReadableSize($size) + { + $base = log($size) / log(1024); + $suffix = ["", " KB", " MB", " GB", " TB"]; + $f_base = floor($base); + return round(pow(1024, $base - floor($base)), 1) . $suffix[$f_base]; + } + +} diff --git a/Model/Config/Source/Status.php b/Model/Config/Source/Status.php new file mode 100644 index 0000000..f8e0bdf --- /dev/null +++ b/Model/Config/Source/Status.php @@ -0,0 +1,42 @@ + 1, 'label' => __('Enable')], ['value' => 0, 'label' => __('Disable')]]; + } +} diff --git a/Model/FileIcon.php b/Model/FileIcon.php new file mode 100644 index 0000000..6581eea --- /dev/null +++ b/Model/FileIcon.php @@ -0,0 +1,100 @@ +_init('Ecomteck\ProductAttachment\Model\ResourceModel\FileIcon'); + } + + /** + * Get fileicon_id + * @return string + */ + public function getFileIconId() + { + return $this->getData(self::FILE_ICON_ID); + } + + /** + * Set fileicon_id + * @param string $fileIconId + * @return \Ecomteck\ProductAttachment\Api\Data\FileIconInterface + */ + public function setFileIconId($fileIconId) + { + return $this->setData(self::FILE_ICON_ID, $fileIconId); + } + + /** + * Get icon_ext + * @return string + */ + public function getIconExt() + { + return $this->getData(self::ICON_EXT); + } + + /** + * Set icon_ext + * @param string $icon_ext + * @return \Ecomteck\ProductAttachment\Api\Data\FileIconInterface + */ + public function setIconExt($icon_ext) + { + return $this->setData(self::ICON_EXT, $icon_ext); + } + + /** + * Get icon_image + * @return string + */ + public function getIconImage() + { + return $this->getData(self::ICON_IMAGE); + } + + /** + * Set icon_image + * @param string $icon_image + * @return \Ecomteck\ProductAttachment\Api\Data\FileIconInterface + */ + public function setIconImage($icon_image) + { + return $this->setData(self::ICON_IMAGE, $icon_image); + } +} diff --git a/Model/FileIcon/DataProvider.php b/Model/FileIcon/DataProvider.php new file mode 100644 index 0000000..58e6869 --- /dev/null +++ b/Model/FileIcon/DataProvider.php @@ -0,0 +1,113 @@ +collection = $collectionFactory->create(); + $this->dataPersistor = $dataPersistor; + $this->storeManager = $storeManager; + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + } + + /** + * Get data + * + * @return array + */ + public function getData() + { + if (isset($this->loadedData)) { + return $this->loadedData; + } + $items = $this->collection->getItems(); + foreach ($items as $model) { + $this->loadedData[$model->getFileIconId()] = $model->getData(); + if ($model->getIconImage()) { + $m['icon_image'][0]['name'] = $model->getIconImage(); + $m['icon_image'][0]['url'] = $this->getMediaUrl().$model->getIconImage(); + $fullData = $this->loadedData; + $this->loadedData[$model->getFileIconId()] = array_merge($fullData[$model->getFileIconId()], $m); + } + } + $data = $this->dataPersistor->get('ecomteck_productattachment_fileicon'); + + if (!empty($data)) { + $model = $this->collection->getNewEmptyItem(); + $model->setData($data); + $this->loadedData[$model->getFileIconId()] = $model->getData(); + $this->dataPersistor->clear('ecomteck_productattachment_fileicon'); + } + + return $this->loadedData; + } + + public function getMediaUrl() + { + $mediaUrl = $this->storeManager->getStore() + ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA).'fileicon/tmp/icon/'; + return $mediaUrl; + } +} diff --git a/Model/FileIconRepository.php b/Model/FileIconRepository.php new file mode 100644 index 0000000..5fc6b91 --- /dev/null +++ b/Model/FileIconRepository.php @@ -0,0 +1,190 @@ +resource = $resource; + $this->fileIconFactory = $fileIconFactory; + $this->fileIconCollectionFactory = $fileIconCollectionFactory; + $this->searchResultsFactory = $searchResultsFactory; + $this->dataObjectHelper = $dataObjectHelper; + $this->dataFileIconFactory = $dataFileIconFactory; + $this->dataObjectProcessor = $dataObjectProcessor; + $this->storeManager = $storeManager; + } + + /** + * {@inheritdoc} + */ + public function save( + \Ecomteck\ProductAttachment\Api\Data\FileIconInterface $fileIcon + ) { + /* if (empty($fileIcon->getStoreId())) { + $storeId = $this->storeManager->getStore()->getId(); + $fileIcon->setStoreId($storeId); + } */ + try { + $fileIcon->getResource()->save($fileIcon); + } catch (\Exception $exception) { + throw new CouldNotSaveException(__( + 'Could not save the file icon: %1', + $exception->getMessage() + )); + } + return $fileIcon; + } + + /** + * {@inheritdoc} + */ + public function getById($fileIconId) + { + $fileIcon = $this->fileIconFactory->create(); + $fileIcon->getResource()->load($fileIcon, $fileIconId); + if (!$fileIcon->getId()) { + throw new NoSuchEntityException(__('File icon with id "%1" does not exist.', $fileIconId)); + } + return $fileIcon; + } + + /** + * {@inheritdoc} + */ + public function getList( + \Magento\Framework\Api\SearchCriteriaInterface $criteria + ) { + $collection = $this->fileIconCollectionFactory->create(); + foreach ($criteria->getFilterGroups() as $filterGroup) { + foreach ($filterGroup->getFilters() as $filter) { + if ($filter->getField() === 'store_id') { + $collection->addStoreFilter($filter->getValue(), false); + continue; + } + $condition = $filter->getConditionType() ?: 'eq'; + $collection->addFieldToFilter($filter->getField(), [$condition => $filter->getValue()]); + } + } + + $sortOrders = $criteria->getSortOrders(); + if ($sortOrders) { + /** @var SortOrder $sortOrder */ + foreach ($sortOrders as $sortOrder) { + $collection->addOrder( + $sortOrder->getField(), + ($sortOrder->getDirection() == SortOrder::SORT_ASC) ? 'ASC' : 'DESC' + ); + } + } + $collection->setCurPage($criteria->getCurrentPage()); + $collection->setPageSize($criteria->getPageSize()); + + $searchResults = $this->searchResultsFactory->create(); + $searchResults->setSearchCriteria($criteria); + $searchResults->setTotalCount($collection->getSize()); + $searchResults->setItems($collection->getItems()); + return $searchResults; + } + + /** + * {@inheritdoc} + */ + public function delete( + \Ecomteck\ProductAttachment\Api\Data\FileIconInterface $fileIcon + ) { + try { + $fileIcon->getResource()->delete($fileIcon); + } catch (\Exception $exception) { + throw new CouldNotDeleteException(__( + 'Could not delete the File icon: %1', + $exception->getMessage() + )); + } + return true; + } + + /** + * {@inheritdoc} + */ + public function deleteById($fileIconId) + { + return $this->delete($this->getById($fileIconId)); + } +} diff --git a/Model/ImageUploader.php b/Model/ImageUploader.php new file mode 100644 index 0000000..92ffa9a --- /dev/null +++ b/Model/ImageUploader.php @@ -0,0 +1,289 @@ +coreFileStorageDatabase = $coreFileStorageDatabase; + $this->mediaDirectory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + $this->uploaderFactory = $uploaderFactory; + $this->storeManager = $storeManager; + $this->logger = $logger; + $this->baseTmpPath = "fileicon/tmp/icon"; + $this->basePath = "fileicon/icon"; + $this->allowedExtensions= ['jpg', 'jpeg', 'gif', 'png']; + } + + /** + * Set base tmp path + * + * @param string $baseTmpPath + * + * @return void + */ + public function setBaseTmpPath($baseTmpPath) + { + $this->baseTmpPath = $baseTmpPath; + } + + /** + * Set base path + * + * @param string $basePath + * + * @return void + */ + public function setBasePath($basePath) + { + $this->basePath = $basePath; + } + + /** + * Set allowed extensions + * + * @param string[] $allowedExtensions + * + * @return void + */ + public function setAllowedExtensions($allowedExtensions) + { + $this->allowedExtensions = $allowedExtensions; + } + + /** + * Retrieve base tmp path + * + * @return string + */ + public function getBaseTmpPath() + { + return $this->baseTmpPath; + } + + /** + * Retrieve base path + * + * @return string + */ + public function getBasePath() + { + return $this->basePath; + } + + /** + * Retrieve base path + * + * @return string[] + */ + public function getAllowedExtensions() + { + return $this->allowedExtensions; + } + + /** + * Retrieve path + * + * @param string $path + * @param string $imageName + * + * @return string + */ + public function getFilePath($path, $imageName) + { + return rtrim($path, '/') . '/' . ltrim($imageName, '/'); + } + + /** + * Checking file for moving and move it + * + * @param string $imageName + * + * @return string + * + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function moveFileFromTmp($imageName) + { + $baseTmpPath = $this->getBaseTmpPath(); + $basePath = $this->getBasePath(); + + $baseImagePath = $this->getFilePath($basePath, $imageName); + $baseTmpImagePath = $this->getFilePath($baseTmpPath, $imageName); + + try { + $this->coreFileStorageDatabase->copyFile( + $baseTmpImagePath, + $baseImagePath + ); + $this->mediaDirectory->renameFile( + $baseTmpImagePath, + $baseImagePath + ); + } catch (\Exception $e) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Something went wrong while saving the file(s).') + ); + } + + return $imageName; + } + + /** + * Checking file for save and save it to tmp dir + * + * @param string $fileId + * + * @return string[] + * + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function saveFileToTmpDir($fileId) + { + $baseTmpPath = $this->getBaseTmpPath(); + + $uploader = $this->uploaderFactory->create(['fileId' => $fileId]); + $uploader->setAllowedExtensions($this->getAllowedExtensions()); + $uploader->setAllowRenameFiles(true); + $size = $uploader->getFileSize(); + + if($size > 20000) { + throw new \Magento\Framework\Exception\LocalizedException( + __('File size must be less than 20KB. Large icon images will effect page load time.') + ); + } + + $result = $uploader->save($this->mediaDirectory->getAbsolutePath($baseTmpPath)); + + if (!$result) { + throw new \Magento\Framework\Exception\LocalizedException( + __('File can not be saved to the destination folder.') + ); + } + + /** + * Workaround for prototype 1.7 methods "isJSON", "evalJSON" on Windows OS + */ + $result['tmp_name'] = str_replace('\\', '/', $result['tmp_name']); + $result['path'] = str_replace('\\', '/', $result['path']); + $result['url'] = $this->storeManager + ->getStore() + ->getBaseUrl( + \Magento\Framework\UrlInterface::URL_TYPE_MEDIA + ) . $this->getFilePath($baseTmpPath, $result['file']); + $result['name'] = $result['file']; + + if (isset($result['file'])) { + try { + $relativePath = rtrim($baseTmpPath, '/') . '/' . ltrim($result['file'], '/'); + $this->coreFileStorageDatabase->saveFile($relativePath); + } catch (\Exception $e) { + $this->logger->critical($e); + throw new \Magento\Framework\Exception\LocalizedException( + __('Something went wrong while saving the file(s).') + ); + } + } + + return $result; + } +} diff --git a/Model/ProductAttachment.php b/Model/ProductAttachment.php new file mode 100644 index 0000000..711608d --- /dev/null +++ b/Model/ProductAttachment.php @@ -0,0 +1,97 @@ +_init('Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment'); + } + + /** + * Return unique ID(s) for each object in system + * + * @return array + */ + public function getIdentities() + { + return [self::CACHE_TAG . '_' . $this->getId()]; + } + + public function getProducts(\Ecomteck\ProductAttachment\Model\ProductAttachment $object) + { + $tbl = $this->getResource()->getTable("ecomteck_productattachment"); + $select = $this->getResource()->getConnection()->select()->from( + $tbl, + ['products'] + ) + ->where( + 'productattach_id = ?', + (int)$object->getId() + ); + + $products = $this->getResource()->getConnection()->fetchCol($select); + + if ($products) { + $products = explode('&', $products[0]); + } + + return $products; + } +} diff --git a/Model/ProductAttachmentTable.php b/Model/ProductAttachmentTable.php new file mode 100644 index 0000000..82aed95 --- /dev/null +++ b/Model/ProductAttachmentTable.php @@ -0,0 +1,201 @@ +_init('Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment'); + } + + public function getIdentities() + { + return [self::CACHE_TAG . '_' . $this->getId()]; + } + + /** + * @return string + */ + public function getProductAttachId() + { + return $this->getData("productattach_id"); + } + + /** + * @param string $val + * @return void + */ + public function setProductAttachId($val) + { + $this->setData("productattach_id",$val); + } + + /** + * @return string + */ + public function getName() + { + return $this->getData("name"); + } + + /** + * @param string $val + * @return void + */ + public function setName($val) + { + $this->setData("name",$val); + } + /** + * @return string + */ + public function getDescription() + { + return $this->getData("description"); + } + + /** + * @param string $val + * @return void + */ + public function setDescription($val) + { + $this->setData("description",$val); + } + + /** + * @return string + */ + public function getFile() + { + return $this->getData("file"); + } + + /** + * @param string $val + * @return void + */ + public function setFile($val) + { + $this->setData("file",$val); + } + + /** + * @return string + */ + public function getUrl() + { + return $this->getData("url"); + } + + /** + * @param string $val + * @return void + */ + public function setUrl($val) + { + $this->setData("url",$val); + } + + /** + * @return string + */ + public function getStore() + { + return $this->getData("store"); + } + + /** + * @param string $val + * @return void + */ + public function setStore($val) + { + $this->setData("store",$val); + } + + /** + * @return string + */ + public function getCustomerGroup() + { + return $this->getData("customer_group"); + } + + /** + * @param string $val + * @return void + */ + public function setCustomerGroup($val) + { + $this->setData("customer_group",$val); + } + + /** + * @return string + */ + public function getProducts() + { + return $this->getData("products"); + } + + /** + * @param string $val + * @return void + */ + public function setProducts($val) + { + $this->setData("products",$val); + } + + /** + * @return string + */ + public function getActive() + { + return $this->getData("active"); + } + + /** + * @param string $val + * @return void + */ + public function setActive($val) + { + $this->setData("active",$val); + } +} \ No newline at end of file diff --git a/Model/ProductAttachmentWebApi.php b/Model/ProductAttachmentWebApi.php new file mode 100644 index 0000000..e24d32b --- /dev/null +++ b/Model/ProductAttachmentWebApi.php @@ -0,0 +1,231 @@ +_productAttachment = $productAttachment; + $this->_productAttachmentCollectionFactory = $productAttachmentCollectionFactory; + $this->_productAttachmentTableInterface = $productAttachmentTableInterface; + $this->_productAttachmentTableInterfaceFactory = $productAttachmentTableInterfaceFactory; + $this->_extensibleDataObjectConverter = $extensibleDataObjectConverter; + $this->_dataHelper = $dataHelper; + } + + /** + * @param Data\ProductAttachmentTableInterface $productAttachmentTableInterface + * @param $fileName + * @param $fileContent + * @return mixed + * @throws \Exception + */ + public function UpdateInsertAttachment( + \Ecomteck\ProductAttachment\Api\Data\ProductAttachmentTableInterface $productAttachmentTableInterface, + $fileName, + $fileContent + ) { + $objectArray = $productAttachmentTableInterface->getData(); + + $id = $productAttachmentTableInterface->getId(); + if($id == 0) + $objectArray["productattach_id"] = null; + + if(array_key_exists('products', $objectArray)) { + $productIds = $objectArray['products']; + $objectArray['products'] = str_replace(',', '&', $productIds); + } + + $attachment = $this->_productAttachmentCollectionFactory->create(); + $attachment->setData($objectArray); + + $this->_productAttachment->load($attachment, $id); + + if($attachment->isObjectNew() == false) + { + //UPDATE ATTACHMENT RECORD + if(array_key_exists('name', $objectArray)) + $attachment->setName($objectArray['name']); + if(array_key_exists('description', $objectArray)) + $attachment->setDescription($objectArray['description']); + if(array_key_exists('url', $objectArray)) + $attachment->setUrl($objectArray['url']); + if(array_key_exists('products', $objectArray)) + $attachment->setProducts($objectArray['products']); + if(array_key_exists('customer_group', $objectArray)) + $attachment->setCustomerGroup($objectArray['customer_group']); + if(array_key_exists('store', $objectArray)) + $attachment->setStore($objectArray['store']); + if(array_key_exists('active', $objectArray)) + $attachment->setActive($objectArray['active']); + } + + //check if file already exists on the file system + if($fileContent){ + //this is a new file or an updated version of it => check if file already exists on the system + if($this->_dataHelper->checkIfFileExists($fileName)) { + //delete file + $this->_dataHelper->deleteFile($this->_dataHelper->getFileDispersionPath($fileName)."/".$fileName); + } + //create file + if(!$this->_dataHelper->saveFile($fileName, $fileContent)){ + return -1; + } else { + //update file path + $attachment->setFile( $this->_dataHelper->getFilePathForDB($fileName) ); + + $fileExt = ""; + $slicedFileName = explode('.', $fileName); + if(count($slicedFileName) > 1){ + $fileExt = $slicedFileName[count($slicedFileName)-1]; + } + $attachment->setFileExt($fileExt); + } + } else { + $attachment->setFileExt(''); + } + + //save attachment record + $this->_productAttachment->save($attachment); + + //return the id of the create/updated record + return $attachment->getId(); + } + + /** + * @param int $int + * @return bool + * @throws \Exception + */ + public function DeleteAttachment( + $int + ) { + //delete DB record + $attachment = $this->_productAttachmentCollectionFactory->create(); + $this->_productAttachment->load($attachment, $int); + if(!$attachment->getId()) + return false; + $this->_productAttachment->delete($attachment); + + //check if this is the last record from the DB linked to this file => if it's true, than delete this file + /** @var \Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment\Collection $collection */ + $collection = $this->_productAttachmentCollectionFactory->create()->getCollection(); + $collection->addFieldToFilter('file', $attachment->getData("file")); + if($collection->count() == 0){ + //delete file on the file system + $this->_dataHelper->deleteFile($attachment->getData("file")); + } + + return true; + } + + /** + * @param int $int + * @return ProductAttachmentTable + * @throws NotFoundException + */ + public function GetAttachment( + $int + ) { + $attachment = $this->_productAttachmentCollectionFactory->create(); + $this->_productAttachment->load($attachment, $int); + if(!$attachment->getId()) { + throw new \Magento\Framework\Exception\NotFoundException( + __('no attachment found') + ); + } + $attachResponse = $this->_productAttachmentCollectionFactory->create(); + if($attachment->getData()) { + $attachResponse->setProductAttachId($attachment->getId()); + $attachResponse->setName($attachment->getName()); + $attachResponse->setDescription($attachment->getDescription()); + $attachResponse->setFile($attachment->getFile()); + $attachResponse->setUrl($attachment->getUrl()); + $attachResponse->setStore($attachment->getStore()); + $attachResponse->setCustomerGroup($attachment->getCustomerGroup()); + $attachResponse->setProducts($attachment->getProducts()); + $attachResponse->setActive($attachment->getActive()); + } + + return $attachResponse; + } + + const CUSTOM_PATH = "custom/upload"; +} diff --git a/Model/ResourceModel/FileIcon.php b/Model/ResourceModel/FileIcon.php new file mode 100644 index 0000000..1e5d15d --- /dev/null +++ b/Model/ResourceModel/FileIcon.php @@ -0,0 +1,43 @@ +_init('ecomteck_productattachment_fileicon', 'fileicon_id'); + } +} diff --git a/Model/ResourceModel/FileIcon/Collection.php b/Model/ResourceModel/FileIcon/Collection.php new file mode 100644 index 0000000..6e83494 --- /dev/null +++ b/Model/ResourceModel/FileIcon/Collection.php @@ -0,0 +1,46 @@ +_init( + 'Ecomteck\ProductAttachment\Model\FileIcon', + 'Ecomteck\ProductAttachment\Model\ResourceModel\FileIcon' + ); + } +} diff --git a/Model/ResourceModel/ProductAttachment.php b/Model/ResourceModel/ProductAttachment.php new file mode 100644 index 0000000..ce441bc --- /dev/null +++ b/Model/ResourceModel/ProductAttachment.php @@ -0,0 +1,45 @@ +_init('ecomteck_productattachment', 'productattach_id'); + } +} diff --git a/Model/ResourceModel/ProductAttachment/Collection.php b/Model/ResourceModel/ProductAttachment/Collection.php new file mode 100644 index 0000000..33ec39f --- /dev/null +++ b/Model/ResourceModel/ProductAttachment/Collection.php @@ -0,0 +1,48 @@ +_init( + 'Ecomteck\ProductAttachment\Model\ProductAttachment', + 'Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment' + ); + } +} diff --git a/Plugin/ProductGet.php b/Plugin/ProductGet.php new file mode 100644 index 0000000..b0705fe --- /dev/null +++ b/Plugin/ProductGet.php @@ -0,0 +1,63 @@ +productExtensionFactory = $productExtensionFactory; + $this->productAttachment = $productAttachment; + } + + /** + * @param \Magento\Catalog\Api\ProductRepositoryInterface $subject + * @param \Magento\Catalog\Api\Data\ProductInterface $product + * @return \Magento\Catalog\Api\Data\ProductInterface + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function afterGet( + \Magento\Catalog\Api\ProductRepositoryInterface $subject, + \Magento\Catalog\Api\Data\ProductInterface $product + ) { + if($product->getExtensionAttributes() && $product->getExtensionAttributes()->getAttachments()) { + return $product; + } + + if(!$product->getExtensionAttributes()) { + $productExtension = $this->productExtensionFactory->create(); + $product->setExtensionAttributes($productExtension); + } + + $attachmentIds = []; + $attachments = $this->productAttachment->getAttachment($product->getId()); + foreach ($attachments as $attachment) { + $attachmentIds[] = $attachment->getId(); + } + + $product->getExtensionAttributes()->setAttachments($attachmentIds); + + return $product; + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..eed9159 --- /dev/null +++ b/README.md @@ -0,0 +1,107 @@ +# Magento 2 Product Attachment +Magento 2 Product Attachments extension allows admin to upload numerous file formats: Pdf, Zip, MOV, Excel or Word, etc for enriching maximally informative product pages. Grasp customers’ attention by adding eye-catching icons to attachment files thus customers recognize the file type they open or download. + +## Highlight features for for Product Attachments +- Support diverse downloadable file formats +- Upload attachments with ease: Drag and drop! +- Upload file attachments directly or using links +- View attachments in order page & product page +- Files are displayed with an icon, title, and size +- Customers can download files in a blink of the eye +- Localize attachment names for multi-language +- Assign a single attachment to many products +- Effortlessly edit file attachments visibility +- Restrict by customer groups and store views +- Customize icons matching with attachments type +- Manage and expand the icon list effortlessly +- User-friendly configuration in the backend + +## 1. Documentation + +- [Installation guide](https://ecomteck.com/magento-2-tutorials/install-magento-2-extension/) +- [Download from our Live site](https://ecomteck.com/downloads/magento-2-product-attachments-pro/) +- [Get Free Support](https://ecomteck.com/ask-question/) +- [Get Custom Work](https://ecomteck.com/contact) + +### Backend +update soon. +#### Configuration +update soon. +#### Management +update soon. + +### Frontend +update soon. +## Introduction installation: + +### 2 - Installation Magento 2 Product Attachment extension +#### Manual Installation +Install Product Attachment extension for Magento2 + * Download the extension + * Unzip the file + * Create a folder {Magento root}/app/code/Ecomteck/ProductAttachment + * Copy the content from the unzip folder + + +##### Using Composer + +``` +composer require ecomteck/module-product-attachment + +``` + +### 2 - Enable And Install the extension + * php bin/magento module:enable Ecomteck_ProductAttachment + * php bin/magento setup:upgrade + * php bin/magento setup:static-content:deploy -f + * php bin/magento cache:clean + +### 3 - See results +update soon. + +## ScreenShots +update soon. + +## Conclusion +Magento 2 Product Attachments extension allows admin to upload numerous file formats: Pdf, Zip, MOV, Excel or Word, etc for enriching maximally informative product pages. Grasp customers’ attention by adding eye-catching icons to attachment files thus customers recognize the file type they open or download. + +**People also search:** +- Magento 2 product attachments extension +- Product attachments for Magento 2 +- Attach files for Magento 2 +- Magento 2 product attachment tutorial +- Ecomteck Magento 2 Product Attachments +- Product Attachments for Magento 2 free +- product attachments module +- Magento 2 downloadable product attachments +- Magento 2 product attachments review +- Magento 2 product attachments seller price comparison +- Demo Magento 2 product attachments +- Magento 2 product attachments extension template +- Magento 2 product attachments seller groups +- Magento 2 product attachments design +- Best Magento 2 product attachments +- Top Magento 2 product attachments +- Magento 2 files upload +- Magento 2 product attachments features +- Magento 2 product attachments software +- Websites use Magento 2 product attachments +- Magento 2 product attachments price +- Magento 2 product attachments users +- Online demo Magento 2 product attachments +- Online tutorial Magento 2 product attachments +- Magento 2 product attachments extension videos +- product attachments for Magento 2 +- product attachments Magento 2 extension +- magento product attachments +- magento attach files +- magento attach files extension +- Product Attachments +- magento file attachments +- File attached extension +- Magento 2 product file attachments + + +**Other free extension on Github** +- [Magento 2 Order Comments](https://github.com/ecomteck/magento2-order-comments) +- [Magento 2 Social Login](https://github.com/ecomteck/magento-2-social-login) diff --git a/Setup/InstallSchema.php b/Setup/InstallSchema.php new file mode 100644 index 0000000..d452305 --- /dev/null +++ b/Setup/InstallSchema.php @@ -0,0 +1,204 @@ +startSetup(); + + /* + * Drop tables if exists + */ + + $installer->getConnection()->dropTable($installer->getTable('ecomteck_productattachment')); + $installer->getConnection()->dropTable($installer->getTable('ecomteck_productattachment_fileicon')); + + /** + * Creating table ecomteck_productattachment + */ + $table_ecomteck_productattachment = $installer->getConnection()->newTable($installer->getTable('ecomteck_productattachment')); + + $table_ecomteck_productattachment->addColumn( + 'productattach_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], + 'Entity Id' + ); + + $table_ecomteck_productattachment->addColumn( + 'name', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 255, + ['nullable' => true], + 'Name' + ); + + $table_ecomteck_productattachment->addColumn( + 'description', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 255, + ['nullable' => true,'default' => null], + 'Description' + ); + + $table_ecomteck_productattachment->addColumn( + 'file', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 255, + ['nullable' => true,'default' => null], + 'Content' + ); + + $table_ecomteck_productattachment->addColumn( + 'file_ext', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 255, + ['nullable' => true,'default' => null], + 'File Extension' + ); + + $table_ecomteck_productattachment->addColumn( + 'url', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + null, + ['nullable' => true,'default' => null], + 'ProductAttachment image media path' + ); + + $table_ecomteck_productattachment->addColumn( + 'store', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + null, + ['nullable' => true,'default' => null], + 'Store' + ); + + $table_ecomteck_productattachment->addColumn( + 'customer_group', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + null, + ['nullable' => true,'default' => null], + 'Customer Group' + ); + + $table_ecomteck_productattachment->addColumn( + 'products', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + null, + ['nullable' => true,'default' => null], + 'Assigned Products' + ); + + $table_ecomteck_productattachment->addColumn( + 'active', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['nullable' => false, 'default' => '0'], + 'Active' + ); + + $table_ecomteck_productattachment->addColumn( + 'visible_scope', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + 1, + ['nullable' => false, 'default' => '0'], + 'Visible to people who have not purchased this item' + ); + + $table_ecomteck_productattachment->addColumn( + 'created_at', + \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, + null, + ['nullable' => false], + 'Created At' + ); + + $table_ecomteck_productattachment->addColumn( + 'published_at', + \Magento\Framework\DB\Ddl\Table::TYPE_DATE, + null, + ['nullable' => true,'default' => null], + 'World publish date' + ); + + $table_ecomteck_productattachment->addIndex( + $installer->getIdxName( + 'Prince_productattach', + ['published_at'], + \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX + ), + ['published_at'], + ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] + )->setComment('Product Attachment item'); + + $installer->getConnection()->createTable($table_ecomteck_productattachment); + + $table_ecomteck_productattachment_fileicon = $setup->getConnection()->newTable($setup->getTable('ecomteck_productattachment_fileicon')); + + $table_ecomteck_productattachment_fileicon->addColumn( + 'fileicon_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + array('identity' => true,'nullable' => false,'primary' => true,'unsigned' => true,), + 'Entity ID' + ); + + $table_ecomteck_productattachment_fileicon->addColumn( + 'icon_ext', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + null, + [], + 'icon_ext' + ); + + $table_ecomteck_productattachment_fileicon->addColumn( + 'icon_image', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + null, + [], + 'icon_image' + ); + + $setup->getConnection()->createTable($table_ecomteck_productattachment_fileicon); + + $installer->endSetup(); + } +} diff --git a/Ui/Component/Listing/Column/CustomerGroup.php b/Ui/Component/Listing/Column/CustomerGroup.php new file mode 100644 index 0000000..1e4a57d --- /dev/null +++ b/Ui/Component/Listing/Column/CustomerGroup.php @@ -0,0 +1,82 @@ +_customerGroup = $customerGroup; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + */ + public function prepareDataSource(array $dataSource) + { + if (isset($dataSource['data']['items'])) { + $fieldName = $this->getData('customer_group'); + foreach ($dataSource['data']['items'] as &$items) { + $groups = explode(',', $items['customer_group']); + $customers = []; + foreach ($groups as $key => $group) { + $customer = $this->_customerGroup->load($group); + $customers[$key] = $customer->getCustomerGroupCode(); + } + $items['customer_group'] = implode(' - ', $customers); + } + } + return $dataSource; + } +} diff --git a/Ui/Component/Listing/Column/Download.php b/Ui/Component/Listing/Column/Download.php new file mode 100644 index 0000000..db2bc50 --- /dev/null +++ b/Ui/Component/Listing/Column/Download.php @@ -0,0 +1,93 @@ +urlBuilder = $urlBuilder; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + */ + public function prepareDataSource(array $dataSource) + { + if (isset($dataSource['data']['items'])) { + foreach ($dataSource['data']['items'] as & $item) { + if (isset($item['file'])) { + $url = str_replace('index.php', '', $this->urlBuilder->getBaseUrl()) . 'pub/media/productattachment'.$item['file']; + $item[$this->getData('name')] = [ + 'edit' => [ + 'href' => $url, + 'label' => __('Download') + ] + ]; + } elseif (isset($item['url'])) { + $url = $item['url']; + $item[$this->getData('name')] = [ + 'edit' => [ + 'href' => $url, + 'label' => __('Goto URL') + ] + ]; + } + } + } + + return $dataSource; + } +} diff --git a/Ui/Component/Listing/Column/File.php b/Ui/Component/Listing/Column/File.php new file mode 100644 index 0000000..34795b1 --- /dev/null +++ b/Ui/Component/Listing/Column/File.php @@ -0,0 +1,69 @@ +storeManager = $storeManager; + $this->assetRepo = $assetRepo; + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function prepareDataSource(array $dataSource) + { + if (isset($dataSource['data']['items'])) { + $path = $this->storeManager->getStore()->getBaseUrl( + \Magento\Framework\UrlInterface::URL_TYPE_MEDIA + ).'fileicon/tmp/icon/'; + + $baseImage = $this->assetRepo->getUrl('Ecomteck_ProductAttachment::images/faq.png'); + foreach ($dataSource['data']['items'] as & $item) { + if ($item['icon_image']) { + $item['icon_image' . '_style'] = 'width: 30px'; + $item['icon_image' . '_src'] = $path.$item['icon_image']; + $item['icon_image' . '_alt'] = $item['icon_ext']; + $item['icon_image' . '_orig_src'] = $path.$item['icon_image']; + } else { + $item['icon_image' . '_style'] = 'width: 30px'; + $item['icon_image' . '_src'] = $baseImage; + $item['icon_image' . '_alt'] = 'Faq'; + $item['icon_image' . '_orig_src'] = $baseImage; + } + } + } + + return $dataSource; + } +} diff --git a/Ui/Component/Listing/Column/FileIconActions.php b/Ui/Component/Listing/Column/FileIconActions.php new file mode 100644 index 0000000..97a783f --- /dev/null +++ b/Ui/Component/Listing/Column/FileIconActions.php @@ -0,0 +1,98 @@ +urlBuilder = $urlBuilder; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + */ + public function prepareDataSource(array $dataSource) + { + if (isset($dataSource['data']['items'])) { + foreach ($dataSource['data']['items'] as & $item) { + if (isset($item['fileicon_id'])) { + $item[$this->getData('name')] = [ + 'edit' => [ + 'href' => $this->urlBuilder->getUrl( + static::URL_PATH_EDIT, + [ + 'fileicon_id' => $item['fileicon_id'] + ] + ), + 'label' => __('Edit') + ], + 'delete' => [ + 'href' => $this->urlBuilder->getUrl( + static::URL_PATH_DELETE, + [ + 'fileicon_id' => $item['fileicon_id'] + ] + ), + 'label' => __('Delete'), + 'confirm' => [ + 'title' => __('Delete "${ $.$data.icon_ext }"'), + 'message' => __('Are you sure you wan\'t to delete a "${ $.$data.icon_ext }" record?') + ] + ] + ]; + } + } + } + + return $dataSource; + } +} diff --git a/Ui/Component/Listing/Column/ProductAttachmentActions.php b/Ui/Component/Listing/Column/ProductAttachmentActions.php new file mode 100644 index 0000000..d7180f4 --- /dev/null +++ b/Ui/Component/Listing/Column/ProductAttachmentActions.php @@ -0,0 +1,106 @@ +urlBuilder = $urlBuilder; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + */ + public function prepareDataSource(array $dataSource) + { + if (isset($dataSource['data']['items'])) { + foreach ($dataSource['data']['items'] as & $item) { + if (isset($item['productattach_id'])) { + $item[$this->getData('name')] = [ + 'edit' => [ + 'href' => $this->urlBuilder->getUrl( + static::URL_PATH_EDIT, + [ + 'productattach_id' => $item['productattach_id'] + ] + ), + 'label' => __('Edit') + ], + 'delete' => [ + 'href' => $this->urlBuilder->getUrl( + static::URL_PATH_DELETE, + [ + 'productattach_id' => $item['productattach_id'] + ] + ), + 'label' => __('Delete'), + 'confirm' => [ + 'title' => __('Delete "${ $.$data.name }"'), + 'message' => __('Are you sure you wan\'t to delete a "${ $.$data.name }" record?') + ] + ] + ]; + } + } + } + + return $dataSource; + } +} diff --git a/Ui/Component/Listing/Column/Status.php b/Ui/Component/Listing/Column/Status.php new file mode 100644 index 0000000..f9a8393 --- /dev/null +++ b/Ui/Component/Listing/Column/Status.php @@ -0,0 +1,83 @@ +Enabled'; + } else { + $items['active'] = 'Disabled'; + } + } + } + return $dataSource; + } + + /** + * @return array + */ + public function toOptionArray() + { + return [['value' => 1, 'label' => __('Enable')], ['value' => 0, 'label' => __('Disable')]]; + } +} diff --git a/Ui/Component/Listing/Column/Store.php b/Ui/Component/Listing/Column/Store.php new file mode 100644 index 0000000..b87d37b --- /dev/null +++ b/Ui/Component/Listing/Column/Store.php @@ -0,0 +1,83 @@ +_systemStore = $systemStore; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function prepareDataSource(array $dataSource) + { + if (isset($dataSource['data']['items'])) { + $fieldName = $this->getData('store'); + foreach ($dataSource['data']['items'] as &$items) { + $stores = explode(',', $items['store']); + $storeArray = []; + foreach ($stores as $key => $store) { + $storeArray[$key] = $this->_systemStore->getStore($store)->getName(); + } + $items['store'] = implode(' - ', $storeArray); + } + } + + return $dataSource; + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..d279075 --- /dev/null +++ b/composer.json @@ -0,0 +1,35 @@ +{ + "name": "ecomteck/module-product-attachment", + "description": "Magento 2 Product Attachments extension allows admin to upload numerous file formats: Pdf, Zip, MOV, Excel or Word, etc for enriching maximally informative product pages. Grasp customers’ attention by adding eye-catching icons to attachment files thus customers recognize the file type they open or download.", + "type": "magento2-module", + "keywords": [ + "ecomteck", + "product attachments", + "Magento 2 product attachments extension", + "Attach files for Magento 2", + "Magento 2 product attachments users", + "Product Attachments for Magento 2 free", + "product attachments module", + "Magento 2 downloadable product attachments" + ], + "version": "1.1.0", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "authors": [ + { + "name": "Ecomteck", + "email": "ecomteck@gmail.com", + "role": "Magento 2 Extension Solutions" + } + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Ecomteck\\ProductAttachment\\": "" + } + } +} diff --git a/etc/acl.xml b/etc/acl.xml new file mode 100644 index 0000000..a5d8993 --- /dev/null +++ b/etc/acl.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/adminhtml/menu.xml b/etc/adminhtml/menu.xml new file mode 100644 index 0000000..47af829 --- /dev/null +++ b/etc/adminhtml/menu.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/etc/adminhtml/routes.xml b/etc/adminhtml/routes.xml new file mode 100644 index 0000000..56f5f5c --- /dev/null +++ b/etc/adminhtml/routes.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml new file mode 100644 index 0000000..8056811 --- /dev/null +++ b/etc/adminhtml/system.xml @@ -0,0 +1,37 @@ + + + + + + +
+ separator-top + + ecomteck + Ecomteck_ProductAttachment::config_productattachment + + + + + Magento\Config\Model\Config\Source\Yesno + + + + Magento\Config\Model\Config\Source\Yesno + + + + Magento\Config\Model\Config\Source\Yesno + + + + Magento\Config\Model\Config\Source\Yesno + + + + + +
+
+
+ diff --git a/etc/config.xml b/etc/config.xml new file mode 100644 index 0000000..aa9cf80 --- /dev/null +++ b/etc/config.xml @@ -0,0 +1,14 @@ + + + + + + 1 + 0 + 1 + 1 + Product Attachment + + + + diff --git a/etc/di.xml b/etc/di.xml new file mode 100644 index 0000000..8ab8512 --- /dev/null +++ b/etc/di.xml @@ -0,0 +1,28 @@ + + + + + + + ecomteck_productattachment + Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment\Collection + + + + + + Ecomteck\ProductAttachment\Model\ResourceModel\ProductAttachment\Grid\Collection + Ecomteck\ProductAttachment\Model\ResourceModel\FileIcon\Grid\Collection + + + + + + ecomteck_productattachment_fileicon + Ecomteck\ProductAttachment\Model\ResourceModel\FileIcon\Collection + + + + + + \ No newline at end of file diff --git a/etc/extension_attributes.xml b/etc/extension_attributes.xml new file mode 100644 index 0000000..6676a76 --- /dev/null +++ b/etc/extension_attributes.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml new file mode 100644 index 0000000..5242845 --- /dev/null +++ b/etc/frontend/di.xml @@ -0,0 +1,4 @@ + + + + diff --git a/etc/frontend/routes.xml b/etc/frontend/routes.xml new file mode 100644 index 0000000..c116f79 --- /dev/null +++ b/etc/frontend/routes.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/etc/module.xml b/etc/module.xml new file mode 100644 index 0000000..754e7f6 --- /dev/null +++ b/etc/module.xml @@ -0,0 +1,4 @@ + + + + diff --git a/etc/webapi.xml b/etc/webapi.xml new file mode 100644 index 0000000..a72dc99 --- /dev/null +++ b/etc/webapi.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/i18n/en_US.csv b/i18n/en_US.csv new file mode 100644 index 0000000..f5b9a38 --- /dev/null +++ b/i18n/en_US.csv @@ -0,0 +1 @@ +"Site ProductAttachment","Site ProductAttachment" \ No newline at end of file diff --git a/registration.php b/registration.php new file mode 100644 index 0000000..21868e0 --- /dev/null +++ b/registration.php @@ -0,0 +1,7 @@ + + + + + + + + + diff --git a/view/adminhtml/layout/productattachment_fileicon_index.xml b/view/adminhtml/layout/productattachment_fileicon_index.xml new file mode 100644 index 0000000..b1054da --- /dev/null +++ b/view/adminhtml/layout/productattachment_fileicon_index.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/view/adminhtml/layout/productattachment_fileicon_new.xml b/view/adminhtml/layout/productattachment_fileicon_new.xml new file mode 100644 index 0000000..17fbd90 --- /dev/null +++ b/view/adminhtml/layout/productattachment_fileicon_new.xml @@ -0,0 +1,4 @@ + + + + diff --git a/view/adminhtml/layout/productattachment_index_edit.xml b/view/adminhtml/layout/productattachment_index_edit.xml new file mode 100644 index 0000000..4cc1798 --- /dev/null +++ b/view/adminhtml/layout/productattachment_index_edit.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + main_section + productattachment_edit_tab_main + + + attachment_products + + Select Products + Select Products + + ajax + + + + + + diff --git a/view/adminhtml/layout/productattachment_index_index.xml b/view/adminhtml/layout/productattachment_index_index.xml new file mode 100644 index 0000000..3b5cca7 --- /dev/null +++ b/view/adminhtml/layout/productattachment_index_index.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/view/adminhtml/layout/productattachment_index_new.xml b/view/adminhtml/layout/productattachment_index_new.xml new file mode 100644 index 0000000..030401b --- /dev/null +++ b/view/adminhtml/layout/productattachment_index_new.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/view/adminhtml/layout/productattachment_index_products.xml b/view/adminhtml/layout/productattachment_index_products.xml new file mode 100644 index 0000000..bab72ce --- /dev/null +++ b/view/adminhtml/layout/productattachment_index_products.xml @@ -0,0 +1,14 @@ + + + + + + + productattach.edit.tab.products + getSelectedProducts + products + index_products + + + + diff --git a/view/adminhtml/layout/productattachment_index_productsgrid.xml b/view/adminhtml/layout/productattachment_index_productsgrid.xml new file mode 100644 index 0000000..a5b9e01 --- /dev/null +++ b/view/adminhtml/layout/productattachment_index_productsgrid.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/view/adminhtml/ui_component/productattachment_fileicon_form.xml b/view/adminhtml/ui_component/productattachment_fileicon_form.xml new file mode 100644 index 0000000..8cedd23 --- /dev/null +++ b/view/adminhtml/ui_component/productattachment_fileicon_form.xml @@ -0,0 +1,84 @@ + +
+ + + productattachment_fileicon_form.fileicon_form_data_source + productattachment_fileicon_form.fileicon_form_data_source + + General Information + + data + productattachment_fileicon_form + + templates/form/collapsible + + Ecomteck\ProductAttachment\Block\Adminhtml\FileIcon\Edit\BackButton + Ecomteck\ProductAttachment\Block\Adminhtml\FileIcon\Edit\DeleteButton + Ecomteck\ProductAttachment\Block\Adminhtml\FileIcon\Edit\SaveButton + Ecomteck\ProductAttachment\Block\Adminhtml\FileIcon\Edit\SaveAndContinueButton + + + + + Ecomteck\ProductAttachment\Model\FileIcon\DataProvider + fileicon_form_data_source + fileicon_id + fileicon_id + + + + + + + + + Magento_Ui/js/form/provider + + + +
+ + + + + + + + + text + File Extension/Type + input + FileIcon + 30 + icon_ext + For ex. png txt zip + + true + + + + + + + + string + FileIcon + Icon Image + true + imageUploader + ui/form/element/uploader/uploader + Ecomteck_ProductAttachment/image-preview + true + 40 + Don't upload big sized icon image. + + + + + true + + + + +
+
diff --git a/view/adminhtml/ui_component/productattachment_fileicon_index.xml b/view/adminhtml/ui_component/productattachment_fileicon_index.xml new file mode 100644 index 0000000..4f76b04 --- /dev/null +++ b/view/adminhtml/ui_component/productattachment_fileicon_index.xml @@ -0,0 +1,121 @@ + ++ + Magento\Framework\View\Element\UiComponent\Context + productattachment_fileicon_index + + + + productattachment_fileicon_index.productattachment_fileicon_grid_data_source + productattachment_fileicon_index.productattachment_fileicon_grid_data_source + + productattachment_fileicon_columns + + + add + Add new File Icon + primary + */*/new + + + + + + Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider + productattachment_fileicon_grid_data_source + fileicon_id + id + + + Magento_Ui/js/grid/provider + + + fileicon_id + + + + + + + + + true + + + + + + + + + + + + productattachment_fileicon_index.productattachment_fileicon_index.productattachment_fileicon_columns.ids + true + fileicon_id + + + false + + + + + productattachment_fileicon_index.productattachment_fileicon_index.productattachment_fileicon_columns_editor + startEdit + + ${ $.$data.rowIndex } + true + + + + + + + + + 10 + text + asc + ID + + + + + + + 20 + text + File Type + + text + + false + + + + + + + + + 40 + Ecomteck_ProductAttachment/grid/cells/thumbnail + Magento_Ui/js/grid/columns/thumbnail + false + icon_ext + 0 + Icon Image + + + + + + + 50 + fileicon_id + + + + + diff --git a/view/adminhtml/ui_component/productattachment_grid_index.xml b/view/adminhtml/ui_component/productattachment_grid_index.xml new file mode 100644 index 0000000..05035e9 --- /dev/null +++ b/view/adminhtml/ui_component/productattachment_grid_index.xml @@ -0,0 +1,177 @@ + ++ + Magento\Framework\View\Element\UiComponent\Context + productattachment_grid_index + + + + productattachment_grid_index.productattachment_grid_index_data_source + productattachment_grid_index.productattachment_grid_index_data_source + + productattachment_grid_index_columns + + + add + Add New Attachment + primary + */*/new + + + + + + Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider + productattachment_grid_index_data_source + productattach_id + id + + + Magento_Ui/js/grid/provider + + + productattach_id + + + + + + + + + ui/grid/toolbar + + + + + true + + + + + + productattachment_grid_index.productattachment_grid_index.productattachment_grid_index_columns.ids + productattach_id + + + + + + delete + Delete Attachment(s) + + + Delete Attachment(s) + Are you sure you wan't to delete selected Attachment(s)? + + + + + + + + + + + + + + + + productattachment_grid_index.productattachment_grid_index.productattachment_grid_index_columns_editor + startEdit + + ${ $.$data.rowIndex } + true + + + + + + + + + productattach_id + + + + + + + text + ID + + + + + + + text + Name + + + + + + + File + 20 + + + + + + Magento\Customer\Model\Config\Source\Group + + select + multiselect + Customer Group + + + + + + Magento\Store\Model\System\Store + + select + multiselect + Store + + + + + + Ecomteck\ProductAttachment\Model\Config\Source\Status + + select + multiselect + Status + ui/grid/cells/html + + + + + + + text + Visible Scope + + + + + + + file + File Download + + + + + + + productattach_id + + + + + diff --git a/view/adminhtml/web/images/csv.png b/view/adminhtml/web/images/csv.png new file mode 100644 index 0000000000000000000000000000000000000000..3eec22e98d21e743c1b4f3dae0bf91d70f3d6289 GIT binary patch literal 1353 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 Q_W%F@07*qoM6N<$f>NuM^#A|> literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/exe.png b/view/adminhtml/web/images/exe.png new file mode 100644 index 0000000000000000000000000000000000000000..8c53ebb21882121e0e57f9ad5e4a848400094468 GIT binary patch literal 1347 zcmV-J1-$x+P)m z@`(yDsPCt3Pak$&H=oI5vQhKIf(BLGdx>d#)Z{^6(NDA4>}h81vMlQ%+qVCXl&8|f zBA`t~K1n8%*GCDS2m-*&_rzkc&stksr-qIl3qldGD4WfGo=&H$!URnu0bu4<$8q+j zQmN@>$BZSRh*+Si2O1k2Z!E`oA_@RAx5VS|gXwg-dPLtVK`0`u!NI{VEX$f1B97-mWv;BMmH?pw?Gxr17Hj-Z~7JCFhm*-feNrk{n>xFmk25_hxXZy(%fk=nj z$4>xJ3lsL1>%P3ZJJt=j!|fA#4wQpQBOrNV`DN_`OdS?U2tGl+Us_LIn@Er-i5YdJO8+Pv>9CSZq z<`KU=`3V@WIdH40e(>!}PrQOZet#IiS5Xs<_auJC-nH&ka%hE!^!s{=c&}WECn8gs`ItwEwqef?Hm}>=NQ5{11nlf=_I%l8 z-3N&1pl#bLTUuJ?5Ef8S^w5#e;Rb2|;K#BeJL?ZELZ*T9%MAXI1m$asctS*V`_DZa( zvsCF^NIv22#LV2Ts@D}r)iMw1zvwtlanhe19!EsW02DusH2CBmAd+cb@05joTPTzO z5qXN4s|ut_ht?3$T+6Z+s_GgdS`6TZ5&!qiZ2mU1nLz2%04$on;r#}HypIqC1Z`wj`qSbC z07n44Q~T)FebaBdWuvOBC#J|R(o;ZRU*AAFovw+R)C-1T zEse4Xe1CyVCUdTHSMOsWH`J0C0JA|b+f|zJ-(&g2Ip8=Q{6{xQHG!MUt~3&nF_>}V zeW4jOCWQc@u{}EUrs6wR?7R0{R`j9xR}ecEHVH9002ovPDHLk FV1lflYB2x+ literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/gif.png b/view/adminhtml/web/images/gif.png new file mode 100644 index 0000000000000000000000000000000000000000..f1aa6c89aa40322f99dcc93dd0227dd3b72298ff GIT binary patch literal 1233 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 M07*qoM6N<$f{;pDjQ{`u literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/pdf.png b/view/adminhtml/web/images/pdf.png new file mode 100644 index 0000000000000000000000000000000000000000..81edd3c14937b6f94ec59f9cc530a765b98f9dfd GIT binary patch literal 1323 zcmV+`1=RY9P)^5YxV($-Tg$$J6Qbugu&RkH=T1QmKCe z<*78W0O%Bv&mxh?bwPrwK>(QfKEp6RPb3lzWyf9(LIKg9PN%;xO|!9_plT8TW=>d^ zbs`pv&GQ{|H3%-`t*z|_KhD)C0L;9+wzl>w(=-=c(RVrs1w=fX&7O?M<4s;p z)hqza90hPH5{WdI^6}irt~Qu?6u{mq`5A_>7C@h?tX-(+2N)%$74V&#|R$2+7H2`k&9W3Iy{sDm820J@DjnUE3H_NA4 z8bo9PIIpUw=XZ5|*RrTV#($?q*%QAL(YBS_ z4xPwm?IXLrUdh{$M= z1bziv5Rs9>=e&sI9kz_aHXhnMD*|>~|caEFo=kej3;umJV=iIKxo0e@oe2Re8F6F1*14P8k90E`$B2NPl0D}$^ z1~b4knbgwN~L-L^Z-C2k!Xm;V*3Hy1>oF7Um_~* zFX|XOqN>Gu4FF=!7-r58$@S&VX*oTx8Ne$<#OZYUW@h$^9WhO_CY#MR6nn(B?N5tM z>jvAl&nak=>(1%{-vWrJ5kM;d6iJo9#e6>h1`(}e<{Ce_MdYtcCi6W6Z@XOp_IMVm z*hXgC_Co+x)YsQ9Gz_CzRrmXiW#+fqcYd;hm=={=*Vh$b=6xvf&?O>wN2Adr0HCTg zHa519nU_0UItunWw|G?@4u`|LNlTv*2~DwynfYN4+bsYdE&l$$f5*|n%q=CtM@3{! z+Y9e>19ZP1E|cm9391m10NPh<`)Dyhdptd-dIc(ozX6;E@P5m>-N)wLxp2FxY$c|^ z6X_~ocz8Htn&yo`le!@k3grd{1};B&D0RE7)CI`T09we$A_(*_mrN!vbsrph3}kN) zMtKry77LnfrTGO~6-ny-M>oj=0xzvdB>>*rM`={^3(b@Pw9 h^x|}p@j$MW;Xj_hycyD@U|j$J002ovPDHLkV1mlBWN82Z literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/png.png b/view/adminhtml/web/images/png.png new file mode 100644 index 0000000000000000000000000000000000000000..b084c6f270713d596a03cd16a6b56451283b03df GIT binary patch literal 1299 zcmV+u1?>8XP)8!>B9A<4z)m$E1*A`{ZAu%JZjVhL~Zrn9Ct?82j*hF?|Gl^dCq)4=bRw~p#9V1Gtp<} z2XVqeEb2MA@rmz@F@5oPJQ-HU4(e1f_Y%{lu;M{r(XW!pl;VzF3tAw}gB0LZq0{Wjsd{Tvnwhp4#Z-y@q==Q!ca)K>2&&A*L7=xNaY*= z%-jgzU?dW$&BX~k$Zj;4xfj63!FaZ9KMbJ5x3Acy3P6qf%C>m`4(3BnEN>zZX?A<* z0uaq+!tQ+OOFBF4PQYZhm-QMLh{*9J*Ia$zCJK-X!vTg0Yu8|S3Y8WZ{?5rD~g7mN7Le*hrA#@5zWySKOZqrz?G1`&Ax z&Zz34acyls)=g_$s^Iq-m^5gyh;C_*`py>L0QL3tBdV*bFJGVKK>R^OtD0AB-c%n*^&{d`qj0pQI{ZBkXAb{uDn z<2a)MJOtoumj0SlC2a;!@ax6A0x0G_JuRn;$vX#S{CqZW$DKSXpPkw}~*qL=#l zM0BoyN-*;amSr9GJntvZ^L`VNi$wHXmj2x*);(IIxu4F8vIZOgGXUHL;PtMquFK4v z0Dx#TI>{JwKt%Rt59~P34iR}HQ#+ZNKM;}ovc-w0g`nL9_$e%ai1cNq$zQ6vDH4fP zh)4tgRCTOv+v`G8I6D>$;;=^=~4Ah#V)PodBNAE;h!TP|#z($^j_$HtGU+rn|fQ zROUOW>I%!U-U5&ik@G}!G@VXc1B*oDLMoN&f}qvcWWc>pUIA3K+89%xqi>9=-aepd zZDV6&GZBpk03!O(7_-1}oCm6^s_I1K2gh+b|7U{veGFA$H%&$n;=WiiOC4rloqIMW5SMrmBeR#8NQ|L7(ePvB@# zMgqVgJ(u$X&2?iqz)*mT^gK|O2wcP#^srHSd8o_;;7YEJ{{TdDyM`PGeR2Q*002ov JPDHLkV1jBPaBBbn literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/tgz.png b/view/adminhtml/web/images/tgz.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa280c949f7cdbba0dee22b0f0ffa8442fe32a8 GIT binary patch literal 1270 zcmVGBdj~EZrsPm(0W5`<*l2H}~E-b7u%17&v~u z12gtoFHTU1K@-0o+V+iY+cSwoA`>)^>D8%XKTJ$-22Jh-7X3Vv$y{XS5zDgHC6mdi zKzYh7ECBjMpP*_o0A}tk z6bffzvDng*V{W9NfLNufU$(cmH=aqa=EW9%WCo> zRkHywb0>ha(P*^UjpJF!ZZw!V4d75Qo@tsJ0E{^Hm0Oe#G+8fwum-@{Qpm|?Vgw?c z-(EQbL@Su^NvZTrCr+3r0DFFWRj+}o5k0@@n!69&LO3cth5S5>jB(Vatr|LZ zCYQ5MGPC!$Cl3RaS_Ai~>PJ7mwq-y5{_6<<-+GaSor@Sy`9=I(^620jRG`fwk`9uf zWCJ2%i^%2q2Y~Es|1^NyEIltGQ&$cE;*om$*ugE!iFlu@NMY9z@UtKIDV0j~%x{dv zV!McF*f5MWs@enKEmhr@N~MOcaC&-r>ZYcqwi3}{0HOIgL}X8P2|Zeu*I@v+_|W9b zK-{vdOIMwb%*@Q}C!*(_$Q>OWcN>N=CL)^2WX2{ZC!Y+5!)*Wt=X06)!3+DIZd$(c z_*nwhIi$P(HNea!fJOj~B9g7Gtvz5E#_IrDocN|`8UPxZIRfCZ`uh6SsygbHpNP5% z`g5sz=5+ZDn7!Bw)6>&YBHCUGUqmj3LZKvpb~lcy-l0mDochZB6gn9Sg+5i)BVO_2 za5VK4$le`H z@-?VgCTO;m8fImcC8_t1ZjuOryUKDU07c4yE2?=zbKO`pun^#K><6k9o{QLkerGGa gxKLs|kaz3&4L~zJHD}xQcs`$R zi(IpohGLR+UH6Ob?(X&|;(81KRqX;Wkxr*KmDE0vNFE#^>I@6~IIk{niV9vJUn21g5Ckua zNQeHvIyRHsAR=b~bcn22>>L0OfHDF>Zxo|HcmBI38`&1m^X_mQ=Y*<0QcfYs0r7(m z49t8I1Bn8Vobi4CvqGVe22k?-&N6zB?|b+%fgVocAxQv=$m5n}?IHP&>$)!iI8jam zW6S`A`=e;vXJ?a5ArWZxOj9lPz6fIP%JG{22a>WLplXPmpAYp7A0TuUvP8aOz$dF^W;Kjz(dh#K Z{{bKiEsb!5j+g)d002ovPDHLkV1jfM?mqwk literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/unknown.png b/view/adminhtml/web/images/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..a05d67872f9400676d95bc034525600c56429946 GIT binary patch literal 542 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8wRq zxP?KOkzv*x2?hqn1D-C9AsLNtZ`fyxI7&2pobTr7D(J$&5_CKBgL21$rD9@D^{Yg# ziA6nS=3ui9)H$k=wc1yUb)%=?R=y@BuEvIC9*c^^suN=J&d;42$(|@@@ovV z?3{jcX+TGk`=OZM2Hlc1N9H~(U;oBu%5#RehZ6H1vd2BnSoCMFar^D9+lnL3Y?$U} zbG$R^Hp{+mwuP&dw@62C-8P@|v-zdpEVaTxt@j=TINwjaTDbE4ArZS?3Ht-4HXJkR zRdzES^IN&d?rwpGC^s_b*nxwW-Ut(eO3z+wL7LqI3EqLr(B5Nn=(2tGAUq zcG3~9m;*-l%6j^zb%hal^PAl~GZWM5vdhxe~vD&hgJ$=dccH3oTs;5f09CH`e{=j;fw{~(w_nH6U zNv!i8aDD50vAgT|#GjKdl}z2yDQ>ZDmyF*dwtEi~+AEv>F)Q}$=8iokwC^GFv(jjr znJht{{8tB*bvfi=MgOWBFPImnf85*Onxp(;qp3>*bP0l+XkKSJC5! literal 0 HcmV?d00001 diff --git a/view/adminhtml/web/images/zip.png b/view/adminhtml/web/images/zip.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa280c949f7cdbba0dee22b0f0ffa8442fe32a8 GIT binary patch literal 1270 zcmVGBdj~EZrsPm(0W5`<*l2H}~E-b7u%17&v~u z12gtoFHTU1K@-0o+V+iY+cSwoA`>)^>D8%XKTJ$-22Jh-7X3Vv$y{XS5zDgHC6mdi zKzYh7ECBjMpP*_o0A}tk z6bffzvDng*V{W9NfLNufU$(cmH=aqa=EW9%WCo> zRkHywb0>ha(P*^UjpJF!ZZw!V4d75Qo@tsJ0E{^Hm0Oe#G+8fwum-@{Qpm|?Vgw?c z-(EQbL@Su^NvZTrCr+3r0DFFWRj+}o5k0@@n!69&LO3cth5S5>jB(Vatr|LZ zCYQ5MGPC!$Cl3RaS_Ai~>PJ7mwq-y5{_6<<-+GaSor@Sy`9=I(^620jRG`fwk`9uf zWCJ2%i^%2q2Y~Es|1^NyEIltGQ&$cE;*om$*ugE!iFlu@NMY9z@UtKIDV0j~%x{dv zV!McF*f5MWs@enKEmhr@N~MOcaC&-r>ZYcqwi3}{0HOIgL}X8P2|Zeu*I@v+_|W9b zK-{vdOIMwb%*@Q}C!*(_$Q>OWcN>N=CL)^2WX2{ZC!Y+5!)*Wt=X06)!3+DIZd$(c z_*nwhIi$P(HNea!fJOj~B9g7Gtvz5E#_IrDocN|`8UPxZIRfCZ`uh6SsygbHpNP5% z`g5sz=5+ZDn7!Bw)6>&YBHCUGUqmj3LZKvpb~lcy-l0mDochZB6gn9Sg+5i)BVO_2 za5VK4$le`H z@-?VgCTO;m8fImcC8_t1ZjuOryUKDU07c4yE2?=zbKO`pun^#K><6k9o{QLkerGGa gxKLs|kaz3&4 diff --git a/view/adminhtml/web/template/image-preview.html b/view/adminhtml/web/template/image-preview.html new file mode 100644 index 0000000..c5576de --- /dev/null +++ b/view/adminhtml/web/template/image-preview.html @@ -0,0 +1,29 @@ +
+
+ + + + +
+ +
+
+ +
+
+ x +
+
\ No newline at end of file diff --git a/view/frontend/layout/catalog_product_view.xml b/view/frontend/layout/catalog_product_view.xml new file mode 100644 index 0000000..44b7100 --- /dev/null +++ b/view/frontend/layout/catalog_product_view.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/view/frontend/layout/productattachment_order_attachment.xml b/view/frontend/layout/productattachment_order_attachment.xml new file mode 100644 index 0000000..81509d6 --- /dev/null +++ b/view/frontend/layout/productattachment_order_attachment.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/view/frontend/layout/productattachment_order_attachment_renderers.xml b/view/frontend/layout/productattachment_order_attachment_renderers.xml new file mode 100644 index 0000000..78a2851 --- /dev/null +++ b/view/frontend/layout/productattachment_order_attachment_renderers.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/view/frontend/layout/sales_order_info_links.xml b/view/frontend/layout/sales_order_info_links.xml new file mode 100644 index 0000000..4ca27bc --- /dev/null +++ b/view/frontend/layout/sales_order_info_links.xml @@ -0,0 +1,21 @@ + + + + + + + + + productattachment/order/attachment + Product Attachments + + + + + + diff --git a/view/frontend/templates/attachment.phtml b/view/frontend/templates/attachment.phtml new file mode 100644 index 0000000..856b812 --- /dev/null +++ b/view/frontend/templates/attachment.phtml @@ -0,0 +1,34 @@ + +isEnable()): ?> + getCurrentId(); ?> + getAttachment($productId); ?> + getConfig('productattachment/general/attachmentsize'); ?> + + + getActive()) : ?> +
+ getFile() && $block->fileExists($attachment->getFile())) : ?> + +
+ +
+ getName(); ?> +
+ + getFileSize($attachment->getFile()).')' ?> + + + getUrl()) : ?> + +
+ +
+ getName(); ?> +
+ +
+ + + \ No newline at end of file diff --git a/view/frontend/templates/order/attachment.phtml b/view/frontend/templates/order/attachment.phtml new file mode 100644 index 0000000..596e072 --- /dev/null +++ b/view/frontend/templates/order/attachment.phtml @@ -0,0 +1,13 @@ + +
+ getChildHtml('attachment_items') ?> + +
diff --git a/view/frontend/templates/order/attachment_items.phtml b/view/frontend/templates/order/attachment_items.phtml new file mode 100644 index 0000000..588b143 --- /dev/null +++ b/view/frontend/templates/order/attachment_items.phtml @@ -0,0 +1,44 @@ + +getOrderAttachment(); +?> +
+ + + + + + + + + + + + getActive()) : ?> + getFile() && $block->fileExists($attachment->getFile())) : ?> + getFile(); ?> + + + + + + + + + + +
+ getName() ?> + + +
+ +
+ getName(); ?> +
+
+ getStatus() ?> +
+
\ No newline at end of file diff --git a/view/frontend/templates/order/items.phtml b/view/frontend/templates/order/items.phtml new file mode 100644 index 0000000..0f3236e --- /dev/null +++ b/view/frontend/templates/order/items.phtml @@ -0,0 +1,53 @@ + +getOrder() ?> + +getInvoiceCollection() as $_invoice): ?> +
+ getIncrementId() ?> + + + +
+
+ + + + + + + + + + + + getAllItems(); ?> + + getOrderItem()->getParentItem()) : ?> + + getItemHtml($_item) ?> + + + + + getInvoiceTotalsHtml($_invoice) ?> + +
+
+getInvoiceCommentsHtml($_invoice) ?> + diff --git a/view/frontend/web/images/csv.png b/view/frontend/web/images/csv.png new file mode 100644 index 0000000000000000000000000000000000000000..8b763280f3e9d113bd5322af53ef8c0fa7f2d871 GIT binary patch literal 1293 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 Q-T(jq07*qoM6N<$f_f0Ok^lez literal 0 HcmV?d00001 diff --git a/view/frontend/web/images/link.png b/view/frontend/web/images/link.png new file mode 100644 index 0000000000000000000000000000000000000000..9a38602fb14a9797483ce3a16dd016acb31751c4 GIT binary patch literal 677 zcmV;W0$TlvP)c`m-9Wp54q8>}0#Ff?N+pz}IFK5M1UA^FgES8)c8zHN ziFJL>`9Ixz&b8q`OFUe>|MdApIN~J|F+auUP3`09$@6DkInv0=8NT*w4shM=9>00} z?t^cDkff+zbH5PDE%2`(GXVn9eYqRN6JYlHRBBZ!wJPSI|3`dnc?DUPJs|-%^PXW) zESKo_O#m*N4G!`J=9S=GPUKODNIW!Ndi>WN46FggatUW>b5uCwuyBBF+Z0P*Fn)S6@l^|M8E=aWo|H;^C`brm5s`Y^#R+00000 LNkvXXu0mjfEpspj literal 0 HcmV?d00001 diff --git a/view/frontend/web/images/mov.png b/view/frontend/web/images/mov.png new file mode 100644 index 0000000000000000000000000000000000000000..acb58d6304959ea8050749594b55d622ab034b9b GIT binary patch literal 658 zcmV;D0&V??P))a=z!hpXYhcdwAi04*|3lqdlLNAIWqwv(kMsq%W(ZO|KdOBmhlb zzJcl5{!(mS^6Op2@{^VO`KfvVR_i`mXSsR!v+m(iUxR@9!>~d{@#5G$KXteOA;O~u z>8|9`>5e&ZarZ$WDt)-I@ zgexQ$1BeF-3Sg}bIoJ*J{y-xUQOx~F9wP5GtYFZB82H_Nw&H>-HVi>9z9T=5>`XX4 zCcgQR@@=pV08e>rc>CtUDE0Mhfc#t{zmlf8UNiLo3p*??Y%iTHZk-IkmI;qQbE{*` z@AjF2AdEFDyn0IaC# sX=hrJWZD1ZKf)CoUd~Vajj%(FUjfV4(oYdvF#rGn07*qoM6N<$g3d=FZ~y=R literal 0 HcmV?d00001 diff --git a/view/frontend/web/images/pdf.png b/view/frontend/web/images/pdf.png new file mode 100644 index 0000000000000000000000000000000000000000..277fe30995992c3c95905b35ba88c141dc74dfce GIT binary patch literal 1006 zcmVX;z3HQr?emv18qd534s=>@f31t zFDVwOIVc1?G&E4^SEDvjEUiT%nu`qqg)|?#Y4&4w=0D@?l4WTpHF@CA>iYHI9etwVwpiE7nP$-3AWMt%6e}DgkZQJpZ zWA|df&ty;nI1XalXwxJ}N;;jUSS&I$G<3ALxA!vNmy`#h?v149H8Fin%@=4Mi<6hV2L?ehl4~vI!nPah}s3bwocqbhq0=mLgH{@tx?&BI87v59Nc0{`1%*L4x`kZ24q8pXeU73TlK`0g4HmY2!*4We%Th8h_m+tWkw z-4C$DtvU$Ttt^*dyxJPno!Q_^$FK+9VfpkK%!%tXoExS7$V+GeyKe~V)30a>&MD+7 zj&1jfvRsS^`pQMtzMe*Wh1=PI)qjRs<>RbApeS3Z@;MaX`hF!TA`%t@h+!aq{*F2~ zg!{sas8}5P{qrQnB_D_?>t4aH97|6tQeMWe7>x%w2M^(nUBq8sr})}&8e8_`Iu6v< zRHcCk!+7KeJgxBzBP^C%S8%7N5J#XciK#W#>{&boKv|?r6EBlNCzE)#4VCT#j%6Wt z?}o+xFW=z&T%ZV4vN%9PR~J?)g}b(fv$%-a(gI6MWM*gasp0@)S>aYhV#=_9I1sH4 ziGBN!d-sT07M9l3x3v**94sIPB&zpfXsttu|A?BK2b&e?RfPs*tC#=WxIrPE#>(YD zYl@dHA%WOc3coZ^o`mo7x5#El{K@y(_bx;@Aovb`^`-cMl#<~7{mNw&;A{Q(zGCJa c=MG!^2U+XI@oH~2^Z)<=07*qoM6N<$f?B-hZ2$lO literal 0 HcmV?d00001 diff --git a/view/frontend/web/images/png.png b/view/frontend/web/images/png.png new file mode 100644 index 0000000000000000000000000000000000000000..94da0d6585664e40a8e743852fcdad4fa0d22efa GIT binary patch literal 677 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 T-Z?Os00000NkvXXu0mjf*k86A literal 0 HcmV?d00001 diff --git a/view/frontend/web/images/unknown.png b/view/frontend/web/images/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..2141a6539f8cf87b55bae05a97062e19c6c0e179 GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEX7WqAsj$Z!;#Vf4nJ za0`PlBg3pYARWIvT^vI^I^SO1@5SsWaQtI`y+TrQ@*5WJwMm(aC!F*8Ae)o3=8X=I z%O}2RW>GhyIQF&t;QAJJ>qO(kh&ysJ71ib5A|jt!TW`+1`Sb0$O*-{0yfO zI{(Cmrq+b?#P6+t8wJl@@DVbI#kK{l1u;-(Htt`byW+TPjZm8w$_h{KMRM!})cR^~P&iQ;YQ` l)oA=@50ZFnS9tbI4P)$c)$S<^SAv3u!PC{xWt~$(69D4lirWAH literal 0 HcmV?d00001 diff --git a/view/frontend/web/images/xls.png b/view/frontend/web/images/xls.png new file mode 100644 index 0000000000000000000000000000000000000000..7082b6400a11035ab92cd3855a9e796e197690a1 GIT binary patch literal 1263 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