CoinSimple - Version 1.0.0

Version Notes

Initial release.

Download this release

Release Info

Developer CoinSimple
Extension CoinSimple
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (25) hide show
  1. README.md +88 -0
  2. app/code/community/Coinsimple/Coinsimple/Model/PaymentMethod.php +120 -0
  3. app/code/community/Coinsimple/Coinsimple/coinsimple_php/.gitignore +3 -0
  4. app/code/community/Coinsimple/Coinsimple/coinsimple_php/README.md +98 -0
  5. app/code/community/Coinsimple/Coinsimple/coinsimple_php/codeception.yml +10 -0
  6. app/code/community/Coinsimple/Coinsimple/coinsimple_php/composer.json +18 -0
  7. app/code/community/Coinsimple/Coinsimple/coinsimple_php/src/business.php +61 -0
  8. app/code/community/Coinsimple/Coinsimple/coinsimple_php/src/coinsimple.php +4 -0
  9. app/code/community/Coinsimple/Coinsimple/coinsimple_php/src/invoice.php +164 -0
  10. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/_bootstrap.php +2 -0
  11. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/_support/UnitHelper.php +10 -0
  12. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit.suite.yml +6 -0
  13. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/BusinessTest.php +19 -0
  14. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/InvoiceTest.php +420 -0
  15. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/UnitTester.php +268 -0
  16. app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/_bootstrap.php +2 -0
  17. app/code/community/Coinsimple/Coinsimple/controllers/CallbackController.php +49 -0
  18. app/code/community/Coinsimple/Coinsimple/controllers/RedirectController.php +9 -0
  19. app/code/community/Coinsimple/Coinsimple/etc/config.xml +65 -0
  20. app/code/community/Coinsimple/Coinsimple/etc/system.xml +74 -0
  21. app/etc/modules/Coinsimple_Coinsimple.xml +11 -0
  22. media/magento/magento-plugin-settings-configuration-payment_methods-coinsimple.png +0 -0
  23. media/magento/magento-plugin-settings-configuration-payment_methods.png +0 -0
  24. media/magento/magento-plugin-settings-configuration.png +0 -0
  25. package.xml +2 -0
