';
+}
+
+?>
diff --git a/app/design/adminhtml/default/default/template/bitpay/system/config/field/header.phtml b/app/design/adminhtml/default/default/template/bitpay/system/config/field/header.phtml
new file mode 100644
index 0000000..6c74aed
--- /dev/null
+++ b/app/design/adminhtml/default/default/template/bitpay/system/config/field/header.phtml
@@ -0,0 +1,18 @@
+' .
+ '' .
+ 'Support' .
+ 'Sign Up' .
+ 'Login' .
+ '';
+
+?>
diff --git a/app/design/frontend/base/default/layout/bitcoins.xml b/app/design/frontend/base/default/layout/bitcoins.xml
deleted file mode 100644
index e2ae5ad..0000000
--- a/app/design/frontend/base/default/layout/bitcoins.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/design/frontend/base/default/layout/bitpay.xml b/app/design/frontend/base/default/layout/bitpay.xml
new file mode 100644
index 0000000..f90422b
--- /dev/null
+++ b/app/design/frontend/base/default/layout/bitpay.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/design/frontend/base/default/template/bitcoins/iframe.phtml b/app/design/frontend/base/default/template/bitcoins/iframe.phtml
deleted file mode 100644
index 617f652..0000000
--- a/app/design/frontend/base/default/template/bitcoins/iframe.phtml
+++ /dev/null
@@ -1,34 +0,0 @@
-GetIframeUrl();
-switch($url){
- case 'notbitpay': break; // customer is using another payment method
- case 'paid':
- echo 'Order payment received. Place Order to complete.'; break;
- case 'disabled':
- echo 'Please click Place Order to continue to bitpay.com.'; break;
- case false:
- echo 'Error creating invoice. Please try again or try another payment solution.'; break;
- default:
- echo ''; break;
-}
-$quoteId = $this->GetQuoteId();
-?>
-
-getRequest();
-$url = Mage::getUrl('bitpay_callback/index/checkForPayment/');
-if ($request->getScheme() == 'https')
- $url = str_replace('http://', 'https://', $url);
-?>
-
\ No newline at end of file
diff --git a/app/design/frontend/base/default/template/bitpay/form/bitpay.phtml b/app/design/frontend/base/default/template/bitpay/form/bitpay.phtml
new file mode 100644
index 0000000..87091e0
--- /dev/null
+++ b/app/design/frontend/base/default/template/bitpay/form/bitpay.phtml
@@ -0,0 +1,17 @@
+getMethodCode();
+if (Mage::getStoreConfig('payment/bitpay/fullscreen')) {
+ echo '
' .
+ '
You will be transfered to BitPay to complete your purchase when using this payment method.
' .
+ '
';
+}
+?>
diff --git a/app/design/frontend/base/default/template/bitpay/iframe.phtml b/app/design/frontend/base/default/template/bitpay/iframe.phtml
new file mode 100644
index 0000000..50143d8
--- /dev/null
+++ b/app/design/frontend/base/default/template/bitpay/iframe.phtml
@@ -0,0 +1,92 @@
+getIframeUrl();
+switch($url) {
+ case 'notbitpay':
+ break; // customer is using another payment method
+ case 'paid':
+ echo 'Order payment received. Place Order to complete.';
+ break;
+ case 'disabled':
+ echo 'Please click Place Order to continue to bitpay.com.';
+ break;
+ case false:
+ echo 'Error creating invoice. Please try again or try another payment solution.';
+ break;
+ default:
+ echo '';
+ break;
+}
+$quoteId = $this->getQuote()->getId();
+$request = Mage::app()->getRequest();
+$url = Mage::getUrl('bitpay/index/index/');
+if ($request->getScheme() == 'https') {
+ $url = str_replace('http://', 'https://', $url);
+}
+
+?>
+
+
+
diff --git a/app/design/frontend/base/default/template/bitpay/info/default.phtml b/app/design/frontend/base/default/template/bitpay/info/default.phtml
new file mode 100644
index 0000000..905db79
--- /dev/null
+++ b/app/design/frontend/base/default/template/bitpay/info/default.phtml
@@ -0,0 +1,10 @@
+' . $this->escapeHtml($this->getMethod()->getTitle()) . '';
+
+echo $this->getChildHtml();
+?>
diff --git a/app/design/frontend/base/default/template/bitpay/json.phtml b/app/design/frontend/base/default/template/bitpay/json.phtml
new file mode 100644
index 0000000..f6802fd
--- /dev/null
+++ b/app/design/frontend/base/default/template/bitpay/json.phtml
@@ -0,0 +1,9 @@
+
+{
+ "paid": isPaid(); ?>
+}
diff --git a/app/etc/modules/Bitpay_Bitcoins.xml b/app/etc/modules/Bitpay_Bitcoins.xml
deleted file mode 100644
index aadee6e..0000000
--- a/app/etc/modules/Bitpay_Bitcoins.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
- true
- community
-
-
-
-
-
-
diff --git a/app/etc/modules/Bitpay_Core.xml b/app/etc/modules/Bitpay_Core.xml
new file mode 100644
index 0000000..896fa96
--- /dev/null
+++ b/app/etc/modules/Bitpay_Core.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+ true
+ community
+
+
+
+
+
+
diff --git a/app/locale/en_US/Bitpay_Core.csv b/app/locale/en_US/Bitpay_Core.csv
new file mode 100644
index 0000000..bc98c80
--- /dev/null
+++ b/app/locale/en_US/Bitpay_Core.csv
@@ -0,0 +1,15 @@
+"Enabled","Enabled"
+"Title","Title"
+"Network","Network"
+"Debug","Debug"
+"New","New"
+"Paid","Paid"
+"Confirmed","Confirmed"
+"Complete","Complete"
+"Expired","Expired"
+"Invalid","Invalid"
+"Low","Low"
+"Medium","Medium"
+"High","High"
+"Livenet","Livenet"
+"Testnet","Testnet"
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..7cb68f3
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/build.properties b/build/build.properties
new file mode 100644
index 0000000..d10344e
--- /dev/null
+++ b/build/build.properties
@@ -0,0 +1,154 @@
+# The MIT License (MIT)
+#
+# 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
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Running a build locally, this also is used
+# to define all the default properties.
+db.user=root
+db.pass=
+db.name=magento
+db.host=127.0.0.1
+magento.version=1.9.0.1
+magento.baseurl=http://www.localhost.com
+
+####
+#
+# This properties file is used to configure the entire build. The purpose of
+# this file is so that it is easy to drop it into a project and change a few
+# of these settings and have a build run successfully.
+#
+# NOTE: You may still need to take a look at and edit `phpunit.xml.dist`.
+#
+
+####
+#
+# Directory Configuration
+#
+
+# The main location of all the projects source code, this should be the only
+# property that you need to change. Code can live in the root directory or it
+# can live inside of it's own directory.
+project.source=${project.basedir}
+#project.source=${project.basedir}/src
+
+# --- You shouldn't need to edit any of the below value ---
+
+# Location of all executables, this is the location on the `bin-dir` that you
+# have configured in `composer.json`. If you have not configured this in
+# 1composer.json` the default is to put it in the `vendor` directory.
+project.bindir=${project.basedir}/bin
+#project.bindir=${project.basedir}/vendor/bin
+
+# Where to put the build artifacts, cache, logs, docs, etc.
+project.builddir=${project.basedir}/build
+
+# Location of vendor directory created by composer.
+project.vendordir=${project.basedir}/vendor
+
+# build artifacts for code analysis
+project.logsdir=${project.builddir}/logs
+
+# Build artifacts that can be reused or updated, they do not need to be deleted
+# every build. These would include charts and images.
+project.cachedir=${project.builddir}/cache
+
+# Location of generated documentation such as API and code coverage
+project.docsdir=${project.builddir}/docs
+#### directory ####
+
+####
+#
+# phpunit configuration
+#
+
+# Directory that contains phpunit.xml or the phpunit.xml file itself
+phpunit.configuration=${project.builddir}/phpunit.xml.dist
+#### phpunit ####
+
+####
+#
+# phpmd configuration
+#
+
+# php source code filename or directory. Can be a comma-separated string
+phpmd.source=${project.source}
+
+# report format, text, xml, or html
+phpmd.report.format=xml
+
+# ruleset filename or a comma-separated string of rulesetfilenames
+phpmd.ruleset=${project.builddir}/rulesets/phpmd.xml
+
+# send report output to this file
+phpmd.report.file=${project.logsdir}/phpmd.xml
+
+# comma-separated string of patterns that are used to ignore directories
+phpmd.exclude=${project.bindir},${project.builddir},${project.vendordir},app/code/community/Bitpay/Bitcoins/tests
+#### phpmd ####
+
+####
+#
+# phploc Configuration
+#
+
+# Source directory of project
+phploc.source=${project.source}/
+
+# Where to put the csv log
+phploc.log.csv=${project.logsdir}/phploc.csv
+
+# Location of xml log
+phploc.log.xml=${project.logsdir}/phploc.xml
+
+# Small hack to exclude multiple directories
+phploc.exclude=vendor --exclude=build --exclude=bin --exclude=app/code/community/Bitpay/Bitcoins/tests
+#### phploc ####
+
+####
+#
+# pdepend configuration
+#
+pdepend.source=${project.source}
+pdepend.jdepend.chart=${project.cachedir}/jdepend_chart.svg
+pdepend.jdepend.xml=${project.logsdir}/jdepend.xml
+pdepend.overview.pyramid=${project.cachedir}/pyramid.svg
+pdepend.summary.xml=${project.logsdir}/jdepend_summary.xml
+pdepend.ignore=bin,build,vendor,app/code/community/Bitpay/Bitcoins/tests
+#### pdepend ####
+
+####
+#
+# phpcs configuration
+#
+phpcs.source=${project.source}
+phpcs.report.xml=${project.logsdir}/phpcs.xml
+phpcs.standard=PSR1 --standard=PSR2
+phpcs.ignore=vendor --ignore=bin --ignore=build --ignore=app/code/community/Bitpay/Bitcoins/tests/
+#### phpcs ####
+
+####
+#
+# phpdoc configuration
+#
+phpdoc.directory=${project.source}/
+phpdoc.target=${project.docsdir}/api
+phpdoc.ignore=vendor/,bin/,app/code/community/Bitpay/Bitcoins/tests/,build/
+#### phpdoc ####
diff --git a/build/n98-magerun.yaml b/build/n98-magerun.yaml
new file mode 100644
index 0000000..d797295
--- /dev/null
+++ b/build/n98-magerun.yaml
@@ -0,0 +1,28 @@
+# The MIT License (MIT)
+#
+# 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
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+commands:
+ N98\Magento\Command\Installer\InstallCommand:
+ installation:
+ defaults:
+ currency: USD
+ locale: en_US
+ timezone: America/New_York
diff --git a/build/phpunit.xml.dist b/build/phpunit.xml.dist
new file mode 100644
index 0000000..72a17db
--- /dev/null
+++ b/build/phpunit.xml.dist
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+ ../tests/
+
+
+
+
+
+ ../app/code/community/Bitpay/Core/
+ ../shell
+
+ ../app/code/community/Bitpay/Core/sql
+
+
+
+
+
+
+
+
+
diff --git a/build/rulesets/phpmd.xml b/build/rulesets/phpmd.xml
new file mode 100644
index 0000000..feb5ee7
--- /dev/null
+++ b/build/rulesets/phpmd.xml
@@ -0,0 +1,43 @@
+
+
+
+
+ Custom phpmd ruleset to be used with BitPay projects.
+
+
+
+
+
+
+
+
+
+
diff --git a/build/travis.properties b/build/travis.properties
new file mode 100644
index 0000000..a21c8f1
--- /dev/null
+++ b/build/travis.properties
@@ -0,0 +1,24 @@
+# The MIT License (MIT)
+#
+# 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
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Properties file for running a build on Travis CI
+db.user=travis
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..c33070e
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,47 @@
+{
+ "name": "bitpay/magento-plugin",
+ "description": "Bitcoin payment module using the bitpay.com service",
+ "keywords": ["magento","bitcoin", "bitcoin cash"],
+ "minimum-stability": "stable",
+ "type": "magento-plugin",
+ "homepage": "https://github.com/bitpay/magento-plugin",
+ "license": "MIT",
+ "support": {
+ "email": "support@bitpay.com",
+ "issues": "https://github.com/bitpay/magento-plugin/issues",
+ "source": "https://github.com/bitpay/magento-plugin"
+ },
+ "require": {
+ "bitpay/php-client": "~2.2"
+ },
+ "require-dev": {
+ "symfony/finder": "~2.3",
+ "symfony/process": "~2.3",
+ "phpmd/phpmd": "~2.1",
+ "phpdocumentor/phpdocumentor": "~2.7",
+ "daedalus/daedalus": "~1.0@dev",
+ "pdepend/pdepend" : "~2.0",
+ "squizlabs/php_codesniffer": "~1.5",
+ "phpunit/phpunit": "~3.7",
+ "phploc/phploc": "~2.0",
+ "fzaninotto/faker": "~1.3"
+ },
+ "config": {
+ "bin-dir": "bin"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.2.x-dev"
+ }
+ },
+ "archive": {
+ "exclude": [
+ "tests/",
+ ".gitattributes",
+ ".gitignore",
+ ".travis.yml",
+ "build/",
+ "build.xml"
+ ]
+ }
+}
diff --git a/docs/MagentoInvoiceSettings.png b/docs/MagentoInvoiceSettings.png
new file mode 100644
index 0000000..eeb0163
Binary files /dev/null and b/docs/MagentoInvoiceSettings.png differ
diff --git a/docs/MagentoSettings.png b/docs/MagentoSettings.png
new file mode 100644
index 0000000..d31bbea
Binary files /dev/null and b/docs/MagentoSettings.png differ
diff --git a/lib/Bitpay/Storage/MagentoStorage.php b/lib/Bitpay/Storage/MagentoStorage.php
new file mode 100644
index 0000000..fbff56d
--- /dev/null
+++ b/lib/Bitpay/Storage/MagentoStorage.php
@@ -0,0 +1,69 @@
+_keys[$key->getId()] = $key;
+
+ $data = serialize($key);
+ $encryptedData = \Mage::helper('core')->encrypt($data);
+ $config = new \Mage_Core_Model_Config();
+
+ if (true === isset($config) && false === empty($config)) {
+ $config->saveConfig($key->getId(), $encryptedData);
+ } else {
+ \Mage::helper('bitpay')->debugData('[ERROR] In file lib/Bitpay/Storage/MagentoStorage.php, class MagentoStorage::persist - Could not instantiate a \Mage_Core_Model_Config object.');
+ throw new \Exception('[ERROR] In file lib/Bitpay/Storage/MagentoStorage.php, class MagentoStorage::persist - Could not instantiate a \Mage_Core_Model_Config object.');
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function load($id)
+ {
+ if (true === isset($id) && true === isset($this->_keys[$id])) {
+ return $this->_keys[$id];
+ }
+
+ $entity = \Mage::getStoreConfig($id);
+
+ /**
+ * Not in database
+ */
+ if (false === isset($entity) || true === empty($entity)) {
+ \Mage::helper('bitpay')->debugData('[INFO] Call to MagentoStorage::load($id) with the id of ' . $id . ' did not return the store config parameter because it was not found in the database.');
+ throw new \Exception('[INFO] Call to MagentoStorage::load($id) with the id of ' . $id . ' did not return the store config parameter because it was not found in the database.');
+ }
+
+ $decodedEntity = unserialize(\Mage::helper('core')->decrypt($entity));
+
+ if (false === isset($decodedEntity) || true === empty($decodedEntity)) {
+ \Mage::helper('bitpay')->debugData('[INFO] Call to MagentoStorage::load($id) with the id of ' . $id . ' could not decrypt & unserialize the entity ' . $entity . '.');
+ throw new \Exception('[INFO] Call to MagentoStorage::load($id) with the id of ' . $id . ' could not decrypt & unserialize the entity ' . $entity . '.');
+ }
+
+ \Mage::helper('bitpay')->debugData('[INFO] Call to MagentoStorage::load($id) with the id of ' . $id . ' successfully decrypted & unserialized the entity ' . $entity . '.');
+
+ return $decodedEntity;
+ }
+}
diff --git a/lib/bitpay/bp_lib.php b/lib/bitpay/bp_lib.php
deleted file mode 100644
index 3ead3fb..0000000
--- a/lib/bitpay/bp_lib.php
+++ /dev/null
@@ -1,130 +0,0 @@
- curl_error($curl));
- } else {
- $response = json_decode($responseString, true);
- if (!$response)
- $response = array('error' => 'invalid json: '.$responseString);
- }
- curl_close($curl);
- return $response;
-}
-// $orderId: Used to display an orderID to the buyer. In the account summary view, this value is used to
-// identify a ledger entry if present.
-//
-// $price: by default, $price is expressed in the currency you set in bp_options.php. The currency can be
-// changed in $options.
-//
-// $posData: this field is included in status updates or requests to get an invoice. It is intended to be used by
-// the merchant to uniquely identify an order associated with an invoice in their system. Aside from that, Bit-Pay does
-// not use the data in this field. The data in this field can be anything that is meaningful to the merchant.
-//
-// $options keys can include any of:
-// ('itemDesc', 'itemCode', 'notificationEmail', 'notificationURL', 'redirectURL', 'apiKey'
-// 'currency', 'physical', 'fullNotifications', 'transactionSpeed', 'buyerName',
-// 'buyerAddress1', 'buyerAddress2', 'buyerCity', 'buyerState', 'buyerZip', 'buyerEmail', 'buyerPhone')
-// If a given option is not provided here, the value of that option will default to what is found in bp_options.php
-// (see api documentation for information on these options).
-function bpCreateInvoice($orderId, $price, $posData, $options = array()) {
- global $bpOptions;
-
- $options = array_merge($bpOptions, $options); // $options override any options found in bp_options.php
-
- $pos = array('posData' => $posData);
- if ($bpOptions['verifyPos'])
- $pos['hash'] = crypt(serialize($posData), $options['apiKey']);
- $options['posData'] = json_encode($pos);
-
- $options['orderID'] = $orderId;
- $options['price'] = $price;
-
- $postOptions = array('orderID', 'itemDesc', 'itemCode', 'notificationEmail', 'notificationURL', 'redirectURL',
- 'posData', 'price', 'currency', 'physical', 'fullNotifications', 'transactionSpeed', 'buyerName',
- 'buyerAddress1', 'buyerAddress2', 'buyerCity', 'buyerState', 'buyerZip', 'buyerEmail', 'buyerPhone');
- foreach($postOptions as $o)
- if (array_key_exists($o, $options))
- $post[$o] = $options[$o];
- $post = json_encode($post);
-
- $response = bpCurl('https://bitpay.com/api/invoice/', $options['apiKey'], $post);
-
- return $response;
-}
-
-// Call from your notification handler to convert $_POST data to an object containing invoice data
-function bpVerifyNotification($apiKey = false) {
- global $bpOptions;
- if (!$apiKey)
- $apiKey = $bpOptions['apiKey'];
-
- $post = file_get_contents("php://input");
- if (!$post)
- return 'No post data';
-
- $json = json_decode($post, true);
-
- if (is_string($json))
- return $json; // error
-
- if (!array_key_exists('posData', $json))
- return 'no posData';
-
- $posData = json_decode($json['posData'], true);
- if($bpOptions['verifyPos'] and $posData['hash'] != crypt(serialize($posData['posData']), $apiKey))
- return 'authentication failed (bad hash)';
- $json['posData'] = $posData['posData'];
-
- return $json;
-}
-
-// $options can include ('apiKey')
-function bpGetInvoice($invoiceId, $apiKey=false) {
- global $bpOptions;
- if (!$apiKey)
- $apiKey = $bpOptions['apiKey'];
-
- $response = bpCurl('https://bitpay.com/api/invoice/'.$invoiceId, $apiKey);
- if (is_string($response))
- return $response; // error
- $response['posData'] = json_decode($response['posData'], true);
- $response['posData'] = $response['posData']['posData'];
-
- return $response;
-}
-
-
-?>
\ No newline at end of file
diff --git a/lib/bitpay/bp_options.php b/lib/bitpay/bp_options.php
deleted file mode 100644
index d8d3075..0000000
--- a/lib/bitpay/bp_options.php
+++ /dev/null
@@ -1,30 +0,0 @@
-
\ No newline at end of file
diff --git a/modman b/modman
new file mode 100644
index 0000000..43f0a58
--- /dev/null
+++ b/modman
@@ -0,0 +1,40 @@
+# The MIT License (MIT)
+#
+# 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
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# Modman file generated by 'generate-modman'
+# app/code
+app/code/community/Bitpay/Core app/code/community/Bitpay/Core
+# app/etc
+app/etc/modules/Bitpay_Core.xml app/etc/modules/Bitpay_Core.xml
+# app/locale
+app/locale/en_US/Bitpay_Core.csv app/locale/en_US/Bitpay_Core.csv
+# app/design
+app/design/adminhtml/default/default/template/bitpay/info/default.phtml app/design/adminhtml/default/default/template/bitpay/info/default.phtml
+app/design/adminhtml/default/default/template/bitpay/system/config/field/header.phtml app/design/adminhtml/default/default/template/bitpay/system/config/field/header.phtml
+app/design/adminhtml/default/default/layout/bitpay.xml app/design/adminhtml/default/default/layout/bitpay.xml
+app/design/frontend/base/default/template/bitpay/iframe.phtml app/design/frontend/base/default/template/bitpay/iframe.phtml
+app/design/frontend/base/default/template/bitpay/info/default.phtml app/design/frontend/base/default/template/bitpay/info/default.phtml
+app/design/frontend/base/default/template/bitpay/json.phtml app/design/frontend/base/default/template/bitpay/json.phtml
+app/design/frontend/base/default/template/bitpay/form/bitpay.phtml app/design/frontend/base/default/template/bitpay/form/bitpay.phtml
+app/design/frontend/base/default/layout/bitpay.xml app/design/frontend/base/default/layout/bitpay.xml
+# lib
+lib/Bitpay/Storage/MagentoStorage.php lib/Bitpay/Storage/MagentoStorage.php
diff --git a/scripts/config.json b/scripts/config.json
new file mode 100644
index 0000000..412a628
--- /dev/null
+++ b/scripts/config.json
@@ -0,0 +1,11 @@
+{
+ "mysql": {
+ "host": "localhost",
+ "user": "magento",
+ "password": "magento",
+ "database": "magento"
+ },
+ "host": "http://127.0.0.1/magento/index.php/bitpay/ipn",
+ "status": "confirmed"
+}
+
diff --git a/scripts/delete.sh b/scripts/delete.sh
new file mode 100755
index 0000000..1ffb56c
--- /dev/null
+++ b/scripts/delete.sh
@@ -0,0 +1,156 @@
+#!/usr/bin/env sh
+#
+# (c) 2014 BitPay, Inc.
+#
+# Shell script that locates and removes
+# any previously installed BitPay Magento
+# plugin files.
+#
+# Written by Rich Morgan
+
+# For full transparency I've listed all the depricated files and folders
+# related to the old plugin here for your information. This is the complete
+# list of items you would want to backup and/or remove if you wanted to do
+# this by hand yourself or if you just wanted a list for tracking purposes.
+old_files[0]="/lib/bitpay/bp_config_default.php"
+old_files[1]="/lib/bitpay/bp_lib.php"
+old_files[2]="/lib/bitpay/bp_options.php"
+old_files[3]="/lib/bitpay"
+old_files[4]="/app/design/frontend/base/default/template/bitcoins/iframe.phtml"
+old_files[5]="/app/design/frontend/base/default/template/bitcoins"
+old_files[6]="/app/design/frontend/base/default/layout/bitcoins.xml"
+old_files[7]="/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn/Collection.php"
+old_files[8]="/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn"
+old_files[9]="/app/code/community/Bitpay/Bitcoins/Model/Resource/Ipn.php"
+old_files[10]="/app/code/community/Bitpay/Bitcoins/Model/PaymentMethod.php"
+old_files[11]="/app/code/community/Bitpay/Bitcoins/Model/Ipn.php"
+old_files[12]="/app/code/community/Bitpay/Bitcoins/Model/Source/Speed.php"
+old_files[13]="/app/code/community/Bitpay/Bitcoins/Model/Source"
+old_files[14]="/app/code/community/Bitpay/Bitcoins/Model/Resource"
+old_files[15]="/app/code/community/Bitpay/Bitcoins/Model"
+old_files[16]="/app/code/community/Bitpay/Bitcoins/sql/Bitcoins_setup/upgrade-0.1.0-1.0.0.php"
+old_files[17]="/app/code/community/Bitpay/Bitcoins/sql/Bitcoins_setup/upgrade-1.0.0-1.1.0.php"
+old_files[18]="/app/code/community/Bitpay/Bitcoins/sql/Bitcoins_setup"
+old_files[19]="/app/code/community/Bitpay/Bitcoins/sql"
+old_files[20]="/app/code/community/Bitpay/Bitcoins/Block/Iframe.php"
+old_files[21]="/app/code/community/Bitpay/Bitcoins/Block"
+old_files[22]="/app/code/community/Bitpay/Bitcoins/controllers/IndexController.php"
+old_files[23]="/app/code/community/Bitpay/Bitcoins/controllers"
+old_files[24]="/app/code/community/Bitpay/Bitcoins/etc/config.xml"
+old_files[25]="/app/code/community/Bitpay/Bitcoins/etc/system.xml"
+old_files[26]="/app/code/community/Bitpay/Bitcoins/etc"
+old_files[27]="/app/code/community/Bitpay/Bitcoins"
+old_files[28]="/app/code/community/Bitpay"
+old_files[29]="/app/etc/modules/Bitpay_Bitcoins.xml"
+old_files[30]="composer.json"
+old_files[31]="magento-plugin-master.zip"
+old_files[32]="modman"
+old_files[33]="README.md"
+
+CLEAN="true"
+RMOPTS="-vrfd"
+
+echo "Looking for your Magento installation. Please stand by - this may take a few minutes while I search..."
+
+# In case we have multiple Magento installs on this one
+# server, we will just take the first one and ask...
+i=`find /var /usr /opt -name Mage.php -type f | head -n 1 2>/dev/null`
+
+if [ -e $i ]
+then
+ DIR=`dirname $i`
+ cd $DIR && cd ../
+ mage_dir=`pwd`
+ echo "It looks like Magento is installed in the $mage_dir directory."
+ echo "Is this correct? (y/n) > "
+else
+ # In case we can't find the Magento folder, we are just
+ # providing a default value here. This happens to be the
+ # default for an Ubuntu-based machine, for example.
+ DIR="/var/www/html/magento"
+ cd $DIR
+ mage_dir=`pwd`
+ echo "You don't have Magento installed or this script doesn't have permissions to view the directory it's contained in."
+ echo "Should I default to $mage_dir ? (y/n) > "
+fi
+
+read answer
+
+if [ $answer = "y" ]
+then
+ echo "Attempting to delete the old plugin files now. Please stand by..."
+ for filename in "${old_files[@]}"
+ do
+ fullname=$mage_dir$filename
+ if [ -e $fullname ]
+ then
+ echo " Found $fullname - removing!"
+ rm $RMOPTS $fullname
+ else
+ echo " $filename does not exist - skipping!"
+ fi
+ done
+ echo "File removal process complete. Checking to make sure your Magento environment was completely cleaned of old BitPay files..."
+ echo ""
+ for filename in "${old_files[@]}"
+ do
+ fullname=$mage_dir$filename
+ if [ -e $fullname ]
+ then
+ echo " The old plugin file $fullname is still present!"
+ CLEAN="false"
+ else
+ echo " $filename is not present - good!"
+ fi
+ done
+ if [ $CLEAN = "false" ]
+ then
+ echo "Old BitPay plugin files are still present in your Magento directory. This is likely due to this script not having permissions to delete them. You can fix this by running this script as superuser or you can remove the files by hand."
+ else
+ echo "Good! I didn't find any remaining old BitPay plugin files in your Magento directory! You can now safely install the new BitPay plugin."
+ fi
+ echo "Process complete."
+ echo ""
+else
+ echo "Okay, please enter the path you would like me to use or QUIT if you wish to abort the process."
+ echo "Full path or QUIT ? > "
+ read answer
+ if [ $answer = "QUIT" ]
+ then
+ echo "Quitting!"
+ else
+ echo "Attempting to delete the old plugin files at the directory you provided. Please stand by..."
+ for filename in "${old_files[@]}"
+ do
+ fullname=$answer$filename
+ if [ -e $fullname ]
+ then
+ echo " Found $fullname - removing!"
+ rm $RMOPTS $fullname
+ else
+ echo " $filename does not exist - skipping!"
+ fi
+ done
+ echo "File removal process complete. Checking to make sure your Magento environment was completely cleaned of old BitPay files..."
+ echo ""
+ for filename in "${old_files[@]}"
+ do
+ fullname=$mage_dir$filename
+ if [ -e $fullname ]
+ then
+ echo " The old plugin file $fullname is still present!"
+ CLEAN="false"
+ else
+ echo " $filename is not present - good!"
+ fi
+ done
+ if [ $CLEAN = "false" ]
+ then
+ echo "Old BitPay plugin files are still present in your Magento directory. This is likely due to this script not having permissions to delete them. You can fix this by running this script as superuser or you can remove the files by hand."
+ else
+ echo "Good! I didn't find any remaining old BitPay plugin files in your Magento directory! You can now safely install the new BitPay plugin."
+ fi
+ echo "Process complete."
+ echo ""
+ fi
+fi
diff --git a/scripts/package b/scripts/package
new file mode 100755
index 0000000..fa55a52
--- /dev/null
+++ b/scripts/package
@@ -0,0 +1,154 @@
+#!/usr/bin/env php
+files()
+ ->in($vendorDir . '/bitpay/php-client/src')
+ ->exclude('Tests');
+
+foreach ($finder as $file) {
+ $path = $file->getRelativePathname();
+ $filesystem->mkdir(
+ sprintf(
+ '%s/lib/%s',
+ $tmpDistDir,
+ dirname($file->getRelativePathname())
+ )
+ );
+ $filesystem->copy(
+ $file->getRealPath(),
+ sprintf(
+ '%s/lib/%s',
+ $tmpDistDir,
+ $file->getRelativePathname()
+ ),
+ true
+ );
+}
+$filesystem->mirror('app/', sprintf('%s/app/', $tmpDistDir));
+$filesystem->mirror('lib/', sprintf('%s/lib/', $tmpDistDir));
+$filesystem->copy('LICENSE', sprintf('%s/app/code/community/Bitpay/Core/LICENSE', $tmpDistDir));
+$filesystem->copy('README.md', sprintf('%s/app/code/community/Bitpay/Core/README.md', $tmpDistDir));
+
+// All required files are in the temp. distribution directory
+
+/**
+ * Need to create the package.xml file required by Magento
+ */
+$xml = simplexml_load_string('');
+$xml->addChild('name', 'Bitpay_Core');
+$xml->addChild('version', $version);
+$xml->addChild('stability', 'stable');
+$xml->addChild('license', 'MIT')
+ ->addAttribute('uri', 'https://github.com/bitpay/magento-plugin/blob/master/LICENSE');
+$xml->addChild('channel', 'community');
+$xml->addChild('extends');
+$xml->addChild('summary', 'Accept Bitcoin and Bitcoin Cash on your Magento-based e-commerce site via BitPay.');
+$xml->addChild('description', 'Use BitPays plugin to accept Bitcoin and Bitcoin Cash payments from customers anywhere on earth. You do not need to worry about bitcoin as a currency, because the plugin uses your local currency to create a BitPay invoice. BitPay will instantly update the Magento order status once the bitcoin payment has been received.');
+$xml->addChild('notes', 'Full support for Magento 1.9');
+
+$authorsNode = $xml->addChild('authors');
+
+$authors = array(
+ array(
+ 'Integrations Team', // Name
+ 'BitPayInc', // Magento Connect Username
+ 'support@bitpay.com', // Email
+ ),
+);
+
+foreach ($authors as $author) {
+ $authorNode = $authorsNode->addChild('author');
+ $authorNode->addChild('name', $author[0]);
+ $authorNode->addChild('user', $author[1]);
+ $authorNode->addChild('email', $author[2]);
+}
+
+$xml->addChild('date', date('Y-m-d'));
+$xml->addChild('time', date('G:i:s'));
+$xml->addChild('compatible');
+$xml->addChild('dependencies');
+
+$requiredNode = $xml->addChild('required', 'php');
+$requiredNode->addAttribute('php_min', '5.4.0');
+$requiredNode->addAttribute('php_max', '7.2.0');
+
+$extensionsNode = $xml->addChild('extensions');
+
+foreach (array('openssl', 'mcrypt') as $ext) {
+ $extNode = $extensionsNode->addChild('name', $ext);
+ $extNode->addChild('min');
+ $extNode->addChild('max');
+}
+
+$targetNode = $xml->addChild('contents')->addChild('target');
+$targetNode->addAttribute('name', 'mage');
+
+$finder = new \Symfony\Component\Finder\Finder();
+$finder
+ ->files()
+ ->in($tmpDistDir);
+
+foreach ($finder as $file) {
+ $node = $targetNode;
+ $directories = explode('/', $file->getRelativePathname());
+ $filename = array_pop($directories);
+
+ for ($i = 1; $i <= count($directories); $i++) {
+ $dir = $directories[$i - 1];
+ $nodes = $node->xpath('dir[@name="' . $dir . '"]');
+ if (count($nodes)) {
+ $node = array_pop($nodes);
+ } else {
+ $node = $node->addChild('dir');
+ $node->addAttribute('name', $dir);
+ }
+ }
+
+ $fileNode = $node->addChild('file');
+ $fileNode->addAttribute('name', $file->getBaseName());
+ $fileNode->addAttribute('hash', md5_file($file->getRealPath()));
+}
+
+$xml->asXml($tmpDistDir . '/package.xml');
+
+// package.xml created, just need to tar/zip everything
+$filesystem->remove($distFile.'.zip');
+$filesystem->remove($distFile.'.tgz');
+
+$process = new \Symfony\Component\Process\Process(
+ sprintf('cd %s; tar -czf %s *', $tmpDistDir, $distFile.'.tgz')
+);
+$process->run();
+
+$process = new \Symfony\Component\Process\Process(
+ sprintf('cd %s; zip -r %s *', $tmpDistDir, $distFile.'.zip')
+);
+$process->run();
+
+// Cleanup
+$filesystem->remove($tmpDistDir);
diff --git a/scripts/send_ipn_for_last_order_created.js b/scripts/send_ipn_for_last_order_created.js
new file mode 100644
index 0000000..b52db24
--- /dev/null
+++ b/scripts/send_ipn_for_last_order_created.js
@@ -0,0 +1,95 @@
+var mysql = require('mysql');
+var format = require('string-template');
+var query = 'select * from bitpay_invoices where quote_id=(select MAX(quote_id) from bitpay_invoices)';
+var spawn = require('child_process').spawn;
+var config = require('./config.json');
+var data = {};
+var connection = mysql.createConnection(config.mysql);
+
+function postIpn() {
+ connection.connect();
+ connection.query(query, processRows);
+}
+
+function send(curl_args) {
+ var curl = spawn('curl', curl_args);
+ var stderr;
+ curl.stdout.on('data', function(data) {
+ console.log(data.toString());
+ });
+ curl.stderr.on('data', function(data) {
+ stderr = data;
+ });
+ curl.on('close', function(code) {
+ if (code === 0) {
+ console.log('curl exited successfully');
+ } else {
+ console.log('curl exited with an error: ' + stderr);
+ }
+ });
+}
+
+function processRows(err, rows, fields) {
+ if (err) {
+ throw err;
+ }
+ var curl_args = [
+ '-X', 'POST', '-H',
+ 'Content-Type: application/json',
+ '-H', "Content-Length: {length}",
+ '-H', 'Connection: close',
+ '-H', 'Accept: application/json',
+ '-d', '',
+ config.host ];
+ var convertedKeys = convertNames(fields);
+ var timeRegExp = new RegExp(/.*Time$/);
+ for (var i=0; iassertSame(
+ 'payment_bitpay.log',
+ Mage::helper('bitpay')->getLogFile()
+ );
+ }
+
+ public function testDebugData()
+ {
+ Mage::helper('bitpay')->debugData('Testing');
+ }
+
+ public function testIsDebugMode()
+ {
+ Mage::app()->getStore()->setConfig('payment/bitpay/debug', null);
+ $this->assertFalse(Mage::helper('bitpay')->isDebug());
+
+ Mage::app()->getStore()->setConfig('payment/bitpay/debug', false);
+ $this->assertFalse(Mage::helper('bitpay')->isDebug());
+
+ Mage::app()->getStore()->setConfig('payment/bitpay/debug', true);
+ $this->assertTrue(Mage::helper('bitpay')->isDebug());
+ }
+
+ public function testHasTransactionSpeedFalse()
+ {
+ Mage::app()->getStore()->setConfig('payment/bitpay/speed', null);
+
+ $this->assertFalse(Mage::helper('bitpay')->hasTransactionSpeed());
+ }
+
+ public function testHasTransactionSpeedTrue()
+ {
+ Mage::app()->getStore()->setConfig('payment/bitpay/speed', 'low');
+
+ $this->assertTrue(Mage::helper('bitpay')->hasTransactionSpeed());
+ }
+
+ /**
+ * Location where BitPay IPNs will go
+ */
+ public function testGetNotificationUrl()
+ {
+ $this->assertSame(
+ 'http://www.localhost.com/bitpay/ipn/',
+ Mage::helper('bitpay')->getNotificationUrl()
+ );
+ }
+
+ public function testGetRedirectUrl()
+ {
+ $this->assertSame(
+ 'http://www.localhost.com/checkout/onepage/success/',
+ Mage::helper('bitpay')->getRedirectUrl()
+ );
+ }
+
+ public function testRegisterAutoloader()
+ {
+ Mage::helper('bitpay')->registerAutoloader();
+ }
+
+ public function testGenerateAndSaveKeys()
+ {
+ Mage::helper('bitpay')->generateAndSaveKeys();
+ }
+
+ public function testGetSinKey()
+ {
+ Mage::helper('bitpay')->getSinKey();
+ }
+
+ private function createInvalidIpn()
+ {
+ $ipn = new Bitpay_Core_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_Core_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/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..a2a0e1a
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,18 @@
+