diff --git a/app/code/community/Bitpay/Bitcoins/Helper/Data.php b/app/code/community/Bitpay/Bitcoins/Helper/Data.php index 1b5c7f8..4d0072d 100644 --- a/app/code/community/Bitpay/Bitcoins/Helper/Data.php +++ b/app/code/community/Bitpay/Bitcoins/Helper/Data.php @@ -3,7 +3,7 @@ /** * The MIT License (MIT) * - * Copyright (c) 2011-2014 BitPay LLC + * Copyright (c) 2011-2014 BitPay, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -67,4 +67,107 @@ class Bitpay_Bitcoins_Helper_Data extends Mage_Core_Helper_Abstract return !empty($speed); } + + /** + * This method is used to removed IPN records in the database that + * are expired and update the magento orders to canceled if they have + * expired. + */ + public function cleanExpired() + { + $expiredRecords = Mage::getModel('Bitcoins/ipn')->getExpired(); + + foreach ($expiredRecords as $ipn) { + $incrementId = $ipn->getOrderId(); + if (empty($incrementId)) { + $this->logIpnParseError($ipn); + continue; + } + + // Cancel the order + $order = Mage::getModel('sales/order')->loadByIncrementId($incrementId); + $this->cancelOrder($order); + + // Delete all IPN records for order id + Mage::getModel('Bitcoins/ipn') + ->deleteByOrderId($ipn->getOrderId()); + Mage::log( + sprintf('Deleted Record: %s', $ipn->toJson()), + Zend_Log::DEBUG, + self::LOG_FILE + ); + } + } + + /** + * Log error if there is an issue parsing an IPN record + * + * @param Bitpay_Bitcoins_Model_Ipn $ipn + * @param boolean $andDelete + */ + private function logIpnParseError(Bitpay_Bitcoins_Model_Ipn $ipn, $andDelete = true) + { + Mage::log( + 'Error processing IPN record', + Zend_Log::DEBUG, + self::LOG_FILE + ); + Mage::log( + $ipn->toJson(), + Zend_Log::DEBUG, + self::LOG_FILE + ); + + if ($andDelete) { + $ipn->delete(); + Mage::log( + 'IPN record deleted from database', + Zend_Log::DEBUG, + self::LOG_FILE + ); + } + } + + /** + * This will cancel the order in the magento database, this will return + * true if the order was canceled or it will return false if the order + * was not updated. For example, if the order is complete, we don't want + * to cancel that order so this method would return false. + * + * @param Mage_Sales_Model_Order + * + * @return boolean + */ + private function cancelOrder(Mage_Sales_Model_Order $order) + { + $orderState = $order->getState(); + + /** + * These order states are useless and can just be skipped over. No + * need to cancel an order that is alread canceled. + */ + $statesWeDontCareAbout = array( + Mage_Sales_Model_Order::STATE_CANCELED, + Mage_Sales_Model_Order::STATE_CLOSED, + Mage_Sales_Model_Order::STATE_COMPLETE, + ); + + if (in_array($orderState, $statesWeDontCareAbout)) { + return false; + } + + $order->setState( + Mage_Sales_Model_Order::STATE_CANCELED, + true, + 'BitPay Invoice has expired', // Comment + false // notifiy customer? + )->save(); + Mage::log( + sprintf('Order "%s" has been canceled', $order->getIncrementId()), + Zend_Log::DEBUG, + self::LOG_FILE + ); + + return true; + } } diff --git a/app/code/community/Bitpay/Bitcoins/Model/Ipn.php b/app/code/community/Bitpay/Bitcoins/Model/Ipn.php index 37b61f2..d84012f 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Ipn.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Ipn.php @@ -31,9 +31,8 @@ class Bitpay_Bitcoins_Model_Ipn extends Mage_Core_Model_Abstract */ function _construct() { + parent::_construct(); $this->_init('Bitcoins/ipn'); - - return parent::_construct(); } /** @@ -133,4 +132,125 @@ class Bitpay_Bitcoins_Model_Ipn extends Mage_Core_Model_Abstract { return $this->GetStatusReceived($quoteId, array('confirmed', 'complete')); } + + /** + * This method returns an array of orders in the database that have paid + * using bitcoins, but are still open and we need to query the invoice + * IDs at BitPay and see if they invoice has expired, is invalid, or is + * complete. + * + * @return array + */ + public function getOpenOrders() + { + $doneCollection = $this->getCollection(); + + /** + * Get all the IPNs that have been completed + * + * SELECT + * order_id + * FROM + * bitpay_ipns + * WHERE + * status IN ('completed','invalid','expired') AND order_id IS NOT NULL + * GROUP BY + * order_id + */ + $doneCollection + ->addFieldToSelect('order_id') + ->addFieldToFilter( + 'status', + array( + 'in' => array( + 'complete', + 'invalid', + 'expired', + ) + ) + ); + $doneCollection + ->getSelect() + ->where('order_id IS NOT NULL') + ->group('order_id'); + + $collection = $this->getCollection(); + + /** + * Get all the open orders that have not received a IPN that closes + * the invoice. + * + * SELECT + * * + * FROM + * bitpay_ipns + * JOIN + * 'sales/order' ON bitpay_ipns.order_id='sales/order'.increment_id + * WHERE + * order_id NOT IN (?) AND order_id IS NOT NULL + * GROUP BY + * order_id + */ + if (0 < $doneCollection->count()) { + $collection + ->addFieldToFilter( + 'status', + array( + 'in' => $doneCollection->getColumnValues('order_id') + ) + ); + } + + $collection + ->getSelect() + ->where('order_id IS NOT NULL') + ->group('order_id'); + + return $collection->getItems(); + } + + /** + * Returns all records that have expired + */ + public function getExpired() + { + $collection = $this->getCollection(); + $now = new DateTime('now', new DateTimezone('UTC')); + + $collection + ->removeFieldFromSelect('status') + ->addFieldToFilter( + 'expiration_time', + array( + 'lteq' => $now->getTimestamp() + ) + ); + + $collection + ->getSelect() + ->group('order_id') + // Newest to oldest + ->order('expiration_time DESC'); + + return $collection->getItems(); + } + + /** + * This will delete all records that match the order id (order id is also + * the increment id of the magento order) + * + * @see Bitpay_Bitcoins_Model_Resource_Ipn_Collection::delete() + * + * @param string $orderId + */ + public function deleteByOrderId($orderId) + { + $collection = Mage::getModel('Bitcoins/ipn') + ->getCollection(); + $collection + ->getSelect() + ->where('order_id = ?', $orderId); + + $collection->delete(); + } } diff --git a/app/code/community/Bitpay/Bitcoins/Model/Observer.php b/app/code/community/Bitpay/Bitcoins/Model/Observer.php new file mode 100644 index 0000000..781e281 --- /dev/null +++ b/app/code/community/Bitpay/Bitcoins/Model/Observer.php @@ -0,0 +1,95 @@ +getLogFile() + ); + + $apiKey = Mage::getStoreConfig('payment/Bitcoins/api_key'); + + if (empty($apiKey)) { + Mage::log( + 'cronjob: Api Key not set.', + Zend_Log::ERR, + Mage::helper('bitpay')->getLogFile() + ); + return; // Api Key needs to be set + } + + + /** + * Get all of the orders that are open and have not received an IPN for + * complete, expired, or invalid. + * + * If anyone knows of a better way to do this, please let me know + */ + $orders = Mage::getModel('Bitcoins/ipn')->getOpenOrders(); + + /** + * Get all orders that have been paid using bitpay and + * are not complete/closed/etc + */ + foreach ($orders as $order) { + /** + * Query BitPay with the invoice ID to get the status. We must take + * care not to anger the API limiting gods and disable our access + * to the API. + */ + $status = null; + + // Does the order need to be updated? + // Yes? Update Order Status + // No? continue + } + + Mage::log( + 'cronjob: end', + Zend_Log::DEBUG, + Mage::helper('bitpay')->getLogFile() + ); + } + + /** + * Method that is called via the magento cron to update orders if the + * invoice has expired + */ + public function cleanExpired() + { + Mage::helper('bitpay')->cleanExpired(); + } +} diff --git a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php index f4c53f3..2df09ee 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php @@ -3,7 +3,7 @@ /** * The MIT License (MIT) * - * Copyright (c) 2011-2014 BitPay LLC + * Copyright (c) 2011-2014 BitPay, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -class Bitpay_Bitcoins_Model_Resource_Ipn extends Mage_Core_Model_Resource_Db_Abstract +class Bitpay_Bitcoins_Model_Resource_Ipn extends Mage_Core_Model_Mysql4_Abstract { protected function _construct() { diff --git a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php index 3821a8c..b5b563a 100644 --- a/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php +++ b/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php @@ -3,7 +3,7 @@ /** * The MIT License (MIT) * - * Copyright (c) 2011-2014 BitPay LLC + * Copyright (c) 2011-2014 BitPay, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,13 +24,21 @@ * THE SOFTWARE. */ -class Bitpay_Bitcoins_Model_Resource_Ipn_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract +class Bitpay_Bitcoins_Model_Resource_Ipn_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { /** */ protected function _construct() { + parent::_construct(); $this->_init('Bitcoins/ipn'); } + + public function delete() + { + foreach ($this->getItems() as $item) { + $item->delete(); + } + } } diff --git a/app/code/community/Bitpay/Bitcoins/etc/config.xml b/app/code/community/Bitpay/Bitcoins/etc/config.xml index 5d8a452..e669244 100644 --- a/app/code/community/Bitpay/Bitcoins/etc/config.xml +++ b/app/code/community/Bitpay/Bitcoins/etc/config.xml @@ -1,118 +1,136 @@ - - - - - - - standard - - Bitpay_Bitcoins - bitpay_callback - - - - - - - bitcoins.xml - - - - - - - - - 1.1.0 - - - - - - - Bitpay_Bitcoins_Block - - - - - - Bitpay_Bitcoins_Helper - - - - - - Bitpay_Bitcoins_Model - Bitcoins_resource - - - Bitpay_Bitcoins_Model_Resource - - - bitpay_ipns
-
-
-
-
- - - - - - Bitpay_Bitcoins - - - core_setup - - - - - core_write - - - - - core_read - - - -
- - - - - 1 - Bitcoins/paymentMethod - Bitcoins - low - 0 - BTC, USD, EUR, GBP, JPY, CAD, AUD, CNY, CHF, SEK, NZD, KRW, AED, AFN, ALL, AMD, ANG, AOA, ARS, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYR, BZD, CDF, CLF, CLP, COP, CRC, CVE, CZK, DJF, DKK, DOP, DZD, EEK, EGP, ETB, FJD, FKP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, ISK, JEP, JMD, JOD, KES, KGS, KHR, KMF, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LTL, LVL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRO, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SGD, SHP, SLL, SOS, SRD, STD, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, UYU, UZS, VEF, VND, VUV, WST, XAF, XAG, XAU, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL - authorize - - - -
+ + + + + + + standard + + Bitpay_Bitcoins + bitpay_callback + + + + + + + bitcoins.xml + + + + + + + + + 1.1.0 + + + + + + + Bitpay_Bitcoins_Block + + + + + + Bitpay_Bitcoins_Helper + + + + + + Bitpay_Bitcoins_Model + Bitcoins_resource + + + Bitpay_Bitcoins_Model_Resource + + + bitpay_ipns
+
+
+
+
+ + + + + + Bitpay_Bitcoins + + + core_setup + + + + + core_write + + + + + core_read + + + +
+ + + + + + + + */30 * * * * + + + Bitcoins/Observer::cleanExpired + + + + + + + + + 1 + Bitcoins/paymentMethod + Bitcoins + low + 0 + BTC, USD, EUR, GBP, JPY, CAD, AUD, CNY, CHF, SEK, NZD, KRW, AED, AFN, ALL, AMD, ANG, AOA, ARS, AWG, AZN, BAM, BBD, BDT, BGN, BHD, BIF, BMD, BND, BOB, BRL, BSD, BTN, BWP, BYR, BZD, CDF, CLF, CLP, COP, CRC, CVE, CZK, DJF, DKK, DOP, DZD, EEK, EGP, ETB, FJD, FKP, GEL, GHS, GIP, GMD, GNF, GTQ, GYD, HKD, HNL, HRK, HTG, HUF, IDR, ILS, INR, IQD, ISK, JEP, JMD, JOD, KES, KGS, KHR, KMF, KWD, KYD, KZT, LAK, LBP, LKR, LRD, LSL, LTL, LVL, LYD, MAD, MDL, MGA, MKD, MMK, MNT, MOP, MRO, MUR, MVR, MWK, MXN, MYR, MZN, NAD, NGN, NIO, NOK, NPR, OMR, PAB, PEN, PGK, PHP, PKR, PLN, PYG, QAR, RON, RSD, RUB, RWF, SAR, SBD, SCR, SDG, SGD, SHP, SLL, SOS, SRD, STD, SVC, SYP, SZL, THB, TJS, TMT, TND, TOP, TRY, TTD, TWD, TZS, UAH, UGX, UYU, UZS, VEF, VND, VUV, WST, XAF, XAG, XAU, XCD, XOF, XPF, YER, ZAR, ZMW, ZWL + authorize + + + +
diff --git a/build.xml b/build.xml index 72738c1..34e324b 100644 --- a/build.xml +++ b/build.xml @@ -123,6 +123,15 @@ --> + + + + + + + + + @@ -206,7 +215,8 @@ - + + @@ -220,22 +230,31 @@ - + - + - + + + + diff --git a/build/phpunit.xml.dist b/build/phpunit.xml.dist index 9898031..03a3d1a 100644 --- a/build/phpunit.xml.dist +++ b/build/phpunit.xml.dist @@ -46,7 +46,10 @@ ../app/code/community/Bitpay/Bitcoins/ - ../lib/bitpay + ../shell + + ../app/code/community/Bitpay/Bitcoins/sql + diff --git a/composer.json b/composer.json index d2db870..72607a7 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "pdepend/pdepend" : "1.1.0", "squizlabs/php_codesniffer": "*", "phpunit/phpunit": "*", - "phploc/phploc": "*" + "phploc/phploc": "*", + "fzaninotto/faker": "*" }, "config": { "bin-dir": "bin" diff --git a/modman b/modman index da4063c..a647434 100644 --- a/modman +++ b/modman @@ -25,3 +25,4 @@ app/design/frontend/base/default/layout/bitcoins.xml app/design/frontend/base/de app/design/frontend/base/default/template/bitcoins app/design/frontend/base/default/template/bitcoins app/etc/modules/Bitpay_Bitcoins.xml app/etc/modules/Bitpay_Bitcoins.xml lib/bitpay lib/bitpay +shell/bitpay.php shell/bitpay.php diff --git a/shell/bitpay.php b/shell/bitpay.php new file mode 100644 index 0000000..4257309 --- /dev/null +++ b/shell/bitpay.php @@ -0,0 +1,92 @@ +getArg('clean')) { + switch ($clean) { + case 'expired': + $this->cleanExpired(); + break; + default: + echo $this->usageHelp(); + return 1; + break; + } + + return 0; + } + + echo $this->usageHelp(); + } + + /** + * Removes expired IPNs from database and updates order if they are + * open + */ + public function cleanExpired() + { + Mage::helper('bitpay')->clearExpired(); + } + + /** + * Display help on how to use this bad boy + */ + public function usageHelp() + { + $figlet = new Zend_Text_Figlet( + array( + 'justification' => Zend_Text_Figlet::JUSTIFICATION_CENTER + ) + ); + + return <<render('BitPay')} + +Usage: php -f bitpay.php + + --clean Delete all IPN records based on + +List of Statuses: + + expired + +USAGE; + } +} + +$shell = new Bitpay_Shell_Bitpay(); +$shell->run(); diff --git a/tests/Bitpay/Bitcoins/Helper/DataTest.php b/tests/Bitpay/Bitcoins/Helper/DataTest.php index a5ae1d2..c077cb1 100644 --- a/tests/Bitpay/Bitcoins/Helper/DataTest.php +++ b/tests/Bitpay/Bitcoins/Helper/DataTest.php @@ -27,6 +27,13 @@ class Bitpay_Bitcoins_Helper_DataTest extends PHPUnit_Framework_TestCase { + protected static $faker; + + public static function setUpBeforeClass() + { + self::$faker = Faker\Factory::create(); + } + public function testHasApiKeyFalse() { Mage::app()->getStore()->setConfig('payment/Bitcoins/api_key', null); @@ -54,4 +61,182 @@ class Bitpay_Bitcoins_Helper_DataTest extends PHPUnit_Framework_TestCase $this->assertTrue(Mage::helper('bitpay')->hasTransactionSpeed()); } + + public function testCleanExpired() + { + // Create a few expired/invalid ipns + $invalidIpn = $this->createInvalidIpn(); + $expiredIpn = $this->createExpiredIpn(); + + // Are the IPNs in the database? + $ipn = Mage::getModel('Bitcoins/ipn'); + $dbInvalidIpn = $ipn->load($invalidIpn->getId())->toArray(); + $dbExpiredIpn = $ipn->load($expiredIpn->getId())->toArray(); + $this->assertArrayHasKey('id', $dbInvalidIpn); + $this->assertArrayHasKey('id', $dbExpiredIpn); + unset($dbInvalidIpn, $dbExpiredIpn); + + // clean them + Mage::helper('bitpay')->cleanExpired(); + + // check the database and see if they are still there + $ipn = Mage::getModel('Bitcoins/ipn'); + $dbInvalidIpn = $ipn->load($invalidIpn->getId())->toArray(); + $dbExpiredIpn = $ipn->load($expiredIpn->getId())->toArray(); + $this->assertEmpty($dbInvalidIpn); + $this->assertEmpty($dbExpiredIpn); + } + + private function createInvalidIpn() + { + $ipn = new Bitpay_Bitcoins_Model_Ipn(); + $ipn->setData( + array( + 'quote_id' => '', + 'order_id' => '', + 'invoice_id' => '', + 'url' => '', + 'pos_data' => '', + 'status' => '', + 'btc_price' => '', + 'price' => '', + 'currency' => '', + 'invoice_time' => '', + 'expiration_time' => '', + 'current_time' => '', + ) + ); + $ipn->save(); + $ipn->load($ipn->getId()); + + return $ipn; + } + + private function createExpiredIpn() + { + $order = $this->createOrder(); + $ipn = new Bitpay_Bitcoins_Model_Ipn(); + $ipn->setData( + array( + 'quote_id' => '', + 'order_id' => $order->getIncrementId(), + 'invoice_id' => '', + 'url' => '', + 'pos_data' => '', + 'status' => '', + 'btc_price' => '', + 'price' => '', + 'currency' => '', + 'invoice_time' => '', + 'expiration_time' => '', + 'current_time' => '', + ) + ); + $ipn->save(); + $ipn->load($ipn->getId()); + + return $ipn; + } + + private function createOrder() + { + $product = $this->createProduct(); + $quote = $this->createQuote(); + $quote->addProduct( + $product, + new Varien_Object( + array( + 'qty' => 1, + ) + ) + ); + $address = array( + 'firstname' => self::$faker->firstName, + 'lastname' => self::$faker->lastName, + 'company' => self::$faker->company, + 'email' => self::$faker->email, + 'city' => self::$faker->city, + 'region_id' => '', + 'region' => 'State/Province', + 'postcode' => self::$faker->postcode, + 'telephone' => self::$faker->phoneNumber, + 'country_id' => self::$faker->state, + 'customer_password' => '', + 'confirm_password' => '', + 'save_in_address_book' => 0, + 'use_for_shipping' => 1, + 'street' => array( + self::$faker->streetAddress + ), + ); + + $quote->getBillingAddress() + ->addData($address); + + $quote->getShippingAddress() + ->addData($address) + ->setShippingMethod('flatrate_flatrate') + ->setPaymentMethod('checkmo') + ->setCollectShippingRates(true) + ->collectTotals(); + + $quote + ->setCheckoutMethod('guest') + ->setCustomerId(null) + ->setCustomerEmail($address['email']) + ->setCustomerIsGuest(true) + ->setCustomerGroupId(Mage_Customer_Model_Group::NOT_LOGGED_IN_ID); + + $quote->getPayment() + ->importData(array('method' => 'checkmo')); + + $quote->save(); + + $service = Mage::getModel('sales/service_quote', $quote); + $service->submitAll(); + $order = $service->getOrder(); + + $order->save(); + $order->load($order->getId()); + + return $order; + } + + private function createProduct() + { + $product = Mage::getModel('catalog/product'); + + $product->addData( + array( + 'attribute_set_id' => 1, + 'website_ids' => array(1), + 'categories' => array(), + 'type_id' => Mage_Catalog_Model_Product_Type::TYPE_SIMPLE, + 'sku' => self::$faker->randomNumber, + 'name' => self::$faker->name, + 'weight' => self::$faker->randomDigit, + 'status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED, + 'tax_class_id' => 2, + 'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, + 'price' => self::$faker->randomFloat(2), + 'description' => self::$faker->paragraphs, + 'short_description' => self::$faker->sentence, + 'stock_data' => array( + 'is_in_stock' => 1, + 'qty' => 100, + ), + ) + ); + + $product->save(); + $product->load($product->getId()); + + return $product; + } + + private function createQuote() + { + return Mage::getModel('sales/quote') + ->setStoreId(Mage::app()->getStore('default')->getId()); + } } diff --git a/tests/Bitpay/Bitcoins/Model/PaymentMethodTest.php b/tests/Bitpay/Bitcoins/Model/PaymentMethodTest.php index 9b81e93..4040d96 100644 --- a/tests/Bitpay/Bitcoins/Model/PaymentMethodTest.php +++ b/tests/Bitpay/Bitcoins/Model/PaymentMethodTest.php @@ -3,7 +3,7 @@ /** * The MIT License (MIT) * - * Copyright (c) 2011-2014 BitPay + * Copyright (c) 2011-2014 BitPay, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 824ea24..b0a1ca1 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -3,7 +3,7 @@ /** * The MIT License (MIT) * - * Copyright (c) 2011-2014 BitPay + * Copyright (c) 2011-2014 BitPay, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,3 +31,9 @@ if ($mage = realpath(__DIR__ . '/../build/magento/app/Mage.php')) { } else { exit('Could not find Mage.php'); } + +if ($composer = realpath(__DIR__ . '/../vendor/autoload.php')) { + require_once $composer; +} else { + exit('Composer not found'); +}