├── .gitignore ├── LICENSE ├── app ├── etc │ └── modules │ │ └── Needle_CouponGenerator.xml ├── design │ └── adminhtml │ │ └── default │ │ └── default │ │ ├── layout │ │ └── coupongenerator.xml │ │ └── template │ │ └── coupongenerator │ │ └── new │ │ └── js.phtml └── code │ └── local │ └── Needle │ └── CouponGenerator │ ├── Block │ └── Admin │ │ ├── Main.php │ │ ├── New.php │ │ ├── New │ │ └── Form.php │ │ └── Main │ │ └── Grid.php │ ├── etc │ ├── config.xml │ └── api.xml │ ├── Helper │ └── Data.php │ ├── controllers │ └── AdminController.php │ └── Model │ └── Api.php ├── js └── needle │ └── needle.js ├── extras ├── testsoap.php ├── testclone.php ├── generate.php ├── coupon.almost └── coupon.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010, Needle, Inc. 2 | All rights reserved. 3 | This software may not be copied, used, modified or adapted without the express written permission of Needle, Inc. 4 | Contact code@needle.com for licensing inquiries. -------------------------------------------------------------------------------- /app/etc/modules/Needle_CouponGenerator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | local 7 | 8 | 9 | -------------------------------------------------------------------------------- /js/needle/needle.js: -------------------------------------------------------------------------------- 1 | Validation.addAllThese([ 2 | ['validate-rand_len', 'String length must be between 5 and 10.', { 3 | min : 5, 4 | max : 10, 5 | include : ['validate-digits'] 6 | }], 7 | ['validate-quantity', 'Cannot be more than 400.', { 8 | max : 400, 9 | include : ['validate-digits'] 10 | }] 11 | ]); -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/layout/coupongenerator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/coupongenerator/new/js.phtml: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /extras/testsoap.php: -------------------------------------------------------------------------------- 1 | login('needle', '123456'); 10 | 11 | $result = $client->call($session, 'salesrule.list'); 12 | 13 | // If you don't need the session anymore 14 | $client->endSession($session); 15 | 16 | print $result; 17 | 18 | ?> -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/Block/Admin/Main.php: -------------------------------------------------------------------------------- 1 | _addButtonLabel = Mage::helper('coupongenerator')->__('Generate Coupons!'); 7 | parent::__construct(); 8 | 9 | $this->_blockGroup = 'coupongenerator'; 10 | $this->_controller = 'admin_main'; 11 | $this->_headerText = Mage::helper('coupongenerator')->__('Single Use Coupons'); 12 | } 13 | } -------------------------------------------------------------------------------- /extras/testclone.php: -------------------------------------------------------------------------------- 1 | 1)); 4 | // If soap isn't default use this link instead 5 | // http://youmagentohost/api/soap/?wsdl 6 | 7 | // If somestuff requires api authentification, 8 | // we should get session token 9 | $session = $client->login('needle', '123456'); 10 | 11 | // $id = $client->call($session, 'coupongenerator.clonerule', array('2', '__NDL_RULE', 'NEEDLE7')); 12 | $result = $client->call($session, 'coupongenerator.info', 2); 13 | 14 | print_r($result); 15 | // $result = $client->call($session, 'coupongenerator.delete', $id); 16 | // If you don't need the session anymore 17 | $client->endSession($session); 18 | 19 | 20 | ?> 21 | -------------------------------------------------------------------------------- /extras/generate.php: -------------------------------------------------------------------------------- 1 | 1)); 4 | $session = $client->login('needle', '123456'); 5 | try { 6 | $id = $client->call($session, 7 | 'coupongenerator.clonerule', 8 | array($_REQUEST['id'], 9 | '__ONEUSE:'.$_REQUEST['name'], 10 | $_REQUEST['code'], 11 | $_REQUEST['expire'])); 12 | } catch (Exception $e) { 13 | echo '' . $e->getMessage() . ''; 14 | return; 15 | } 16 | echo ''; 17 | //$result = $client->call($session, 'coupongenerator.info', $id); 18 | //print_r($result); 19 | // $result = $client->call($session, 'coupongenerator.delete', $id); 20 | $client->endSession($session); 21 | ?> 22 | -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/Block/Admin/New.php: -------------------------------------------------------------------------------- 1 | _blockGroup = 'coupongenerator'; 9 | $this->_mode = 'new'; 10 | $this->_controller = 'admin'; 11 | 12 | $this->_updateButton('save', 'label', Mage::helper('customer')->__('Generate!')); 13 | } 14 | 15 | public function getHeaderText() 16 | { 17 | return Mage::helper('coupongenerator')->__('Generate New Bulk Coupon'); 18 | } 19 | 20 | public function _prepareLayout() 21 | { 22 | $this->getLayout()->getBlock('head')->addJs('needle/needle.js'); 23 | return parent::_prepareLayout(); 24 | } 25 | } -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 0.1.0 6 | 7 | 8 | 9 | 10 | 11 | Needle_CouponGenerator_Block 12 | 13 | 14 | 15 | 16 | Needle_CouponGenerator_Model 17 | 18 | 19 | 20 | 21 | Needle_CouponGenerator_Helper 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Coupon Generator 31 | 100 32 | coupongenerator/admin 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | coupongenerator.xml 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | admin 49 | 50 | Needle_CouponGenerator 51 | coupongenerator 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/Helper/Data.php: -------------------------------------------------------------------------------- 1 | load($sourceSalesruleId); 21 | 22 | 23 | if (!$parentrule->getId()) 24 | { 25 | $this->_fault('not_exists'); 26 | } 27 | $parentruleData = $parentrule->toArray(); 28 | 29 | /** 30 | * Set up the new rule by creating a new model, setting the 31 | * $newRuleData (array) to the $parentruleData (array) values 32 | * and then overriding the attributes that we care about 33 | */ 34 | $newRule = Mage::getModel('salesrule/rule'); 35 | $newRuleData = $parentruleData; 36 | unset($newRuleData['rule_id']); 37 | $newRuleData['name'] = $newName; 38 | $newRuleData['coupon_code'] = $couponCode; 39 | if(isset($expireDate)) 40 | { 41 | $newDate = Mage::app()->getLocale()->date($expireDate, Zend_Date::DATE_SHORT); 42 | $newRuleData['to_date'] = $newDate->toString('YYYY-MM-dd'); 43 | } 44 | $newRuleData['uses_per_coupon'] = '1'; 45 | $newRuleData['uses_per_customer'] = '1'; 46 | $newRuleData['is_active'] = '1'; 47 | $newRuleData['times_used'] = '0'; 48 | 49 | $newRule->setData($newRuleData); 50 | if (isset($parentruleData['conditions_serialized'])) 51 | $newRule->getConditions()->setConditions(array())->loadArray(unserialize($parentruleData['conditions_serialized'])); 52 | if (isset($parentruleData['actions_serialized'])) 53 | $newRule->getActions()->setActions(array())->loadArray(unserialize($parentruleData['actions_serialized'])); 54 | // Now try to save the child 55 | try 56 | { 57 | $newRule->save(); 58 | } 59 | catch (Mage_Core_Exception $e) 60 | { 61 | $this->_fault('data_invalid', $e->getMessage()); 62 | } 63 | 64 | return $newRule->getId(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Name 2 | **CouponGenerator** - Create and manage single-use coupons for Magento stores. 3 | 4 | # Usage 5 | 1)); 8 | $session = $client->login('username', 'password'); 9 | 10 | // Set the to your parent coupon's ID. 11 | $pId = ; 12 | 13 | // Make a SOAP call to the service, passing in options as an array. Change the obvious values in between the <> 14 | $id = $client->call($session, 'coupongenerator.clonerule', array($pId, '', '', '')); 15 | 16 | // Retrieve your new coupon and print out the object that you are returned. (This should just be a single array().) 17 | $result = $client->call($session, 'coupongenerator.info', $id); 18 | print_r($result); 19 | 20 | // Close the session now that we are done. 21 | $client->endSession($session); 22 | ?> 23 | 24 | # Description 25 | The CouponGenerator is designed for creating single-use coupons for Magento stores. It allows coupons to be generated for a single customer. It uses all data from the parent coupon, so care must be taken while creating the parent coupons. 26 | 27 | For the purpose of this document, 'coupon' is used interchangeably with 'sales rule' in the Magento world. 28 | 29 | # Store Setup Best Practices 30 | Since the CouponGenerator uses already existing coupons from which to clone new single-use coupons, it is important that the parent coupon is set up properly. 31 | 32 | ## Parent Setup 33 | * **Name** - The parent coupon name should use a meaningful prefix to set it apart from other coupons. The name of the coupon should be as descriptive as possible, while still being short enough to not mess with UIs (your custom UI and/or the magento admin UI). 34 | ** Example: _TEMPLATE:Fifty Percent Off Underwear 35 | * **Description** - The description field is very important for letting your users know what the coupon does. It is important to remember that the parent coupon's description field will be inherited directly by the new coupon. This field is currently not overridden by the cloning process. 36 | * **Status** - The parent coupon's status should be set to 'Inactive' so that the parent coupon cannot be used. 37 | * **Public in RSS Feed** - This should be set to 'No' so that the parent coupon is not publicly visible. 38 | * **Uses per coupon** - Set this to how many cloned coupons you would like to allow. The cloning process will decrement this number, and then not allow any more coupons to be cloned when it reaches zero. You can always add more coupons to the parent if you would like to allocate more. 39 | * **To Date** - If you would like all cloned To Dates to be inherited from the parent, set this date and do not pass it as part of your SOAP call. 40 | 41 | ## Caveats 42 | * The cloned coupon code must be unique. 43 | * The new coupon name does not need to be unique, but it should be something that does not clutter the store and can be sorted out of the list of results. A good example format is **__ONEUSE:Coupon Name**. This will cause the cloned coupons to be listed at the very end of the coupon list when sorted by name. 44 | 45 | ## Packaging 46 | Packaging this application for distribution is relatively simple: 47 | cd CouponGenerator 48 | tar cvzf app js CouponGenerator-.tgz 49 | 50 | ## Installation 51 | Copy the CouponGenerator-.tgz to the customer's Magento installation root and extract. Simple as that! 52 | -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/etc/api.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | coupongenerator/api 7 | Needle SalesRule Api 8 | coupongenerator 9 | 10 | 11 | Retrieve Coupons 12 | items 13 | coupongenerator/info 14 | 15 | 16 | Delete Coupons 17 | delete 18 | coupongenerator/delete 19 | 20 | 21 | Show Coupons 22 | info 23 | coupongenerator/info 24 | 25 | 26 | Clone a Coupons 27 | cloneRule 28 | coupongenerator/clonerule 29 | 30 | 31 | 32 | 33 | 101 34 | Invalid filters specified. Details in error message. 35 | 36 | 37 | 102 38 | The source rule does not exist. 39 | 40 | 41 | 103 42 | There are no uses left on the source rule. 43 | 44 | 45 | 104 46 | Something went horribly wrong while saving the data. 47 | 48 | 49 | 105 50 | Something went horribly wrong while deleting the sales rule. 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Needle CouponGenerator 59 | 3 60 | 61 | Retrieve Coupon (SalesRule) info 62 | 63 | 64 | Delete Coupon (SalesRule) 65 | 66 | 67 | Clone Coupon (SalesRule) 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/Block/Admin/New/Form.php: -------------------------------------------------------------------------------- 1 | getCollection(); 10 | // $templates->addFieldToFilter('uses_per_coupon', array('gt' => 0)); 11 | $templates->addFieldToFilter('name', array('like' => '_TEMPLATE:%')); 12 | 13 | $ruleKV = array(); 14 | 15 | foreach ($templates as $t) 16 | { 17 | $ruleKV[$t['rule_id']] = substr($t['name'], 10); 18 | } 19 | 20 | $fieldset = $form->addFieldset('new_bulkcoupon', array('legend' => Mage::helper('coupongenerator')->__('Coupon Details'))); 21 | 22 | $fieldset->addField('rule_id', 'select', array( 23 | 'name' => 'rule_id', 24 | 'title' => Mage::helper('coupongenerator')->__('Template Rule'), 25 | 'label' => Mage::helper('coupongenerator')->__('Template Rule'), 26 | 'maxlength' => '250', 27 | 'required' => true, 28 | 'values' => $ruleKV 29 | )); 30 | 31 | $fieldset->addField('prefix', 'text', array( 32 | 'name' => 'prefix', 33 | 'title' => Mage::helper('coupongenerator')->__('Coupon Prefix'), 34 | 'label' => Mage::helper('coupongenerator')->__('Coupon Prefix'), 35 | 'maxlength' => '50', 36 | 'required' => true, 37 | )); 38 | 39 | $fieldset->addField('name_prefix', 'text', array( 40 | 'name' => 'name_prefix', 41 | 'title' => Mage::helper('coupongenerator')->__('Rule Name Prefix'), 42 | 'label' => Mage::helper('coupongenerator')->__('Rule Name Prefix'), 43 | 'maxlength' => '50', 44 | 'required' => true, 45 | )); 46 | 47 | $fieldset->addField('quantity', 'text', array( 48 | 'name' => 'quantity', 49 | 'title' => Mage::helper('coupongenerator')->__('Quantity'), 50 | 'label' => Mage::helper('coupongenerator')->__('Quantity'), 51 | 'maxlength' => '50', 52 | 'class' => 'input-text required-entry validate-quantity', 53 | 'required' => true, 54 | )); 55 | 56 | $fieldset->addField('rand_len', 'text', array( 57 | 'name' => 'rand_len', 58 | 'title' => Mage::helper('coupongenerator')->__('Random String Length'), 59 | 'label' => Mage::helper('coupongenerator')->__('Random String Length'), 60 | 'maxlength' => '2', 61 | 'class' => 'input-text required-entry validate-rand_len', 62 | 'required' => true, 63 | )); 64 | 65 | $dateFormatIso = Mage::app()->getLocale()->getDateFormat( 66 | Mage_Core_Model_Locale::FORMAT_TYPE_SHORT 67 | ); 68 | 69 | $fieldset->addField('expires', 'date', array( 70 | 'name' => 'expires', 71 | 'title' => Mage::helper('coupongenerator')->__('Expires'), 72 | 'label' => Mage::helper('coupongenerator')->__('Expires'), 73 | 'input_format' => Varien_Date::DATE_INTERNAL_FORMAT, 74 | 'format' => $dateFormatIso, 75 | 'image' => $this->getSkinUrl('images/grid-cal.gif') 76 | )); 77 | 78 | $form->setMethod('post'); 79 | $form->setUseContainer(true); 80 | $form->setId('edit_form'); 81 | $form->setAction($this->getUrl('*/*/post')); 82 | 83 | $this->setForm($form); 84 | } 85 | } -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/Block/Admin/Main/Grid.php: -------------------------------------------------------------------------------- 1 | setId('coupongeneratorGrid'); 9 | $this->_controller = 'coupongenerator'; 10 | } 11 | 12 | protected function _prepareCollection() 13 | { 14 | $model = Mage::getModel('salesrule/rule'); 15 | $collection = $model->getCollection(); 16 | #$collection->addFieldToFilter('name', array('like' => '__ONEUSE:%')); 17 | $this->setCollection($collection); 18 | 19 | $this->addExportType('*/*/exportCsv', Mage::helper('coupongenerator')->__('CSV')); 20 | return parent::_prepareCollection(); 21 | } 22 | 23 | 24 | 25 | protected function _prepareColumns() 26 | { 27 | 28 | $this->addColumn('rule_id', array( 29 | 'header' => Mage::helper('coupongenerator')->__('ID'), 30 | 'align' => 'right', 31 | 'width' => '50px', 32 | 'filter_index' => 'rule_id', 33 | 'index' => 'rule_id', 34 | )); 35 | 36 | $this->addColumn('name', array( 37 | 'header' => Mage::helper('coupongenerator')->__('Rule Name'), 38 | 'align' => 'left', 39 | 'width' => '50px', 40 | 'filter_index' => 'name', 41 | 'index' => 'name', 42 | )); 43 | 44 | $this->addColumn('coupon_code', array( 45 | 'header' => Mage::helper('coupongenerator')->__('Coupon Code'), 46 | 'align' => 'left', 47 | 'width' => '150px', 48 | 'filter_index' => 'coupon_code', 49 | 'index' => 'coupon_code', 50 | 'type' => 'text', 51 | 'truncate' => 50, 52 | 'escape' => true, 53 | )); 54 | 55 | $this->addColumn('description', array( 56 | 'header' => Mage::helper('coupongenerator')->__('Coupon Description'), 57 | 'align' => 'left', 58 | 'filter_index' => 'description', 59 | 'index' => 'description', 60 | 'type' => 'text', 61 | 'escape' => true, 62 | )); 63 | 64 | $this->addColumn('action', 65 | array( 66 | 'header' => Mage::helper('coupongenerator')->__('Action'), 67 | 'width' => '150px', 68 | 'type' => 'action', 69 | 'getter' => 'getRuleId', 70 | 'actions' => array( 71 | array( 72 | 'caption' => Mage::helper('coupongenerator')->__('Delete'), 73 | 'url' => array( 74 | 'base'=>'*/*/delete' 75 | ), 76 | 'field' => 'id' 77 | ) 78 | ), 79 | 'filter' => false, 80 | 'sortable' => false, 81 | 'is_system' => true 82 | )); 83 | 84 | return parent::_prepareColumns(); 85 | } 86 | 87 | protected function _prepareMassaction() 88 | { 89 | $this->setMassactionIdField('rule_id'); 90 | $this->getMassactionBlock()->setFormFieldName('rule'); 91 | 92 | $this->getMassactionBlock()->addItem('delete', array( 93 | 'label' => Mage::helper('coupongenerator')->__('Delete'), 94 | 'url' => $this->getUrl('*/*/massDelete'), 95 | 'confirm' => Mage::helper('coupongenerator')->__('Are you sure?') 96 | )); 97 | return $this; 98 | } 99 | 100 | public function getRowUrl($row) 101 | { 102 | return $this->getUrl('adminhtml/promo_quote/edit', array( 103 | 'id' => $row->getRuleId(), 104 | )); 105 | } 106 | } -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/controllers/AdminController.php: -------------------------------------------------------------------------------- 1 | loadLayout() 22 | ->_addContent($this->getLayout()->createBlock('coupongenerator/admin_main')) 23 | ->renderLayout(); 24 | } 25 | 26 | /** 27 | * Export grid to CSV format 28 | */ 29 | public function exportCsvAction() 30 | { 31 | $fileName = 'coupons.csv'; 32 | $content = $this->getLayout()->createBlock('coupongenerator/admin_main_grid') 33 | ->getCsvFile(); 34 | 35 | $this->_prepareDownloadResponse($fileName, $content); 36 | } 37 | 38 | public function newAction() 39 | { 40 | // $this->loadLayout() 41 | // ->_addContent($this->getLayout()->createBlock('coupongenerator/admin_new')) 42 | // ->renderLayout(); 43 | 44 | $this->loadLayout(); 45 | $this->_addContent($this->getLayout()->createBlock('coupongenerator/admin_new')); 46 | $this->renderLayout(); 47 | } 48 | 49 | public function postAction() 50 | { 51 | if ($data = $this->getRequest()->getPost()) 52 | { 53 | $api = Mage::getModel('coupongenerator/api'); 54 | #$data = $this->_filterDates($data, array('expires')); 55 | 56 | $numCoupons = $this->getRequest()->getPost('quantity'); 57 | $sourceRuleID = $this->getRequest()->getPost('rule_id'); 58 | $couponPrefix = $this->getRequest()->getPost('prefix'); 59 | $namePrefix = $this->getRequest()->getPost('name_prefix'); 60 | $expireDate = $data['expires']; 61 | $strLen = $this->getRequest()->getPost('rand_len'); 62 | $parentRule = $api->info($sourceRuleID); 63 | $parentName = $parentRule['name']; 64 | 65 | Mage::log('Expire date: '.$expireDate); 66 | 67 | try 68 | { 69 | for ($i = 0; $i < $numCoupons; $i++) 70 | { 71 | $newName = $namePrefix . ":" . substr($parentName, 10); 72 | $couponCode = $couponPrefix . "-" . $this->randomString($strLen); 73 | Mage::helper('coupongenerator')->cloneRule($sourceRuleID, $newName, $couponCode, $expireDate); 74 | } 75 | Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('coupongenerator') 76 | ->__('Coupons were generated successfully!')); 77 | $this->getResponse()->setRedirect($this->getUrl('*/*/')); 78 | return; 79 | } 80 | catch (Exception $e) 81 | { 82 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 83 | } 84 | } 85 | $this->getResponse()->setRedirect($this->getUrl('*/*/')); 86 | return; 87 | } 88 | 89 | public function massDeleteAction() 90 | { 91 | $ruleIds = $this->getRequest()->getParam('rule'); 92 | if (!is_array($ruleIds)) 93 | { 94 | Mage::getSingleton('adminhtml/session')->addError(Mage::helper('adminhtml')->__('Please select rule(s)')); 95 | } 96 | else 97 | { 98 | try 99 | { 100 | $rule = Mage::getModel('salesrule/rule'); 101 | foreach ($ruleIds as $ruleId) 102 | { 103 | $rule->load($ruleId) 104 | ->delete(); 105 | } 106 | Mage::getSingleton('adminhtml/session')->addSuccess( 107 | Mage::helper('adminhtml')->__( 108 | 'Total of %d record(s) were successfully deleted', count($ruleIds) 109 | ) 110 | ); 111 | } 112 | catch (Exception $e) 113 | { 114 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 115 | } 116 | } 117 | 118 | $this->_redirect('*/*/index'); 119 | } 120 | 121 | public function deleteAction() 122 | { 123 | $ruleId = $this->getRequest()->getParam("rule_id"); 124 | try 125 | { 126 | $rule = Mage::getModel("salesrule/rule"); 127 | $rule->load($ruleId)->delete(); 128 | Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Rule was deleted')); 129 | } 130 | catch (Exception $e) 131 | { 132 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 133 | } 134 | $this->_redirect('*/*/index'); 135 | } 136 | } -------------------------------------------------------------------------------- /app/code/local/Needle/CouponGenerator/Model/Api.php: -------------------------------------------------------------------------------- 1 | getCollection(); 8 | 9 | if (is_array($filters)) 10 | { 11 | try 12 | { 13 | foreach ($filters as $field => $value) 14 | { 15 | $collection->addFieldToFilter($field, $value); 16 | } 17 | } 18 | catch (Mage_Core_Exception $e) 19 | { 20 | $this->_fault('filters_invalid', $e->getMessage()); 21 | // If we are adding filter on non-existent attribute 22 | } 23 | } 24 | 25 | $result = array(); 26 | foreach ($collection as $salesrule) 27 | { 28 | $result[] = $salesrule->toArray(); 29 | } 30 | 31 | return $result; 32 | } 33 | 34 | /** 35 | * Retrieve salesrule data 36 | * 37 | * @param int $salesruleId 38 | * @param array $attributes 39 | * @return array 40 | */ 41 | public function info($salesruleId, $attributes = null) 42 | { 43 | $salesrule = Mage::getModel('salesrule/rule')->load($salesruleId); 44 | 45 | if (!$salesrule->getId()) 46 | { 47 | $this->_fault('not_exists'); 48 | } 49 | 50 | return $salesrule->toArray(); 51 | } 52 | 53 | /** 54 | * Clone a salesrule to a single-use salesrule 55 | * 56 | * @param int $sourceSalesruleId 57 | * @param string $newName 58 | * @param string $couponCode 59 | * @param string $expireDate 60 | * @return int 61 | */ 62 | public function cloneRule($sourceSalesruleId, $newName, $couponCode, $expireDate, $numUses=1) 63 | { 64 | $numUsesPerCoupon = $numUses; 65 | $numUsesPerCustomer = 1; 66 | 67 | $parentrule = Mage::getModel('salesrule/rule')->load($sourceSalesruleId); 68 | if (!$parentrule->getId()) 69 | { 70 | $this->_fault('not_exists'); 71 | } 72 | $parentruleData = $parentrule->toArray(); 73 | if($parentruleData['uses_per_coupon'] < $numUses) 74 | { 75 | $this->_fault('no_uses_left', 'Parent coupon does not have enough uses to generate the number of uses requested.'); 76 | return 0; 77 | } 78 | 79 | /** 80 | * Set up the new rule by creating a new model, setting the 81 | * $newRuleData (array) to the $parentruleData (array) values 82 | * and then overriding the attributes that we care about 83 | */ 84 | $parentconditions = $parentrule->getConditions(); 85 | $parentactions = $parentrule->getActions(); 86 | 87 | $newRule = Mage::getModel('salesrule/rule'); 88 | $newRuleData = $parentruleData; 89 | unset($newRuleData['rule_id']); 90 | $newRuleData['name'] = $newName; 91 | $newRuleData['coupon_code'] = $couponCode; 92 | 93 | /** 94 | * Set the new rule's actions and conditions to be the same 95 | * as the parent rule's. 96 | */ 97 | 98 | /** 99 | * Set the new rule's expiration date if one was provided. 100 | */ 101 | if(isset($expireDate)) 102 | { 103 | if(preg_match('/\d{4}-\d{2}-\d{2}/i', $expireDate)) 104 | $newRuleData['to_date'] = $expireDate; 105 | else 106 | { 107 | $this->_fault('data_invalid', 'Date is in the wrong format! Expects : yyyy-mm-dd Got: ' . $expireDate); 108 | return; 109 | } 110 | } 111 | 112 | $newRuleData['uses_per_coupon'] = $numUses; 113 | $newRuleData['uses_per_customer'] = '1'; 114 | $newRuleData['is_active'] = '1'; 115 | $newRuleData['times_used'] = '0'; 116 | 117 | /** Do some stuff to the original parent now that we have set the 118 | * attributes on the child. 119 | * * Decrement uses_per_coupon 120 | * * Increment uses_per_customer 121 | */ 122 | $parentruleData['uses_per_coupon'] = $parentruleData['uses_per_coupon'] + $numUses; 123 | $parentruleData['uses_per_customer'] = $parentruleData['uses_per_customer'] + $numUses; 124 | 125 | // Set the data before trying to save it. 126 | $parentrule->setData($parentruleData); 127 | $newRule->setData($newRuleData); 128 | if (isset($parentruleData['conditions_serialized'])) 129 | $newRule->getConditions()->setConditions(array())->loadArray(unserialize($parentruleData['conditions_serialized'])); 130 | if (isset($parentruleData['actions_serialized'])) 131 | $newRule->getActions()->setActions(array())->loadArray(unserialize($parentruleData['actions_serialized'])); 132 | 133 | // Try to save the parent first 134 | try 135 | { 136 | $parentrule->save(); 137 | } 138 | catch (Mage_Core_Exception $e) 139 | { 140 | $this->_fault('data_invalid', $e->getMessage()); 141 | } 142 | 143 | // Now try to save the child 144 | try 145 | { 146 | $newRule->save(); 147 | } 148 | catch (Mage_Core_Exception $e) 149 | { 150 | $this->_fault('data_invalid', $e->getMessage()); 151 | } 152 | 153 | return $newRule->getId(); 154 | } 155 | 156 | /** 157 | * Delete salesrule 158 | * 159 | * @param int $salesruleId 160 | * @return boolean 161 | */ 162 | public function delete($salesruleId) 163 | { 164 | $salesrule = Mage::getModel('salesrule/rule')->load($salesruleId); 165 | 166 | if (!$salesrule->getId()) 167 | { 168 | $this->_fault('not_exists'); 169 | } 170 | 171 | try 172 | { 173 | $salesrule->delete(); 174 | } 175 | catch (Mage_Core_Exception $e) 176 | { 177 | $this->_fault('not_deleted', $e->getMessage()); 178 | } 179 | 180 | return true; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /extras/coupon.almost: -------------------------------------------------------------------------------- 1 | 2 | 3 | Coupon Central 4 | 54 | 56 | 57 | 58 | 173 | 174 | 175 | 176 | 177 | 178 | Coupon Generator 179 | 180 | 181 | 182 | 183 | 184 | --- Select Discount Offer --- 185 | (Nonexistent) 186 | (Already Exhausted) 187 | 1)); 189 | $session = $client->login('needle', '123456'); 190 | $filter = array(array('uses_per_coupon' => array('gt' => '0'), 'name' => array('like' => '_TEMPLATE:%'))); 191 | $result = $client->call($session, 'coupongenerator.list', $filter); 192 | //print_r($result); 193 | $count = count($result); 194 | for ($i = 0; $i < $count; $i++) { 195 | echo "" 200 | . substr($result[$i]['name'], 10) 201 | . "\n"; 202 | } 203 | $client->endSession($session); 204 | ?> 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | Comments about work... 222 | 223 | Reads rules with names like '_TEMPLATE:%' 224 | Shows matching rules in the list selector 225 | Creates child coupons 226 | Yes, a good UI person will find a lot to do here 227 | TODO: Validate the form before submitting (the current red-box thingi is not to my liking) 228 | I cannot seem to make a button behave: too difficult to go from disabled to hovering to not hovering. I give up. 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /extras/coupon.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | Coupon Central 4 | 55 | 57 | 58 | 59 | 177 | 178 | 179 | 180 | 181 | 182 | Coupon Generator 183 | 184 | 185 | --- Select Discount Offer --- 186 | (Nonexistent) 187 | (Already Exhausted) 188 | 1)); 190 | $session = $client->login('needle', '123456'); 191 | $filter = array(array('uses_per_coupon' => array('gt' => '0'), 'name' => array('like' => '_TEMPLATE:%'))); 192 | $result = $client->call($session, 'coupongenerator.list', $filter); 193 | //print_r($result); 194 | $count = count($result); 195 | for ($i = 0; $i < $count; $i++) { 196 | echo "" 201 | . substr($result[$i]['name'], 10) 202 | . "\n"; 203 | } 204 | $client->endSession($session); 205 | ?> 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | Today 214 | Tomorrow 215 | 2 days 216 | 3 days 217 | 4 days 218 | 5 days 219 | 6 days 220 | 7 days 221 | 222 | 223 | 224 | 225 | 226 | 227 | Comments about work... 228 | 229 | Reads rules with names like '_TEMPLATE:%' 230 | Shows matching rules in the list selector 231 | Creates child coupons 232 | Yes, a good UI person will find a lot to do here 233 | TODO: Validate the form before submitting (the current red-box thingi is not to my liking) 234 | I cannot seem to make a button behave: too difficult to go from disabled to hovering to not hovering. I give up. 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | --------------------------------------------------------------------------------
101
102
103
104
105