README.md ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ The CoinSimple Magento plugin allows e-commerce stores to accept bitcoin through CoinSimple.
3
+
4
+ <!--more-->
5
+
6
+ ## Requirements
7
+
8
+ **A Business ID and API key from CoinSimple.com**. To find your information, go to your [CoinSimple.com](http://coinsimple.com) dashboard, select your business, and go to "Settings". You will find your *Business ID* and *API key* under "Busines Information" and "API Credentials".
9
+
10
+ ## Installation
11
+
12
+ *Do not attempt to install this plugin through the "Magento Connect Manager". Use the following instructions, instead.*
13
+
14
+ 1. [Download a zip file of the plugin](https://github.com/coinsimple/coinsimple-magento/archive/v1.zip). Extract the zip file.
15
+ 2. Copy the contents of the zip file under in the root of your Magento installation.
16
+
17
+ At this point the plugin is installed and activated but it still needs to be enabled and configured.
18
+
19
+ ## Configuration
20
+
21
+ 1. Log in to your Magento site as administration and click on "Settings" and then "Configuration".
22
+
23
+ ![Select "Settings" and then "Configuration"](/media/magento/magento-plugin-settings-configuration.png)
24
+
25
+ 2. In the screen that appears click on "Payment Methods" on the left.
26
+
27
+ ![Click on "Payment Methods"](/media/magento/magento-plugin-settings-configuration-payment_methods.png)
28
+
29
+ 5. Select "Yes" in the "Enabled" dropdown menu and enter your CoinSimple.com business ID and CoinSimple API key in the appropriate fields. Also, enter the URL of the page that your customers will be directed to after they make their payment.
30
+
31
+ ![Business ID, API key and callback URL](/media/magento/magento-plugin-settings-configuration-payment_methods-coinsimple.png)
32
+
33
+ 5. Click "Save Config".
34
+
35
+ ## Use
36
+
37
+ - When a buyer selects "Bitcoin" as their payment method, an invoice is generated at CoinSimple.
38
+ - After the buyer pays, CoinSimple directs the buyer to the page that you selected in your Settings above.
39
+
40
+ ## Support
41
+
42
+ ### CoinSimple Support
43
+
44
+ * If you are having a problem with this plugin, please use [this Github issues page](https://github.com/coinsimple/coinsimple-magento/issues) to report your problem.
45
+
46
+ ## Magento Support
47
+
48
+ * [Homepage](http://magento.com)
49
+ * [Documentation](http://docs.magentocommerce.com)
50
+ * [Community Edition Support Forums](https://www.magentocommerce.com/support/ce/)
51
+
52
+ ### Troubleshooting
53
+
54
+ * This plugin requires PHP 5.4 or higher to function correctly. Contact your webhosting provider or server administrator if you are unsure which version is installed on your web server.
55
+ * Ensure a valid SSL certificate is installed on your server. Also ensure your root CA cert is updated. If your CA cert is not current, you will see curl SSL verification errors.
56
+ * Verify that your web server is not blocking POSTs from servers it may not recognize. Double check this on your firewall as well, if one is being used.
57
+ * Check the system error log file (usually the web server error log) for any errors during CoinSimple payment attempts. If you contact CoinSimple support, they will ask to see the log file to help diagnose the problem.
58
+ * If all else fails, send an email describing your issue in detail to [support@coinsimple.com](mailto:support@coinsimple.com). In your support request, please provide:
59
+ * Magento version
60
+ * PHP version
61
+ * Other plugins installed
62
+ * Configuration settings for the CoinSimple plugin
63
+ * Screenshot of error messages, if any
64
+
65
+
66
+ ## Contribute
67
+
68
+ To contribute to this project, please fork and submit a pull request.
69
+
70
+
71
+ ## About CoinSimple
72
+
73
+ CoinSimple allows consultants and online merchants to **easily** accept bitcoins either through a bitcoin payment processor ([BitPay](http://bitpay.com), [Coinbase](http://coinbase.com), [GoCoin](http://gocoin.com)) or directly to their deterministic wallet ([Electrum](http://electrum.org), [Armory](http://bitcoinarmory.com), [Trezor](http://www.bitcointrezor.com/)) or to any non-deterministic bitcoin wallet. One can use the [CoinSimple web app](https://coinsimple.com) to issue invoices directly, Wordpress eCommerce (see [demo site](http://wordpress.coinsimple.com) or [plugin page](https://github.com/coinsimple/coinsimple-wpecommerce)), WooCommerce (see [demo site](http://woocommerce.coinsimple.com) or [plugin page](https://github.com/coinsimple/coinsimple-woocommerce)), Magento (see [demo site](http://magento.coinsimple.com) or [plugin page](https://github.com/coinsimple/coinsimple-magento)), to sell products through the respective online stores, or a "Pay in Bitcoin" button on any webpage to accept donations, payments or even sell products.
74
+
75
+ For more information about CoinSimple, please visit [CoinSimple.com](https://coinsimple.com).
76
+
77
+
78
+ ## License
79
+
80
+ The MIT License (MIT)
81
+
82
+ Copyright (c) 2014-2015 CoinSimple
83
+
84
+ 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:
85
+
86
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
87
+
88
+ 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.
app/code/community/Coinsimple/Coinsimple/Model/PaymentMethod.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Coinsimple_Coinsimple_Model_PaymentMethod extends Mage_Payment_Model_Method_Abstract
4
+ {
5
+ protected $_code = 'Coinsimple';
6
+
7
+ /**
8
+ * Is this payment method a gateway (online auth/charge) ?
9
+ */
10
+ protected $_isGateway = true;
11
+
12
+ /**
13
+ * Can authorize online?
14
+ */
15
+ protected $_canAuthorize = true;
16
+
17
+ /**
18
+ * Can capture funds online?
19
+ */
20
+ protected $_canCapture = false;
21
+
22
+ /**
23
+ * Can capture partial amounts online?
24
+ */
25
+ protected $_canCapturePartial = false;
26
+
27
+ /**
28
+ * Can refund online?
29
+ */
30
+ protected $_canRefund = false;
31
+
32
+ /**
33
+ * Can void transactions online?
34
+ */
35
+ protected $_canVoid = false;
36
+
37
+ /**
38
+ * Can use this payment method in administration panel?
39
+ */
40
+ protected $_canUseInternal = true;
41
+
42
+ /**
43
+ * Can show this payment method as an option on checkout payment page?
44
+ */
45
+ protected $_canUseCheckout = true;
46
+
47
+ /**
48
+ * Is this payment method suitable for multi-shipping checkout?
49
+ */
50
+ protected $_canUseForMultishipping = true;
51
+
52
+ /**
53
+ * Can save credit card information for future processing?
54
+ */
55
+ protected $_canSaveCc = false;
56
+
57
+
58
+ public function authorize(Varien_Object $payment, $amount)
59
+ {
60
+
61
+ require_once(Mage::getModuleDir('coinsimple_php', 'Coinsimple_Coinsimple') . "/coinsimple_php/src/coinsimple.php");
62
+
63
+ $apiKey = Mage::getStoreConfig('payment/Coinsimple/api_key');
64
+ $businessId = Mage::getStoreConfig('payment/Coinsimple/business_id');
65
+
66
+ if($apiKey == null || $businessId == null) {
67
+ throw new Exception("Before using the CoinSimple plugin, you need to enter your business' API Key and Business ID in Magento Admin > Configuration > System > Payment Methods > CoinSimple.");
68
+ }
69
+
70
+ $business = new \CoinSimple\Business($businessId, $apiKey);
71
+
72
+ $order = $payment->getOrder();
73
+ $currency = strtolower($order->getBaseCurrencyCode());
74
+
75
+ $successUrl = Mage::getStoreConfig('payment/Coinsimple/custom_success_url');
76
+
77
+ if ($successUrl == false) {
78
+ $successUrl = Mage::getUrl('coinsimple_coinsimple'). 'redirect/success/';
79
+ }
80
+
81
+ $name = $order->getCustomerFirstname() . ' ' . $order->getCustomerLastname();
82
+ $custom = $order->getId();
83
+
84
+ $address = $order->getBillingAddress();
85
+ $email = $address->getEmail();
86
+
87
+ $params = array(
88
+ 'callback_url' => Mage::getUrl('coinsimple_coinsimple'). 'callback/callback/',
89
+ 'redirect_url' => $successUrl,
90
+ 'name' => $name,
91
+ 'custom' => $custom,
92
+ 'email' => $email,
93
+ 'currency' => strtolower(Mage::app()->getStore()->getCurrentCurrencyCode()),
94
+ 'items' => array(
95
+ array('price' => $amount, 'quantity' => 1, 'description' => "Order #" . $order->getIncrementId())
96
+ )
97
+ );
98
+
99
+ $invoice = new \CoinSimple\Invoice($params);
100
+ $res = $business->sendInvoice($invoice);
101
+
102
+ if ($res->status == "error") {
103
+ throw new Exception("Could not generate new invoice. Double check your API Key and Secret. " . $res->error());
104
+ } else {
105
+ $redirectUrl = $res->url;
106
+
107
+ $payment->setIsTransactionPending(true);
108
+ Mage::getSingleton('customer/session')->setRedirectUrl($redirectUrl);
109
+ }
110
+
111
+ return $this;
112
+ }
113
+
114
+
115
+ public function getOrderPlaceRedirectUrl()
116
+ {
117
+ return Mage::getSingleton('customer/session')->getRedirectUrl();
118
+ }
119
+ }
120
+ ?>
app/code/community/Coinsimple/Coinsimple/coinsimple_php/.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ /vendor
2
+ composer.lock
3
+ tests/_output/*
app/code/community/Coinsimple/Coinsimple/coinsimple_php/README.md ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PHP CoinSimple API
2
+
3
+ The CoinSimple API allows you to create invoices for your businesses programatically using the Business's ID and API key.
4
+
5
+ ## Installation
6
+
7
+ #### Composer
8
+
9
+ You can add this repo to your project via composer, to both download and include the neccessary classes into your project. To do this simply add `coinsimple/coinsimple` to your `composer.json` like in the following:
10
+
11
+ ```json
12
+ {
13
+ "require": {
14
+ "coinsimple/coinsimple": "0.0.1"
15
+ }
16
+ }
17
+ ```
18
+
19
+ #### Manual Install
20
+
21
+ Alternatively you can download the repo manually and `require` the `coinsimple.php` file into your project.
22
+
23
+ ## Usage
24
+
25
+ To create a new invoice you need to objects, a `business` and an `invoice`. A business contains the `Business ID` and the `API Key` and handles authorization:
26
+
27
+ ```php
28
+ $business = new \CoinSimple\Business(BUSINESS_ID, API_KEY);
29
+ ```
30
+
31
+ You can then use this instance to send invoices. An invoice can have the following fields:
32
+
33
+ ```php
34
+ $data = array(
35
+ "name" => "",
36
+ "email" => "",
37
+ "items" => array(
38
+ array("description" => "", "price" => 0.0, "quantity" => 0)
39
+ ),
40
+ "processor" => "",
41
+ "rate" => "",
42
+ "currency" => "",
43
+ "notes" => "",
44
+ "percent" => 0.0,
45
+ "custom" => array(),
46
+ "callback_url" => "",
47
+ "redirect_url" => "",
48
+ "invoice_type" => "",
49
+ "interval" => 0,
50
+ "recurring_times" => 0
51
+ );
52
+
53
+ $invoice = new \CoinsSimple\Invoice($data);
54
+ ```
55
+
56
+ But the only fields that are really required are `name`, `email`, `items`, `processor`, `rate` and `currency`. If you set defaults for `processor`, `rate` and `currency` in the business settings on CoinSimple, then they can be left out as well.
57
+
58
+ This library also contains the following functions if you preffer to setup the invoice incrementally:
59
+
60
+ - `->setName($name)`
61
+ - `->setEmail($email)`
62
+ - `->addItem($item)`
63
+ - `->setProcessor($processor)`
64
+ - `->setRate($rate)`
65
+ - `->setCurrency($currency)`
66
+ - `->setNotes($notes)`
67
+ - `->setPercent($percent)` (alias: `->setDiscount($percent)`)
68
+ - `->setCustom($data)`
69
+ - `->setCallbackUrl($url)`
70
+ - `->setRedirectUrl($url)`
71
+ - `->setRecurringTimes($times)` (alias: `->stopAfter($times)`)
72
+ - `->recurByDays($num_days)`
73
+ - `->recurByDate($day_of_month)`
74
+
75
+ These methods are all chainable and you can mix both options of using functions and setting intial parameters in the constructor. For example you can create an invoice like so:
76
+
77
+ ```php
78
+ $user_info = array(
79
+ "name" => "Coin Simple",
80
+ "email" => "hi@coinsimple.com"
81
+ );
82
+
83
+ $invoice = new \CoinSimple\Invoice($user_info);
84
+
85
+ $invoice.addItem(array(
86
+ "description" => "Nice Shirt",
87
+ "price" => 15.8,
88
+ "quantity" => 2,
89
+ ))->setCurrency("usd")->recurByDays(4)->stopAfter(2);
90
+ ```
91
+
92
+ This code will create an invoice with one item which will recur 2 times once every four days.
93
+
94
+ To then send the invoice using a business you created you can use the `sendInvoice` method:
95
+
96
+ ```php
97
+ $business->sendInvoice($invoice);
98
+ ```
app/code/community/Coinsimple/Coinsimple/coinsimple_php/codeception.yml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ actor: Tester
2
+ paths:
3
+ tests: tests
4
+ log: tests/_output
5
+ data: tests/_data
6
+ helpers: tests/_support
7
+ settings:
8
+ bootstrap: _bootstrap.php
9
+ colors: true
10
+ memory_limit: 1024M
app/code/community/Coinsimple/Coinsimple/coinsimple_php/composer.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "coinsimple/coinsimple",
3
+ "description": "CoinSimple API wrapper",
4
+ "keywords": ["bitcoin", "coinsimple"],
5
+ "homepage": "https://coinsimple.com",
6
+ "type": "library",
7
+ "license": "MIT",
8
+ "autoload": {
9
+ "files": [
10
+ "src/coinsimple.php"
11
+ ]
12
+ },
13
+ "require-dev": {
14
+ "codeception/codeception": "*",
15
+ "codeception/specify": "*",
16
+ "codeception/verify": "*"
17
+ }
18
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/src/business.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace CoinSimple;
4
+
5
+ class Business
6
+ {
7
+ const NEW_INVOICE_URL = "https://app.coinsimple.com/api/v1/invoice";
8
+
9
+ protected $businessId;
10
+ protected $apiKey;
11
+
12
+ public function __construct($bId, $apiKey)
13
+ {
14
+ $this->businessId = $bId;
15
+ $this->apiKey = $apiKey;
16
+ }
17
+
18
+ public function sendInvoice($invoice)
19
+ {
20
+ $timestamp = time();
21
+
22
+ $options = $invoice->data();
23
+ $options['timestamp'] = $timestamp;
24
+ $options['hash'] = hash_hmac("sha256", $this->apiKey, $timestamp);
25
+ $options['business_id'] = $this->businessId;
26
+
27
+ return $this->httpSendInvoice($options);
28
+ }
29
+
30
+ public function validateHash($hash, $timestamp)
31
+ {
32
+ return $hash == hash_hmac("sha256", $this->apiKey, $timestamp);
33
+ }
34
+
35
+ protected function httpSendInvoice($options)
36
+ {
37
+ $curl = curl_init(self::NEW_INVOICE_URL);
38
+ $data = json_encode($options);
39
+
40
+ $headers = array(
41
+ 'Content-Type: application/json',
42
+ 'Content-Length: ' . strlen($data)
43
+ );
44
+
45
+ curl_setopt($curl, CURLOPT_PORT, 443);
46
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
47
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
48
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
49
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
50
+ curl_setopt($curl, CURLOPT_POST, 1);
51
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
52
+
53
+ $response = curl_exec($curl);
54
+
55
+ if ($response == false || curl_getinfo($curl, CURLINFO_HTTP_CODE) >= 400) {
56
+ return array("status" => "error", "error" => "Error creating Invoice");
57
+ }
58
+
59
+ return json_decode($response);
60
+ }
61
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/src/coinsimple.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+
3
+ require_once(dirname(__FILE__) . '/invoice.php');
4
+ require_once(dirname(__FILE__) . '/business.php');
app/code/community/Coinsimple/Coinsimple/coinsimple_php/src/invoice.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace CoinSimple;
4
+
5
+ class Invoice
6
+ {
7
+ protected $options;
8
+
9
+ public function __construct($opts = array())
10
+ {
11
+ if (!is_array($opts)) {
12
+ throw new \InvalidArgumentException('Invoice expects a hash');
13
+ }
14
+
15
+ $this->options = array();
16
+ $this->processInputHash($opts);
17
+ }
18
+
19
+ protected function processInputHash($opts)
20
+ {
21
+ foreach ($opts as $key => $val) {
22
+ $command = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
23
+ if (method_exists($this, $command)) {
24
+ call_user_func(array($this, $command), $val);
25
+ }
26
+ }
27
+
28
+ if (array_key_exists('interval', $opts) && array_key_exists('invoice_type', $opts)) {
29
+ $command = 'recurBy' . ucfirst(strtolower($opts['invoice_type']));
30
+ if (method_exists($this, $command)) {
31
+ call_user_func(array($this, $command), $opts['interval']);
32
+ }
33
+ }
34
+
35
+ if (array_key_exists('items', $opts) && is_array($opts['items'])) {
36
+ foreach ($opts['items'] as $item) {
37
+ $this->addItem($item);
38
+ }
39
+ }
40
+ }
41
+
42
+ public function setName($name)
43
+ {
44
+ $this->options['name'] = strval($name);
45
+ return $this;
46
+ }
47
+
48
+ public function setEmail($email)
49
+ {
50
+ $pattern = '/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/';
51
+ if (preg_match($pattern, $email) != 1) {
52
+ throw new \InvalidArgumentException('Invoice expects a valid email');
53
+ }
54
+ $this->options['email'] = strval($email);
55
+ return $this;
56
+ }
57
+
58
+ public function addItem($item)
59
+ {
60
+ if (!is_array($item)) {
61
+ throw new \InvalidArgumentException('An Invoice item must be a Hash');
62
+ }
63
+
64
+ if (!array_key_exists('price', $item)
65
+ || !array_key_exists('description', $item)
66
+ || !array_key_exists('quantity', $item)) {
67
+ throw new \InvalidArgumentException('An Invoice item must contain a price, description and quantity');
68
+ }
69
+
70
+ if (!array_key_exists('items', $this->options)) {
71
+ $this->options['items'] = array();
72
+ }
73
+
74
+ array_push($this->options['items'], $item);
75
+ return $this;
76
+ }
77
+
78
+ public function setProcessor($processor)
79
+ {
80
+ $this->options['processor'] = strtolower(strval($processor));
81
+ return $this;
82
+ }
83
+
84
+ public function setRate($rate)
85
+ {
86
+ $this->options['rate'] = strtolower(strval($rate));
87
+ return $this;
88
+ }
89
+
90
+ public function setCurrency($currency)
91
+ {
92
+ $this->options['currency'] = strtolower(strval($currency));
93
+ return $this;
94
+ }
95
+
96
+ public function setNotes($notes)
97
+ {
98
+ $this->options['notes'] = strval($notes);
99
+ return $this;
100
+ }
101
+
102
+ public function setPercent($percent)
103
+ {
104
+ $this->options['percent'] = floatval($percent);
105
+ return $this;
106
+ }
107
+
108
+ public function setDiscount($percent)
109
+ {
110
+ return $this->setPercent($percent);
111
+ }
112
+
113
+ public function setCustom($data)
114
+ {
115
+ if (!is_array($data)) {
116
+ $data = strval($data);
117
+ }
118
+
119
+ $this->options['custom'] = $data;
120
+ return $this;
121
+ }
122
+
123
+ public function setCallbackUrl($url)
124
+ {
125
+ $this->options['callback_url'] = strval($url);
126
+ return $this;
127
+ }
128
+
129
+ public function setRedirectUrl($url)
130
+ {
131
+ $this->options['redirect_url'] = strval($url);
132
+ return $this;
133
+ }
134
+
135
+ public function setRecurringTimes($times)
136
+ {
137
+ $this->options['recurring_times'] = intval($times);
138
+ return $this;
139
+ }
140
+
141
+ public function stopAfter($times)
142
+ {
143
+ return $this->setRecurringTimes($times);
144
+ }
145
+
146
+ public function recurByDays($numDays)
147
+ {
148
+ $this->options['invoice_type'] = 'days';
149
+ $this->options['interval'] = intval($numDays);
150
+ return $this;
151
+ }
152
+
153
+ public function recurByDate($dayOfMonth)
154
+ {
155
+ $this->options['invoice_type'] = 'date';
156
+ $this->options['interval'] = intval($dayOfMonth);
157
+ return $this;
158
+ }
159
+
160
+ public function data()
161
+ {
162
+ return $this->options;
163
+ }
164
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/_bootstrap.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // This is global bootstrap for autoloading
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/_support/UnitHelper.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Codeception\Module;
3
+
4
+ // here you can define custom actions
5
+ // all public methods declared in helper class will be available in $I
6
+
7
+ class UnitHelper extends \Codeception\Module
8
+ {
9
+
10
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit.suite.yml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # Codeception Test Suite Configuration
2
+
3
+ # suite for unit (internal) tests.
4
+ class_name: UnitTester
5
+ modules:
6
+ enabled: [Asserts, UnitHelper]
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/BusinessTest.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ class BusinessTest extends \Codeception\TestCase\Test
5
+ {
6
+ /**
7
+ * @var \UnitTester
8
+ */
9
+ protected $tester;
10
+
11
+ protected function _before()
12
+ {
13
+ }
14
+
15
+ protected function _after()
16
+ {
17
+ }
18
+
19
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/InvoiceTest.php ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ require "vendor/autoload.php";
3
+
4
+ class InvoiceTest extends \Codeception\TestCase\Test
5
+ {
6
+ use Codeception\Specify;
7
+
8
+ /**
9
+ * @var \UnitTester
10
+ */
11
+ protected $tester;
12
+
13
+ protected function _before()
14
+ {
15
+ }
16
+
17
+ protected function _after()
18
+ {
19
+ }
20
+
21
+ public function testConstructorParameter()
22
+ {
23
+ $this->specify('when passing a number', function() {
24
+ $i = new \CoinSimple\Invoice(5);
25
+ }, ['throws' => 'InvalidArgumentException']);
26
+
27
+ $this->specify('when passing a string', function() {
28
+ $i = new \CoinSimple\Invoice('str');
29
+ }, ['throws' => 'InvalidArgumentException']);
30
+
31
+ $this->specify('when passing an array', function() {
32
+ $i = new \CoinSimple\Invoice(array());
33
+ verify($i->data())->equals(array());
34
+ });
35
+
36
+ $this->specify('when passing nothing', function() {
37
+ $i = new \CoinSimple\Invoice(array());
38
+ verify($i->data())->equals(array());
39
+ });
40
+ }
41
+
42
+ public function testFullInvoice() {
43
+ $data = array(
44
+ "name" => "Gabriel",
45
+ "email" => "gmanricks@gmail.com",
46
+ "items" => array(
47
+ array("description" => "item", "price" => 3.0, "quantity" => 6)
48
+ ),
49
+ "processor" => "coinsimple",
50
+ "rate" => "coinsimple",
51
+ "currency" => "usd",
52
+ "notes" => "Note",
53
+ "percent" => 1.5,
54
+ "custom" => array("id" => 4),
55
+ "callback_url" => "http://coinsimple.com/callback",
56
+ "redirect_url" => "http://coinsimple.com/redirect",
57
+ "invoice_type" => "date",
58
+ "interval" => 5,
59
+ "recurring_times" => 2
60
+ );
61
+
62
+ $this->specify('from constructor', function() use($data) {
63
+ $i = new \CoinSimple\Invoice($data);
64
+ verify($i->data())->equals($data);
65
+ });
66
+
67
+ $this->specify('from methods', function() use($data) {
68
+ $i = new \CoinSimple\Invoice();
69
+ $i->setName("Gabriel")
70
+ ->setEmail("gmanricks@gmail.com")
71
+ ->addItem(array("description" => "item", "price" => 3.0, "quantity" => 6))
72
+ ->setProcessor("coinsimple")
73
+ ->setRate("coinsimple")
74
+ ->setCurrency("usd")
75
+ ->setNotes("Note")
76
+ ->setPercent(1.5)
77
+ ->setCustom(array("id" => 4))
78
+ ->setCallbackUrl("http://coinsimple.com/callback")
79
+ ->setRedirectUrl("http://coinsimple.com/redirect")
80
+ ->recurBydate(5)
81
+ ->stopAfter(2);
82
+ verify($i->data())->equals($data);
83
+ });
84
+ }
85
+
86
+ public function testSetName() {
87
+ $this->specify('sets name as a string', function() {
88
+ $i = new \CoinSimple\Invoice();
89
+ verify($i->data())->equals(array());
90
+
91
+ $i->setName("Gabriel");
92
+ $data = $i->data();
93
+ verify(array_key_exists('name', $data))->true();
94
+ verify($data['name'])->equals("Gabriel");
95
+
96
+ $i->setName(5);
97
+ verify($i->data()['name'])->equals("5");
98
+ });
99
+ }
100
+
101
+ public function testSetEmail() {
102
+ $this->specify('checks for valid email address', function() {
103
+ $i = new \CoinSimple\Invoice();
104
+ verify($i->data())->equals(array());
105
+
106
+ $i->setEmail("gmanricks@gmail.com");
107
+ $data = $i->data();
108
+ verify(array_key_exists('email', $data))->true();
109
+ verify($data['email'])->equals("gmanricks@gmail.com");
110
+ });
111
+
112
+ $this->specify('when passing an invalid email', function() {
113
+ $i = new \CoinSimple\Invoice();
114
+ $i->setEmail("gmanricks.com");
115
+ }, ['throws' => 'InvalidArgumentException']);
116
+ }
117
+
118
+ public function testAddItem() {
119
+ $this->specify('when passing an invalid item', function() {
120
+ $i = new \CoinSimple\Invoice();
121
+ $i->addItem('invalid item');
122
+ }, ['throws' => 'InvalidArgumentException']);
123
+
124
+
125
+ $this->specify('when passing an incomplete item', function() {
126
+ $i = new \CoinSimple\Invoice();
127
+ $i->addItem(array('price' => 24, 'quantity' => 2));
128
+ }, ['throws' => 'InvalidArgumentException']);
129
+
130
+ $this->specify('when passing a valid item', function() {
131
+ $i = new \CoinSimple\Invoice();
132
+ verify($i->data())->equals(array());
133
+
134
+ $i->addItem(array('price' => 24, 'quantity' => 2, 'description' => 'item'));
135
+
136
+ $data = $i->data();
137
+ verify(array_key_exists('items', $data))->true();
138
+ verify($data['items'])->equals(array(
139
+ array('price' => 24, 'quantity' => 2, 'description' => 'item')
140
+ ));
141
+ });
142
+ }
143
+
144
+ public function testSetProcessor() {
145
+ $this->specify('sets the processor', function() {
146
+ $i = new \CoinSimple\Invoice();
147
+ verify($i->data())->equals(array());
148
+
149
+ $i->setProcessor('coinsimple');
150
+ $data = $i->data();
151
+ verify(array_key_exists('processor', $data))->true();
152
+ verify($data['processor'])->equals("coinsimple");
153
+ });
154
+
155
+ $this->specify('converts the processor to lowercase', function() {
156
+ $i = new \CoinSimple\Invoice();
157
+ verify($i->data())->equals(array());
158
+
159
+ $i->setProcessor('CoinSimple');
160
+ $data = $i->data();
161
+ verify(array_key_exists('processor', $data))->true();
162
+ verify($data['processor'])->equals("coinsimple");
163
+ });
164
+ }
165
+
166
+ public function testSetRate() {
167
+ $this->specify('sets the rate', function() {
168
+ $i = new \CoinSimple\Invoice();
169
+ verify($i->data())->equals(array());
170
+
171
+ $i->setRate('coinsimple');
172
+ $data = $i->data();
173
+ verify(array_key_exists('rate', $data))->true();
174
+ verify($data['rate'])->equals("coinsimple");
175
+ });
176
+
177
+ $this->specify('converts the rate to lowercase', function() {
178
+ $i = new \CoinSimple\Invoice();
179
+ verify($i->data())->equals(array());
180
+
181
+ $i->setRate('CoinSimple');
182
+ $data = $i->data();
183
+ verify(array_key_exists('rate', $data))->true();
184
+ verify($data['rate'])->equals("coinsimple");
185
+ });
186
+ }
187
+
188
+ public function testSetCurrency() {
189
+ $this->specify('sets the currency', function() {
190
+ $i = new \CoinSimple\Invoice();
191
+ verify($i->data())->equals(array());
192
+
193
+ $i->setCurrency('coinsimple');
194
+ $data = $i->data();
195
+ verify(array_key_exists('currency', $data))->true();
196
+ verify($data['currency'])->equals("coinsimple");
197
+ });
198
+
199
+ $this->specify('converts the currency to lowercase', function() {
200
+ $i = new \CoinSimple\Invoice();
201
+ verify($i->data())->equals(array());
202
+
203
+ $i->setCurrency('CoinSimple');
204
+ $data = $i->data();
205
+ verify(array_key_exists('currency', $data))->true();
206
+ verify($data['currency'])->equals("coinsimple");
207
+ });
208
+ }
209
+
210
+ public function testSetNotes() {
211
+ $this->specify('sets the notes fields', function() {
212
+ $i = new \CoinSimple\Invoice();
213
+ verify($i->data())->equals(array());
214
+
215
+ $i->setNotes('CoinSimple Memo');
216
+ $data = $i->data();
217
+ verify(array_key_exists('notes', $data))->true();
218
+ verify($data['notes'])->equals("CoinSimple Memo");
219
+ });
220
+ }
221
+
222
+ public function testSetPercent() {
223
+ $this->specify('sets the percent field', function() {
224
+ $i = new \CoinSimple\Invoice();
225
+ verify($i->data())->equals(array());
226
+
227
+ $i->setPercent(4.5);
228
+ $data = $i->data();
229
+ verify(array_key_exists('percent', $data))->true();
230
+ verify($data['percent'])->equals(4.5);
231
+ });
232
+
233
+ $this->specify('converts strings to float', function() {
234
+ $i = new \CoinSimple\Invoice();
235
+ verify($i->data())->equals(array());
236
+
237
+ $i->setPercent("4.5");
238
+ $data = $i->data();
239
+ verify(array_key_exists('percent', $data))->true();
240
+ verify($data['percent'])->equals(4.5);
241
+ });
242
+ }
243
+
244
+ public function testSetDiscount() {
245
+ $this->specify('sets the percent field', function() {
246
+ $i = new \CoinSimple\Invoice();
247
+ verify($i->data())->equals(array());
248
+
249
+ $i->setDiscount(4.5);
250
+ $data = $i->data();
251
+ verify(array_key_exists('percent', $data))->true();
252
+ verify($data['percent'])->equals(4.5);
253
+ });
254
+
255
+ $this->specify('converts strings to float', function() {
256
+ $i = new \CoinSimple\Invoice();
257
+ verify($i->data())->equals(array());
258
+
259
+ $i->setDiscount("4.5");
260
+ $data = $i->data();
261
+ verify(array_key_exists('percent', $data))->true();
262
+ verify($data['percent'])->equals(4.5);
263
+ });
264
+ }
265
+
266
+ public function testSetCustom() {
267
+ $this->specify('sets the custom field', function() {
268
+ $i = new \CoinSimple\Invoice();
269
+ verify($i->data())->equals(array());
270
+
271
+ $i->setCustom("custom data");
272
+ $data = $i->data();
273
+ verify(array_key_exists('custom', $data))->true();
274
+ verify($data['custom'])->equals("custom data");
275
+ });
276
+
277
+ $this->specify('converts non arrays to strings', function() {
278
+ $i = new \CoinSimple\Invoice();
279
+ verify($i->data())->equals(array());
280
+
281
+ $i->setCustom(34);
282
+ $data = $i->data();
283
+ verify(array_key_exists('custom', $data))->true();
284
+ verify($data['custom'])->equals("34");
285
+ });
286
+
287
+ $this->specify('does not convert arrays or hashes', function() {
288
+ $i = new \CoinSimple\Invoice();
289
+ verify($i->data())->equals(array());
290
+
291
+ $i->setCustom(array(3, 5, 6));
292
+ $data = $i->data();
293
+ verify(array_key_exists('custom', $data))->true();
294
+ verify($data['custom'])->equals(array(3, 5, 6));
295
+
296
+ $i->setCustom(array("id" => 23));
297
+ $data = $i->data();
298
+ verify(array_key_exists('custom', $data))->true();
299
+ verify($data['custom'])->equals(array("id" => 23));
300
+ });
301
+ }
302
+
303
+ public function testSetCallbackUrl() {
304
+ $this->specify('sets the callback url fields', function() {
305
+ $i = new \CoinSimple\Invoice();
306
+ verify($i->data())->equals(array());
307
+
308
+ $i->setCallbackUrl('http://demo.com');
309
+ $data = $i->data();
310
+ verify(array_key_exists('callback_url', $data))->true();
311
+ verify($data['callback_url'])->equals("http://demo.com");
312
+ });
313
+
314
+ $this->specify('converts callback url to string', function() {
315
+ $i = new \CoinSimple\Invoice();
316
+ verify($i->data())->equals(array());
317
+
318
+ $i->setCallbackUrl(5);
319
+ $data = $i->data();
320
+ verify(array_key_exists('callback_url', $data))->true();
321
+ verify($data['callback_url'])->equals("5");
322
+ });
323
+ }
324
+
325
+ public function testSetRedirectUrl() {
326
+ $this->specify('sets the redirect url fields', function() {
327
+ $i = new \CoinSimple\Invoice();
328
+ verify($i->data())->equals(array());
329
+
330
+ $i->setRedirectUrl('http://demo.com');
331
+ $data = $i->data();
332
+ verify(array_key_exists('redirect_url', $data))->true();
333
+ verify($data['redirect_url'])->equals("http://demo.com");
334
+ });
335
+
336
+ $this->specify('converts redirect url to string', function() {
337
+ $i = new \CoinSimple\Invoice();
338
+ verify($i->data())->equals(array());
339
+
340
+ $i->setRedirectUrl(5);
341
+ $data = $i->data();
342
+ verify(array_key_exists('redirect_url', $data))->true();
343
+ verify($data['redirect_url'])->equals("5");
344
+ });
345
+ }
346
+
347
+ public function testSetRecurringTimes() {
348
+ $this->specify('sets the percent field', function() {
349
+ $i = new \CoinSimple\Invoice();
350
+ verify($i->data())->equals(array());
351
+
352
+ $i->setRecurringTimes(4);
353
+ $data = $i->data();
354
+ verify(array_key_exists('recurring_times', $data))->true();
355
+ verify($data['recurring_times'])->equals(4);
356
+ });
357
+
358
+ $this->specify('converts param to int', function() {
359
+ $i = new \CoinSimple\Invoice();
360
+ verify($i->data())->equals(array());
361
+
362
+ $i->setRecurringTimes("4");
363
+ $data = $i->data();
364
+ verify(array_key_exists('recurring_times', $data))->true();
365
+ verify($data['recurring_times'])->equals(4);
366
+ });
367
+ }
368
+
369
+ public function testRecurByDays() {
370
+ $this->specify('sets the recurring fields', function() {
371
+ $i = new \CoinSimple\Invoice();
372
+ verify($i->data())->equals(array());
373
+
374
+ $i->recurByDays(4);
375
+ $data = $i->data();
376
+ verify(array_key_exists('invoice_type', $data))->true();
377
+ verify(array_key_exists('interval', $data))->true();
378
+ verify($data['invoice_type'])->equals("days");
379
+ verify($data['interval'])->equals(4);
380
+ });
381
+
382
+ $this->specify('converts param to int', function() {
383
+ $i = new \CoinSimple\Invoice();
384
+ verify($i->data())->equals(array());
385
+
386
+ $i->recurByDays("4");
387
+ $data = $i->data();
388
+ verify(array_key_exists('invoice_type', $data))->true();
389
+ verify(array_key_exists('interval', $data))->true();
390
+ verify($data['invoice_type'])->equals("days");
391
+ verify($data['interval'])->equals(4);
392
+ });
393
+ }
394
+
395
+ public function testRecurByDate() {
396
+ $this->specify('sets the recurring fields', function() {
397
+ $i = new \CoinSimple\Invoice();
398
+ verify($i->data())->equals(array());
399
+
400
+ $i->recurByDate(4);
401
+ $data = $i->data();
402
+ verify(array_key_exists('invoice_type', $data))->true();
403
+ verify(array_key_exists('interval', $data))->true();
404
+ verify($data['invoice_type'])->equals("date");
405
+ verify($data['interval'])->equals(4);
406
+ });
407
+
408
+ $this->specify('converts param to int', function() {
409
+ $i = new \CoinSimple\Invoice();
410
+ verify($i->data())->equals(array());
411
+
412
+ $i->recurByDate("4");
413
+ $data = $i->data();
414
+ verify(array_key_exists('invoice_type', $data))->true();
415
+ verify(array_key_exists('interval', $data))->true();
416
+ verify($data['invoice_type'])->equals("date");
417
+ verify($data['interval'])->equals(4);
418
+ });
419
+ }
420
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/UnitTester.php ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php //[STAMP] 157d433c4bd60bd3957188fc88c5d0f8
2
+
3
+ // This class was automatically generated by build task
4
+ // You should not change it manually as it will be overwritten on next build
5
+ // @codingStandardsIgnoreFile
6
+
7
+
8
+ use Codeception\Module\Asserts;
9
+ use Codeception\Module\UnitHelper;
10
+
11
+ /**
12
+ * Inherited Methods
13
+ * @method void wantToTest($text)
14
+ * @method void wantTo($text)
15
+ * @method void execute($callable)
16
+ * @method void expectTo($prediction)
17
+ * @method void expect($prediction)
18
+ * @method void amGoingTo($argumentation)
19
+ * @method void am($role)
20
+ * @method void lookForwardTo($achieveValue)
21
+ * @method void comment($description)
22
+ * @method void haveFriend($name, $actorClass = null)
23
+ *
24
+ * @SuppressWarnings(PHPMD)
25
+ */
26
+ class UnitTester extends \Codeception\Actor
27
+ {
28
+
29
+ /**
30
+ * [!] Method is generated. Documentation taken from corresponding module.
31
+ *
32
+ * Checks that two variables are equal.
33
+ *
34
+ * @param $expected
35
+ * @param $actual
36
+ * @param string $message
37
+ *
38
+ * @return mixed
39
+ * @see \Codeception\Module\Asserts::assertEquals()
40
+ */
41
+ public function assertEquals($expected, $actual, $message = null) {
42
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertEquals', func_get_args()));
43
+ }
44
+
45
+
46
+ /**
47
+ * [!] Method is generated. Documentation taken from corresponding module.
48
+ *
49
+ * Checks that two variables are not equal
50
+ *
51
+ * @param $expected
52
+ * @param $actual
53
+ * @param string $message
54
+ * @see \Codeception\Module\Asserts::assertNotEquals()
55
+ */
56
+ public function assertNotEquals($expected, $actual, $message = null) {
57
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertNotEquals', func_get_args()));
58
+ }
59
+
60
+
61
+ /**
62
+ * [!] Method is generated. Documentation taken from corresponding module.
63
+ *
64
+ * Checks that expected is greater than actual
65
+ *
66
+ * @param $expected
67
+ * @param $actual
68
+ * @param string $message
69
+ * @see \Codeception\Module\Asserts::assertGreaterThan()
70
+ */
71
+ public function assertGreaterThan($expected, $actual, $message = null) {
72
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThan', func_get_args()));
73
+ }
74
+
75
+
76
+ /**
77
+ * [!] Method is generated. Documentation taken from corresponding module.
78
+ *
79
+ * @deprecated
80
+ * @see \Codeception\Module\Asserts::assertGreaterThen()
81
+ */
82
+ public function assertGreaterThen($expected, $actual, $message = null) {
83
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThen', func_get_args()));
84
+ }
85
+
86
+
87
+ /**
88
+ * [!] Method is generated. Documentation taken from corresponding module.
89
+ *
90
+ * Checks that expected is greater or equal than actual
91
+ *
92
+ * @param $expected
93
+ * @param $actual
94
+ * @param string $message
95
+ * @see \Codeception\Module\Asserts::assertGreaterThanOrEqual()
96
+ */
97
+ public function assertGreaterThanOrEqual($expected, $actual, $message = null) {
98
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThanOrEqual', func_get_args()));
99
+ }
100
+
101
+
102
+ /**
103
+ * [!] Method is generated. Documentation taken from corresponding module.
104
+ *
105
+ * @deprecated
106
+ * @see \Codeception\Module\Asserts::assertGreaterThenOrEqual()
107
+ */
108
+ public function assertGreaterThenOrEqual($expected, $actual, $message = null) {
109
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertGreaterThenOrEqual', func_get_args()));
110
+ }
111
+
112
+
113
+ /**
114
+ * [!] Method is generated. Documentation taken from corresponding module.
115
+ *
116
+ * Checks that expected is less than actual
117
+ *
118
+ * @param $expected
119
+ * @param $actual
120
+ * @param string $message
121
+ * @see \Codeception\Module\Asserts::assertLessThan()
122
+ */
123
+ public function assertLessThan($expected, $actual, $message = null) {
124
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertLessThan', func_get_args()));
125
+ }
126
+
127
+
128
+ /**
129
+ * [!] Method is generated. Documentation taken from corresponding module.
130
+ *
131
+ * Checks that expected is less or equal than actual
132
+ *
133
+ * @param $expected
134
+ * @param $actual
135
+ * @param string $message
136
+ * @see \Codeception\Module\Asserts::assertLessThanOrEqual()
137
+ */
138
+ public function assertLessThanOrEqual($expected, $actual, $message = null) {
139
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertLessThanOrEqual', func_get_args()));
140
+ }
141
+
142
+
143
+ /**
144
+ * [!] Method is generated. Documentation taken from corresponding module.
145
+ *
146
+ * Checks that haystack contains needle
147
+ *
148
+ * @param $needle
149
+ * @param $haystack
150
+ * @param string $message
151
+ * @see \Codeception\Module\Asserts::assertContains()
152
+ */
153
+ public function assertContains($needle, $haystack, $message = null) {
154
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertContains', func_get_args()));
155
+ }
156
+
157
+
158
+ /**
159
+ * [!] Method is generated. Documentation taken from corresponding module.
160
+ *
161
+ * Checks that haystack doesn't contain needle.
162
+ *
163
+ * @param $needle
164
+ * @param $haystack
165
+ * @param string $message
166
+ * @see \Codeception\Module\Asserts::assertNotContains()
167
+ */
168
+ public function assertNotContains($needle, $haystack, $message = null) {
169
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertNotContains', func_get_args()));
170
+ }
171
+
172
+
173
+ /**
174
+ * [!] Method is generated. Documentation taken from corresponding module.
175
+ *
176
+ * Checks that variable is empty.
177
+ *
178
+ * @param $actual
179
+ * @param string $message
180
+ * @see \Codeception\Module\Asserts::assertEmpty()
181
+ */
182
+ public function assertEmpty($actual, $message = null) {
183
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertEmpty', func_get_args()));
184
+ }
185
+
186
+
187
+ /**
188
+ * [!] Method is generated. Documentation taken from corresponding module.
189
+ *
190
+ * Checks that variable is not empty.
191
+ *
192
+ * @param $actual
193
+ * @param string $message
194
+ * @see \Codeception\Module\Asserts::assertNotEmpty()
195
+ */
196
+ public function assertNotEmpty($actual, $message = null) {
197
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertNotEmpty', func_get_args()));
198
+ }
199
+
200
+
201
+ /**
202
+ * [!] Method is generated. Documentation taken from corresponding module.
203
+ *
204
+ * Checks that variable is NULL
205
+ *
206
+ * @param $actual
207
+ * @param string $message
208
+ * @see \Codeception\Module\Asserts::assertNull()
209
+ */
210
+ public function assertNull($actual, $message = null) {
211
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertNull', func_get_args()));
212
+ }
213
+
214
+
215
+ /**
216
+ * [!] Method is generated. Documentation taken from corresponding module.
217
+ *
218
+ * Checks that variable is not NULL
219
+ *
220
+ * @param $actual
221
+ * @param string $message
222
+ * @see \Codeception\Module\Asserts::assertNotNull()
223
+ */
224
+ public function assertNotNull($actual, $message = null) {
225
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertNotNull', func_get_args()));
226
+ }
227
+
228
+
229
+ /**
230
+ * [!] Method is generated. Documentation taken from corresponding module.
231
+ *
232
+ * Checks that condition is positive.
233
+ *
234
+ * @param $condition
235
+ * @param string $message
236
+ * @see \Codeception\Module\Asserts::assertTrue()
237
+ */
238
+ public function assertTrue($condition, $message = null) {
239
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertTrue', func_get_args()));
240
+ }
241
+
242
+
243
+ /**
244
+ * [!] Method is generated. Documentation taken from corresponding module.
245
+ *
246
+ * Checks that condition is negative.
247
+ *
248
+ * @param $condition
249
+ * @param string $message
250
+ * @see \Codeception\Module\Asserts::assertFalse()
251
+ */
252
+ public function assertFalse($condition, $message = null) {
253
+ return $this->scenario->runStep(new \Codeception\Step\Action('assertFalse', func_get_args()));
254
+ }
255
+
256
+
257
+ /**
258
+ * [!] Method is generated. Documentation taken from corresponding module.
259
+ *
260
+ * Fails the test with message.
261
+ *
262
+ * @param $message
263
+ * @see \Codeception\Module\Asserts::fail()
264
+ */
265
+ public function fail($message) {
266
+ return $this->scenario->runStep(new \Codeception\Step\Action('fail', func_get_args()));
267
+ }
268
+ }
app/code/community/Coinsimple/Coinsimple/coinsimple_php/tests/unit/_bootstrap.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Here you can initialize variables that will be available to your tests
app/code/community/Coinsimple/Coinsimple/controllers/CallbackController.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Coinsimple_Coinsimple_CallbackController extends Mage_Core_Controller_Front_Action
4
+ {
5
+
6
+ public function callbackAction() {
7
+
8
+ require_once(Mage::getModuleDir('coinsimple_php', 'Coinsimple_Coinsimple') . "/coinsimple_php/src/coinsimple.php");
9
+
10
+ $data = json_decode(file_get_contents('php://input'));
11
+
12
+ $apiKey = Mage::getStoreConfig('payment/Coinsimple/api_key');
13
+ $businessId = Mage::getStoreConfig('payment/Coinsimple/business_id');
14
+
15
+ if($apiKey == null || $businessId == null) {
16
+ throw new Exception("Before using the CoinSimple plugin, you need to enter your business' API Key and Business ID in Magento Admin > Configuration > System > Payment Methods > CoinSimple.");
17
+ }
18
+
19
+ $business = new \CoinSimple\Business($businessId, $apiKey);
20
+
21
+ if (!$business->validateHash($data->hash, $data->timestamp)) {
22
+ Mage::log("Coinsimple: incorrect callback with incorrect hash.");
23
+ header("HTTP/1.1 500 Internal Server Error");
24
+ return;
25
+ }
26
+
27
+ $orderId = intval($data->custom);
28
+ $order = Mage::getModel('sales/order')->load($orderId);
29
+
30
+ if(!$order) {
31
+ Mage::log("Coinsimple: incorrect callback with incorrect order ID $orderId.");
32
+ header("HTTP/1.1 500 Internal Server Error");
33
+ return;
34
+ }
35
+
36
+
37
+ $payment = $order->getPayment();
38
+ Mage::log($payment);
39
+ $payment->setPreparedMessage("Paid with CoinSimple.")
40
+ ->setShouldCloseParentTransaction(true)
41
+ ->setIsTransactionClosed(0);
42
+
43
+ $payment->registerCaptureNotification($data->total);
44
+
45
+ Mage::dispatchEvent('coinsimple_callback_received', array('status' => "paid", 'order_id' => $orderId));
46
+ $order->save();
47
+ }
48
+
49
+ }
app/code/community/Coinsimple/Coinsimple/controllers/RedirectController.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Coinsimple_Coinsimple_RedirectController extends Mage_Core_Controller_Front_Action
4
+ {
5
+ public function successAction() {
6
+ $this->_redirect('checkout/onepage/success', array('_secure'=>true));
7
+ }
8
+
9
+ }
app/code/community/Coinsimple/Coinsimple/etc/config.xml ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Coinsimple_Coinsimple>
5
+ <version>1.0</version>
6
+ </Coinsimple_Coinsimple>
7
+ </modules>
8
+ <frontend>
9
+ <routers>
10
+ <coinsimple_coinsimple>
11
+ <use>standard</use>
12
+ <args>
13
+ <module>Coinsimple_Coinsimple</module>
14
+ <frontName>coinsimple_coinsimple</frontName>
15
+ </args>
16
+ </coinsimple_coinsimple>
17
+ </routers>
18
+ </frontend>
19
+ <global>
20
+ <blocks>
21
+ <Coinsimple>
22
+ <class>Coinsimple_Coinsimple_Block</class>
23
+ </Coinsimple>
24
+ </blocks>
25
+
26
+ <models>
27
+ <Coinsimple>
28
+ <class>Coinsimple_Coinsimple_Model</class>
29
+ </Coinsimple>
30
+ </models>
31
+
32
+ <resources>
33
+ <Coinsimple_setup>
34
+ <setup>
35
+ <module>Coinsimple_Coinsimple</module>
36
+ </setup>
37
+ <connection>
38
+ <use>core_setup</use>
39
+ </connection>
40
+ </Coinsimple_setup>
41
+ <Coinsimple_write>
42
+ <connection>
43
+ <use>core_write</use>
44
+ </connection>
45
+ </Coinsimple_write>
46
+ <Coinsimple_read>
47
+ <connection>
48
+ <use>core_read</use>
49
+ </connection>
50
+ </Coinsimple_read>
51
+ </resources>
52
+ </global>
53
+
54
+ <default>
55
+ <payment>
56
+ <Coinsimple>
57
+ <active>1</active>
58
+ <model>Coinsimple/paymentMethod</model>
59
+ <title>Bitcoin</title>
60
+
61
+ <payment_action>authorize</payment_action>
62
+ </Coinsimple>
63
+ </payment>
64
+ </default>
65
+ </config>
app/code/community/Coinsimple/Coinsimple/etc/system.xml ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <sections>
4
+ <payment>
5
+ <groups>
6
+ <Coinsimple translate="label" module="paygate">
7
+ <label>CoinSimple</label>
8
+ <sort_order>700</sort_order>
9
+ <show_in_default>1</show_in_default>
10
+ <show_in_website>1</show_in_website>
11
+ <show_in_store>0</show_in_store>
12
+ <comment><![CDATA[<b>Setup Instructions:</b><br><ol><li>Go to <a href="https://app.coinsimple.com">https://app.coinsimple.com</a> and open a business' settings page to get its API Key and Business ID for this plugin.</li><li>Copy and paste the API Key and Business ID into the boxes below, and save the plugin settings.</li></ol>]]></comment>
13
+ <fields>
14
+ <active translate="label">
15
+ <label>Enabled</label>
16
+ <frontend_type>select</frontend_type>
17
+ <source_model>adminhtml/system_config_source_yesno</source_model>
18
+ <sort_order>0</sort_order>
19
+ <show_in_default>1</show_in_default>
20
+ <show_in_website>1</show_in_website>
21
+ <show_in_store>0</show_in_store>
22
+ </active>
23
+
24
+ <title translate="label">
25
+ <label>Title</label>
26
+ <frontend_type>text</frontend_type>
27
+ <sort_order>1</sort_order>
28
+ <show_in_default>1</show_in_default>
29
+ <show_in_website>1</show_in_website>
30
+ <show_in_store>0</show_in_store>
31
+ </title>
32
+
33
+ <api_key translate="label">
34
+ <label>API Key</label>
35
+ <frontend_type>text</frontend_type>
36
+ <sort_order>3</sort_order>
37
+ <show_in_default>1</show_in_default>
38
+ <show_in_website>1</show_in_website>
39
+ <show_in_store>0</show_in_store>
40
+ </api_key>
41
+
42
+ <business_id translate="label">
43
+ <label>Business ID</label>
44
+ <frontend_type>text</frontend_type>
45
+ <sort_order>4</sort_order>
46
+ <show_in_default>1</show_in_default>
47
+ <show_in_website>1</show_in_website>
48
+ <show_in_store>0</show_in_store>
49
+ </business_id>
50
+
51
+ <sort_order translate="label">
52
+ <label>Sort Order</label>
53
+ <frontend_type>text</frontend_type>
54
+ <sort_order>5</sort_order>
55
+ <show_in_default>1</show_in_default>
56
+ <show_in_website>1</show_in_website>
57
+ <show_in_store>0</show_in_store>
58
+ <comment>Customize the order of the CoinSimple plugin relative to other payment plugins.</comment>
59
+ </sort_order>
60
+
61
+ <custom_success_url translate="label">
62
+ <label>Custom Redirect URL</label>
63
+ <frontend_type>text</frontend_type>
64
+ <sort_order>6</sort_order>
65
+ <show_in_default>1</show_in_default>
66
+ <show_in_website>1</show_in_website>
67
+ <show_in_store>0</show_in_store>
68
+ </custom_success_url>
69
+ </fields>
70
+ </Coinsimple>
71
+ </groups>
72
+ </payment>
73
+ </sections>
74
+ </config>
app/etc/modules/Coinsimple_Coinsimple.xml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Coinsimple_Coinsimple>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ </depends>
9
+ </Coinsimple_Coinsimple>
10
+ </modules>
11
+ </config>
media/magento/magento-plugin-settings-configuration-payment_methods-coinsimple.png ADDED
Binary file
media/magento/magento-plugin-settings-configuration-payment_methods.png ADDED
Binary file
media/magento/magento-plugin-settings-configuration.png ADDED
Binary file
package.xml ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?xml version="1.0"?>
2
+ <package><name>CoinSimple</name><version>1.0.0</version><stability>stable</stability><license>MIT</license><channel>community</channel><extends></extends><summary>Allows a Magento store to accept Bitcoin using any wallet or payment processor.</summary><description>Allows a Magento store to accept Bitcoin using any wallet or payment processor.</description><notes>Initial release.</notes><authors><author><name>CoinSimple</name><user>coinsimple</user><email>support@coinsimple.com</email></author></authors><date>2015-02-24</date><time>16:21:25</time><compatible></compatible><dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies><contents><target name="mage"><file name="README.md" hash="235c6e3b831f890e823392dadeb68acc"/><dir name="app"><dir name="code"><dir name="community"><dir name="Coinsimple"><dir name="Coinsimple"><dir name="coinsimple_php"><file name="README.md" hash="9f978eaf5ec5845086461e4f074ca9bd"/><file name="codeception.yml" hash="621d34aabcc28d86a14cfd5103a8a319"/><file name="composer.json" hash="71293d14ad7dc073ed07221af5ef175f"/><dir name="src"><file name="business.php" hash="3ee386a1559c057a5a281d88d56ed8b3"/><file name="coinsimple.php" hash="50d4e6aecd6317ef56859b8fe0db1f6e"/><file name="invoice.php" hash="30cc39a469be7525b4b6b346cfca321c"/></dir><dir name="tests"><file name="_bootstrap.php" hash="69de87e3ca89be891a5420875c2c149b"/><file name="unit.suite.yml" hash="f7e4b1bfa69f82a5ade04989ceb13c1f"/><dir name="_support"><file name="UnitHelper.php" hash="f1c654f5ba78864c1ada3b9b29076e5f"/></dir><dir name="unit"><file name="BusinessTest.php" hash="7d05449ee27a3bb5a8da147d29fb18cf"/><file name="InvoiceTest.php" hash="75beaebad4071221af54bee242f433ee"/><file name="UnitTester.php" hash="8045fec6a30033e813b71d2d3a30389b"/><file name="_bootstrap.php" hash="d4187c8d31266d51ad1182e9aef77611"/></dir></dir></dir><dir name="controllers"><file name="CallbackController.php" hash="6351414ee5d7cec66d62b86d9e6d1c49"/><file name="RedirectController.php" hash="1f03a3110397d1e702b9dbb0ac7b455e"/></dir><dir name="etc"><file name="config.xml" hash="6853882c2f922ebbce5f55787857c0a2"/><file name="system.xml" hash="9fe9c21099b3de908c178c3537cc2dc5"/></dir><dir name="Model"><file name="PaymentMethod.php" hash="2c05d86674263b97848623fccb7432cf"/></dir></dir></dir></dir></dir><dir name="etc"><dir name="modules"><file name="Coinsimple_Coinsimple.xml" hash="62c462ec1b2fac5025922b8e9f7851e7"/></dir></dir></dir><dir name="media"><dir name="magento"><file name="magento-plugin-settings-configuration-payment_methods-coinsimple.png" hash="ecfe28f114f6fa7152d7cb33e7c0c3b3"/><file name="magento-plugin-settings-configuration-payment_methods.png" hash="d0db383087ca9f8e72f80bd7f3b6e779"/><file name="magento-plugin-settings-configuration.png" hash="65fdb5802676875b5ebad601f541b7ab"/></dir></dir></target></contents></package>