├── .gitignore ├── .rspec ├── .travis.yml ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── lib ├── paymill.rb └── paymill │ ├── base.rb │ ├── client.rb │ ├── offer.rb │ ├── operations │ ├── all.rb │ ├── create.rb │ ├── delete.rb │ ├── find.rb │ └── update.rb │ ├── payment.rb │ ├── preauthorization.rb │ ├── refund.rb │ ├── request │ ├── base.rb │ ├── connection.rb │ ├── helpers.rb │ ├── info.rb │ └── validator.rb │ ├── subscription.rb │ ├── transaction.rb │ ├── version.rb │ └── webhook.rb ├── paymill.gemspec └── spec ├── fake_logger.rb ├── paymill ├── base_spec.rb ├── client_spec.rb ├── offer_spec.rb ├── payment_spec.rb ├── preauthorization_spec.rb ├── refund_spec.rb ├── request │ ├── base_spec.rb │ ├── connection_spec.rb │ ├── info_spec.rb │ └── validator_spec.rb ├── subscription_spec.rb ├── transaction_spec.rb └── webhook_spec.rb ├── paymill_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | pkg/* 4 | *.html 5 | /.rvmrc 6 | .project 7 | .ruby-version 8 | .ruby-gemset 9 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | - 1.9.2 5 | - 2.0.0 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem "rake" 6 | gem "webmock" 7 | gem "pry" 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | paymill (0.5.1) 5 | json 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | addressable (2.3.2) 11 | coderay (1.0.9) 12 | crack (0.3.2) 13 | diff-lcs (1.2.5) 14 | json (1.8.1) 15 | method_source (0.8.2) 16 | pry (0.9.12.2) 17 | coderay (~> 1.0.5) 18 | method_source (~> 0.8) 19 | slop (~> 3.4) 20 | rake (0.9.2.2) 21 | rspec (3.1.0) 22 | rspec-core (~> 3.1.0) 23 | rspec-expectations (~> 3.1.0) 24 | rspec-mocks (~> 3.1.0) 25 | rspec-core (3.1.7) 26 | rspec-support (~> 3.1.0) 27 | rspec-expectations (3.1.2) 28 | diff-lcs (>= 1.2.0, < 2.0) 29 | rspec-support (~> 3.1.0) 30 | rspec-mocks (3.1.3) 31 | rspec-support (~> 3.1.0) 32 | rspec-support (3.1.2) 33 | slop (3.4.6) 34 | webmock (1.9.0) 35 | addressable (>= 2.2.7) 36 | crack (>= 0.1.7) 37 | 38 | PLATFORMS 39 | ruby 40 | 41 | DEPENDENCIES 42 | paymill! 43 | pry 44 | rake 45 | rspec 46 | webmock 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 Stefan Sprenger 4 | Copyright (c) 2012 dkd Internet Service GmbH 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Paymill [![Build Status](https://secure.travis-ci.org/dkd/paymill-ruby.png)](https://travis-ci.org/dkd/paymill-ruby) 2 | ====== 3 | 4 | This is a Ruby wrapper for Paymill's API. 5 | 6 | Documentation 7 | ===== 8 | 9 | We use RubyDoc for documentation. 10 | 11 | The documentation of the current release can be found here: 12 | http://rubydoc.info/gems/paymill/frames/index 13 | 14 | Usage 15 | ====== 16 | 17 | First, you've to install the gem 18 | 19 | gem install paymill 20 | 21 | and require it 22 | 23 | require "paymill" 24 | 25 | Then you have to set your API key: 26 | 27 | Paymill.api_key = "your-api-key" 28 | 29 | ## Configuration 30 | 31 | You can also set the API version, base endpoint and port: 32 | 33 | Paymill.api_version = "v2" 34 | Paymill.api_base = "0.0.0.0" 35 | Paymill.api_port = 3000 36 | 37 | ### Logging 38 | 39 | Out of the box paymill-ruby will log all requests and responses to `STDOUT`, you 40 | can use any logger you want, though: 41 | 42 | Paymill.logger = Logger.new(STDERR) 43 | 44 | Clients 45 | ------- 46 | 47 | *[Paymill documentation on clients](https://www.paymill.com/en-gb/documentation-3/reference/api-reference/#clients)* 48 | 49 | Creating a new client: 50 | 51 | Paymill::Client.create(email: "stefan.sprenger@dkd.de", description: "He is a Ruby guy.") 52 | 53 | Or find an existing client: 54 | 55 | Paymill::Client.find("client_88a388d9dd48f86c3136") 56 | 57 | Updating an existing client only works on an instance: 58 | 59 | client = Paymill::Client.find("client_88a388d9dd48f86c3136") 60 | client.update_attributes(email: "carl.client@example.com") 61 | 62 | Deleting a client: 63 | 64 | Paymill::Client.delete("client_88a388d9dd48f86c3136") 65 | 66 | 67 | For retrieving a collection of all clients you might use the `all` 68 | operation: 69 | 70 | Paymill::Client.all 71 | 72 | To sort and filter collection lists of objects, use the `all` method 73 | with an options hash. For example to find the most recent transactions 74 | belonging to a client you can use the following code: 75 | 76 | Paymill::Transaction.all(client: "", order: "created_at_desc") 77 | 78 | Please note that Transactions and Payments cannot be updated. 79 | 80 | Payments 81 | ------- 82 | 83 | *[Paymill documentation on payments](https://www.paymill.com/en-gb/documentation-3/reference/api-reference/#document-payments)* 84 | 85 | Creating a new credit card payment: 86 | 87 | Paymill::Payment.create(token: "098f6bcd4621d373cade4e832627b4f6") 88 | 89 | Creating a new debit card payment: 90 | 91 | Paymill::Payment.create(type: "debit", code: "12345678", account: "1234512345", holder: "Max Mustermann") 92 | 93 | Or finding an existing payment: 94 | 95 | Paymill::Payment.find("pay_3af44644dd6d25c820a8") 96 | 97 | Deleting a payment: 98 | 99 | Paymill::Payment.delete("pay_3af44644dd6d25c820a8") 100 | 101 | 102 | For retrieving a collection of all payments you might use the `all` 103 | operation: 104 | 105 | Paymill::Payment.all 106 | 107 | Transactions 108 | ----------- 109 | 110 | *[Paymill documentation on transactions](https://www.paymill.com/en-gb/documentation-3/reference/api-reference/#transactions)* 111 | 112 | A transaction can be executed as following 113 | 114 | params = { 115 | :amount => 2000, # cents. Must be an integer 116 | :currency => 'USD', # iso 117 | :client => 'client_123', # client id. Use 'Paymill::Client' 118 | :payment => 'payment_123', # payment id. Use 'Paymill::Payment' 119 | :description => "some comment if needed" 120 | } 121 | Paymill::Transaction.create(params) 122 | 123 | Offers 124 | ------ 125 | 126 | *[Paymill documentation on offers](https://www.paymill.com/en-gb/documentation-3/reference/api-reference/#offers)* 127 | 128 | Creating a new offer: 129 | 130 | Paymill::Offer.create(name: "Monthly", interval: "1 month", amount: 1000, currency: "GBP", trial_period_days: 0) 131 | 132 | Updating an offer (works on an Offer instance and only the name can be changed): 133 | 134 | offer = Paymill::Offer.find("offer_08064e30032afa3aa046") 135 | offer.update_attributes(name: "New name") 136 | 137 | Deleting an offer: 138 | 139 | Paymill::Offer.delete('offer_08064e30032afa3aa046') 140 | 141 | Retrieving an offer: 142 | 143 | Paymill::Offer.find("offer_753480df39aeb114f2f3") 144 | 145 | Retrieving all offers: 146 | 147 | Paymill::Offer.all 148 | 149 | 150 | Webhooks 151 | ------ 152 | 153 | *[Paymill documentation on webhooks](https://www.paymill.com/en-gb/documentation-3/reference/api-reference/#webhooks)* 154 | 155 | Creating a new webhook: 156 | 157 | Paymill::Webhook.create(email: "email@bob.com", event_types: ["transaction.succeeded", "subscription.succeeded"]) 158 | 159 | Updating a webhook works on an instance (url/email and the event types can be changed): 160 | 161 | hook = Paymill::Webhook.find("hook_940143bcdc0c40e7756f") 162 | hook.update_attributes(email: "bob@email.com") 163 | 164 | Deleting a webhook: 165 | 166 | Paymill::Webhook.delete("hook_940143bcdc0c40e7756f") 167 | 168 | Retrieving a webhook: 169 | 170 | hook = Paymill::Webhook.find("hook_940143bcdc0c40e7756f") 171 | 172 | Retrieving all webhooks: 173 | 174 | Paymill::Webhook.all 175 | 176 | 177 | Refunds 178 | ------ 179 | 180 | *[Paymill documentation on refunds](https://www.paymill.com/en-gb/documentation-3/reference/api-reference/#refunds)* 181 | 182 | Creating a new refund: 183 | 184 | Paymill::Refund.create(id: "tran_023d3b5769321c649435", amount: 4200) 185 | 186 | Retrieving a refund: 187 | 188 | refund = Paymill::Refund.find("refund_87bc404a95d5ce616049") 189 | 190 | Retrieving all refunds: 191 | 192 | Paymill::Refund.all 193 | 194 | 195 | Requirements 196 | ===== 197 | 198 | This gem requires Ruby 1.9 and faces version 2 of Paymill's API. 199 | 200 | Bugs 201 | ====== 202 | 203 | Please report bugs at http://github.com/dkd/paymill-ruby/issues. 204 | 205 | Note on Patches/Pull Requests 206 | ====== 207 | 208 | * Fork the project from http://github.com/dkd/paymill-ruby. 209 | * Make your feature addition or bug fix. 210 | * Add tests for it. This is important so I don't break it in a 211 | future version unintentionally. 212 | * Commit, do not mess with rakefile, version, or history. 213 | (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) 214 | * Send me a pull request. Bonus points for topic branches. 215 | 216 | Copyright 217 | ====== 218 | 219 | Copyright (c) 2012-2014 dkd Internet Service GmbH, Stefan Sprenger. See LICENSE for details. 220 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | require "rspec/core/rake_task" 4 | RSpec::Core::RakeTask.new(:spec) do |spec| 5 | spec.pattern = FileList['spec/**/*_spec.rb'] 6 | end 7 | 8 | task default: :spec -------------------------------------------------------------------------------- /lib/paymill.rb: -------------------------------------------------------------------------------- 1 | require "net/http" 2 | require "net/https" 3 | require "json" 4 | require "paymill/version" 5 | require "logger" 6 | 7 | module Paymill 8 | API_BASE = "api.paymill.com" 9 | API_VERSION = "v2" 10 | ROOT_PATH = File.dirname(__FILE__) 11 | 12 | @@api_key = nil 13 | @@api_base = API_BASE 14 | @@api_version = API_VERSION 15 | @@api_port = Net::HTTP.https_default_port 16 | @@logger = Logger.new(STDOUT) 17 | 18 | autoload :Base, "paymill/base" 19 | autoload :Client, "paymill/client" 20 | autoload :Offer, "paymill/offer" 21 | autoload :Payment, "paymill/payment" 22 | autoload :Preauthorization, "paymill/preauthorization" 23 | autoload :Refund, "paymill/refund" 24 | autoload :Subscription, "paymill/subscription" 25 | autoload :Transaction, "paymill/transaction" 26 | autoload :Webhook, "paymill/webhook" 27 | 28 | module Operations 29 | autoload :All, "paymill/operations/all" 30 | autoload :Create, "paymill/operations/create" 31 | autoload :Delete, "paymill/operations/delete" 32 | autoload :Find, "paymill/operations/find" 33 | autoload :Update, "paymill/operations/update" 34 | end 35 | 36 | module Request 37 | autoload :Base, "paymill/request/base" 38 | autoload :Connection, "paymill/request/connection" 39 | autoload :Helpers, "paymill/request/helpers" 40 | autoload :Info, "paymill/request/info" 41 | autoload :Validator, "paymill/request/validator" 42 | end 43 | 44 | class PaymillError < StandardError; end 45 | class AuthenticationError < PaymillError; end 46 | class APIError < PaymillError; end 47 | 48 | # Returns the api key 49 | # 50 | # @return [String] The api key 51 | def self.api_key 52 | @@api_key 53 | end 54 | 55 | # Sets the api key 56 | # 57 | # @param [String] api_key The api key 58 | def self.api_key=(api_key) 59 | @@api_key = api_key 60 | end 61 | 62 | # Returns the api base endpoint 63 | # 64 | # @return [String] The api base endpoint 65 | def self.api_base 66 | @@api_base 67 | end 68 | 69 | # Sets the api base endpoint 70 | # 71 | # @param [String] api_base The api base endpoint 72 | def self.api_base=(api_base) 73 | @@api_base = api_base 74 | end 75 | 76 | # Returns the api version 77 | # 78 | # @return [String] The api version 79 | def self.api_version 80 | @@api_version 81 | end 82 | 83 | # Sets the api version 84 | # 85 | # @param [String] api_version The api version 86 | def self.api_version=(api_version) 87 | @@api_version = api_version 88 | end 89 | 90 | # Returns the api port 91 | # 92 | # @return [String] The api port 93 | def self.api_port 94 | @@api_port 95 | end 96 | 97 | # Sets the api port 98 | # 99 | # @param [String] api_port The api port 100 | def self.api_port=(api_port) 101 | @@api_port = api_port 102 | end 103 | 104 | # Returns the current logger 105 | # 106 | # @return [Logger] The current logger 107 | def self.logger 108 | @@logger 109 | end 110 | 111 | # Sets the logger for Paymill 112 | # 113 | # @param [Logger] logger The logger instance to be used 114 | def self.logger=(logger) 115 | @@logger = logger 116 | end 117 | 118 | # Makes a request against the Paymill API 119 | # 120 | # @param [Symbol] http_method The http method to use, must be one of :get, :post, :put and :delete 121 | # @param [String] api_url The API url to use 122 | # @param [Hash] data The data to send, e.g. used when creating new objects. 123 | # @return [Array] The parsed JSON response. 124 | def self.request(http_method, api_url, data) 125 | info = Request::Info.new(http_method, api_url, data) 126 | Request::Base.new(info).perform 127 | end 128 | end 129 | -------------------------------------------------------------------------------- /lib/paymill/base.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Base 3 | include Paymill::Operations::All 4 | include Paymill::Operations::Create 5 | include Paymill::Operations::Find 6 | 7 | attr_accessor :created_at, :updated_at 8 | 9 | # Initializes the object using the given attributes 10 | # 11 | # @param [Hash] attributes The attributes to use for initialization 12 | def initialize(attributes = {}) 13 | set_attributes(attributes) 14 | parse_timestamps 15 | end 16 | 17 | # Sets the attributes 18 | # 19 | # @param [Hash] attributes The attributes to initialize 20 | def set_attributes(attributes) 21 | attributes.each_pair do |key, value| 22 | instance_variable_set("@#{key}", value) 23 | end 24 | end 25 | 26 | # Parses UNIX timestamps and creates Time objects. 27 | def parse_timestamps 28 | @created_at = Time.at(created_at) if created_at 29 | @updated_at = Time.at(updated_at) if updated_at 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/paymill/client.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Client < Base 3 | include Paymill::Operations::Delete 4 | include Paymill::Operations::Update 5 | 6 | attr_accessor :id, :email, :description, :attributes, :payment, :subscription 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/paymill/offer.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Offer < Base 3 | include Paymill::Operations::Delete 4 | include Paymill::Operations::Update 5 | 6 | attr_accessor :id, :name, :amount, :interval, :trial_period_days, :currency 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/paymill/operations/all.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Operations 3 | module All 4 | module ClassMethods 5 | # Retrieves all available objects from the Paymill API 6 | # 7 | # @param [Hash] options Options to pass to the API 8 | # @return [Array] The available objects 9 | def all(options = {}) 10 | response = Paymill.request(:get, "#{self.name.split("::").last.downcase}s/", options) 11 | results_from response 12 | end 13 | 14 | private 15 | def results_from(response) 16 | results = [] 17 | response["data"].each do |obj| 18 | results << self.new(obj) 19 | end 20 | results 21 | end 22 | end 23 | 24 | def self.included(base) 25 | base.extend(ClassMethods) 26 | end 27 | 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/paymill/operations/create.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Operations 3 | module Create 4 | module ClassMethods 5 | # Creates a new object 6 | # 7 | # @param [Hash] attributes The attributes of the created object 8 | def create(attributes) 9 | response = Paymill.request(:post, "#{self.name.split("::").last.downcase}s", attributes) 10 | self.new(response["data"]) 11 | end 12 | end 13 | 14 | def self.included(base) 15 | base.extend(ClassMethods) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/paymill/operations/delete.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Operations 3 | module Delete 4 | module ClassMethods 5 | # Deletes the given object 6 | # 7 | # @param [Integer] id The id of the object that gets deleted 8 | def delete(id) 9 | response = Paymill.request(:delete, "#{self.name.split("::").last.downcase}s/#{id}", {}) 10 | true 11 | end 12 | end 13 | 14 | def self.included(base) 15 | base.extend(ClassMethods) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/paymill/operations/find.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Operations 3 | module Find 4 | module ClassMethods 5 | # Finds a given object 6 | # 7 | # @param [Integer] id The id of the object that should be found 8 | # @return [Paymill::Base] The found object 9 | def find(id) 10 | response = Paymill.request(:get, "#{self.name.split("::").last.downcase}s/#{id}", {}) 11 | self.new(response["data"]) 12 | end 13 | end 14 | 15 | def self.included(base) 16 | base.extend(ClassMethods) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/paymill/operations/update.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Operations 3 | module Update 4 | 5 | module ClassMethods 6 | # Updates a object 7 | # @param [Integer] id The id of the object that should be updated 8 | # @param [Hash] attributes The attributes that should be updated 9 | def update_attributes(id, attributes) 10 | response = Paymill.request(:put, "#{self.name.split("::").last.downcase}s/#{id}", attributes) 11 | self.new(response["data"]) 12 | end 13 | end 14 | 15 | def self.included(base) 16 | base.extend(ClassMethods) 17 | end 18 | 19 | # Updates a object 20 | # 21 | # @param [Hash] attributes The attributes that should be updated 22 | def update_attributes(attributes) 23 | response = Paymill.request(:put, "#{self.class.name.split("::").last.downcase}s/#{id}", attributes) 24 | set_attributes(response["data"]) 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/paymill/payment.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Payment < Base 3 | include Paymill::Operations::Delete 4 | 5 | attr_accessor :id, :card_type, :country, :expire_month, :expire_year, 6 | :card_holder, :holder, :last4, :account, :code, :client, 7 | :type 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/paymill/preauthorization.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Preauthorization < Base 3 | include Paymill::Operations::Delete 4 | 5 | attr_accessor :id, :amount, :status, :livemode, :payment, :preauthorization, :currency, :client, :source 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/paymill/refund.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Refund < Base 3 | attr_accessor :id, :transaction, :amount, :status, :description, :livemode 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/paymill/request/base.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Request 3 | class Base 4 | attr_reader :info 5 | attr_accessor :response 6 | 7 | def initialize(info) 8 | @info = info 9 | end 10 | 11 | def perform 12 | connection.setup_https 13 | send_request 14 | 15 | validator.validated_data_for(response) 16 | end 17 | 18 | protected 19 | 20 | def send_request 21 | self.response = connection.request 22 | end 23 | 24 | def connection 25 | @connection ||= Connection.new(info) 26 | end 27 | 28 | def validator 29 | @validator ||= Validator.new(info) 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/paymill/request/connection.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Request 3 | class Connection 4 | include Helpers 5 | attr_reader :https 6 | 7 | def initialize(request_info) 8 | @info = request_info 9 | end 10 | 11 | def setup_https 12 | @https = Net::HTTP.new(Paymill.api_base, Paymill.api_port) 13 | @https.use_ssl = true 14 | end 15 | 16 | def request 17 | response = https.start do |connection| 18 | https.request(https_request) 19 | end 20 | log_request_info(response) 21 | response 22 | end 23 | 24 | private 25 | 26 | def https_request 27 | https_request = case @info.http_method 28 | when :post 29 | Net::HTTP::Post.new(@info.url) 30 | when :put 31 | Net::HTTP::Put.new(@info.url) 32 | when :delete 33 | Net::HTTP::Delete.new(@info.url) 34 | else 35 | Net::HTTP::Get.new(@info.path_with_params(@info.url, @info.data)) 36 | end 37 | https_request.basic_auth(Paymill.api_key, "") 38 | 39 | if [:post, :put].include?(@info.http_method) 40 | https_request.set_form_data(normalize_params(@info.data)) 41 | end 42 | 43 | https_request 44 | end 45 | 46 | def log_request_info(response) 47 | if @info 48 | Paymill.logger.info "[Paymill] [#{current_time}] #{@info.http_method.upcase} #{@info.url} #{response.code}" 49 | end 50 | end 51 | 52 | def current_time 53 | Time.now.utc.strftime("%d/%b/%Y %H:%M:%S %Z") 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/paymill/request/helpers.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Request 3 | module Helpers 4 | def flatten_hash_keys(old_hash, new_hash={}, keys=nil) 5 | old_hash.each do |key, value| 6 | key = key.to_s 7 | if value.is_a?(Hash) 8 | all_keys_formatted = keys + "[#{key}]" 9 | flatten_hash_keys(value, new_hash, all_keys_formatted) 10 | else 11 | new_hash[key] = value 12 | end 13 | end 14 | new_hash 15 | end 16 | 17 | def normalize_params(params, key=nil) 18 | params = flatten_hash_keys(params) if params.is_a?(Hash) 19 | result = {} 20 | params.each do |key, value| 21 | case value 22 | when Hash 23 | result[key.to_s] = normalize_params(value) 24 | when Array 25 | value.each_with_index do |item_value, index| 26 | result["#{key.to_s}[#{index}]"] = item_value.to_s 27 | end 28 | else 29 | result[key.to_s] = value.to_s 30 | end 31 | end 32 | result 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/paymill/request/info.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Request 3 | class Info 4 | attr_accessor :http_method, :api_url, :data 5 | 6 | def initialize(http_method, api_url, data) 7 | @http_method = http_method 8 | @api_url = api_url 9 | @data = data 10 | end 11 | 12 | def url 13 | url = "/#{Paymill.api_version}/#{api_url}" 14 | if is_refund? 15 | url += "/#{data[:id]}" 16 | data.delete(:id) 17 | end 18 | 19 | url 20 | end 21 | 22 | def path_with_params(path, params) 23 | unless params.empty? 24 | encoded_params = URI.encode_www_form(params) 25 | [path, encoded_params].join("?") 26 | else 27 | path 28 | end 29 | end 30 | 31 | protected 32 | 33 | def is_refund? 34 | api_url == "refunds" 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/paymill/request/validator.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | module Request 3 | class Validator 4 | attr_reader :info 5 | attr_accessor :response 6 | 7 | def initialize(info) 8 | @info = info 9 | end 10 | 11 | def validated_data_for(incoming_response) 12 | self.response = incoming_response 13 | verify_response_code 14 | info.data = JSON.parse(response.body) 15 | validate_response_data 16 | info.data 17 | end 18 | 19 | protected 20 | 21 | def verify_response_code 22 | raise AuthenticationError if response.code.to_i == 401 23 | raise APIError if response.code.to_i >= 500 24 | end 25 | 26 | def validate_response_data 27 | raise APIError.new(info.data["error"]) if info.data["error"] 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/paymill/subscription.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Subscription < Base 3 | include Paymill::Operations::Delete 4 | include Paymill::Operations::Update 5 | 6 | attr_accessor :id, :offer, :livemode, :cancel_at_period_end, :canceled_at, :client, 7 | :trial_start, :trial_end, :next_capture_at, :payment 8 | 9 | # Parses UNIX timestamps and creates Time objects 10 | def parse_timestamps 11 | super 12 | @next_capture_at = Time.at(next_capture_at) if next_capture_at 13 | @canceled_at = Time.at(canceled_at) if canceled_at 14 | @trial_start = Time.at(trial_start) if trial_start 15 | @trial_end = Time.at(trial_end) if trial_end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/paymill/transaction.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Transaction < Base 3 | include Paymill::Operations::Update 4 | 5 | attr_accessor :id, :amount, :status, :description, :livemode, 6 | :payment, :currency, :client, :response_code, 7 | :origin_amount, :refunds, :source, :short_id 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/paymill/version.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | VERSION = "0.5.1" 3 | end 4 | -------------------------------------------------------------------------------- /lib/paymill/webhook.rb: -------------------------------------------------------------------------------- 1 | module Paymill 2 | class Webhook < Base 3 | include Paymill::Operations::Delete 4 | include Paymill::Operations::Update 5 | 6 | attr_accessor :id, :url, :livemode, :event_types, :active, :app_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /paymill.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "paymill/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "paymill" 7 | s.version = Paymill::VERSION 8 | s.authors = ["Stefan Sprenger"] 9 | s.email = ["stefan.sprenger@dkd.de"] 10 | s.homepage = "https://github.com/dkd/paymill-ruby" 11 | s.summary = %q{API wrapper for Paymill.} 12 | s.description = %q{API wrapper for Paymill.} 13 | 14 | s.files = `git ls-files`.split("\n") 15 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 16 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 17 | s.require_paths = ["lib"] 18 | 19 | s.add_dependency "json" 20 | s.add_development_dependency "rspec" 21 | end -------------------------------------------------------------------------------- /spec/fake_logger.rb: -------------------------------------------------------------------------------- 1 | class FakeLogger 2 | def info(message) 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /spec/paymill/base_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Base do 4 | describe "#parse_timestamps" do 5 | context "given #created_at is present" do 6 | it "creates a Time object" do 7 | base = Paymill::Base.new(created_at: 1362823928) 8 | base.created_at.class.should eql(Time) 9 | end 10 | end 11 | 12 | context "given #updated_at is present" do 13 | it "creates a Time object" do 14 | base = Paymill::Base.new(updated_at: 1362823928) 15 | base.updated_at.class.should eql(Time) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/paymill/client_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Client do 4 | let(:valid_attributes) do 5 | { email: "stefan.sprenger@dkd.de", description: "First customer." } 6 | end 7 | 8 | let (:client) do 9 | Paymill::Client.new(valid_attributes) 10 | end 11 | 12 | describe "#initialize" do 13 | it "initializes all attributes correctly" do 14 | client.email.should eql("stefan.sprenger@dkd.de") 15 | client.description.should eql("First customer.") 16 | end 17 | end 18 | 19 | describe ".find" do 20 | it "makes a new GET request using the correct API endpoint to receive a specific client" do 21 | Paymill.should_receive(:request).with(:get, "clients/123", {}).and_return("data" => {}) 22 | Paymill::Client.find("123") 23 | end 24 | end 25 | 26 | describe ".all" do 27 | it "makes a new GET request using the correct API endpoint to receive all clients" do 28 | Paymill.should_receive(:request).with(:get, "clients/", {}).and_return("data" => {}) 29 | Paymill::Client.all 30 | end 31 | end 32 | 33 | describe ".delete" do 34 | it "makes a new DELETE request using the correct API endpoint" do 35 | Paymill.should_receive(:request).with(:delete, "clients/123", {}).and_return(true) 36 | Paymill::Client.delete("123") 37 | end 38 | end 39 | 40 | describe ".create" do 41 | it "makes a new POST request using the correct API endpoint" do 42 | Paymill.should_receive(:request).with(:post, "clients", valid_attributes).and_return("data" => {}) 43 | Paymill::Client.create(valid_attributes) 44 | end 45 | end 46 | 47 | describe "#update_attributes" do 48 | it "makes a new PUT request using the correct API endpoint" do 49 | client.id = "client_123" 50 | Paymill.should_receive(:request).with(:put, "clients/client_123", {:email => "tim.test@exmaple.com"}).and_return("data" => {}) 51 | 52 | client.update_attributes({:email => "tim.test@exmaple.com"}) 53 | end 54 | 55 | it "updates the instance with the returned attributes" do 56 | changed_attributes = {:email => "tim.test@example.com"} 57 | Paymill.should_receive(:request).and_return("data" => changed_attributes) 58 | client.update_attributes(changed_attributes) 59 | 60 | client.email.should eql("tim.test@example.com") 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/paymill/offer_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Offer do 4 | let(:valid_attributes) do 5 | { 6 | amount: 4200, 7 | currency: "eur", 8 | interval: "month", 9 | name: "Medium Plan" 10 | } 11 | end 12 | 13 | let (:offer) do 14 | Paymill::Offer.new(valid_attributes) 15 | end 16 | 17 | describe "#initialize" do 18 | it "initializes all attributes correctly" do 19 | offer.amount.should eql(4200) 20 | offer.currency.should eql("eur") 21 | offer.interval.should eql("month") 22 | offer.name.should eql("Medium Plan") 23 | end 24 | end 25 | 26 | describe ".find" do 27 | it "makes a new GET request using the correct API endpoint to receive a specific offer" do 28 | Paymill.should_receive(:request).with(:get, "offers/123", {}).and_return("data" => {}) 29 | Paymill::Offer.find("123") 30 | end 31 | end 32 | 33 | describe ".all" do 34 | it "makes a new GET request using the correct API endpoint to receive all offers" do 35 | Paymill.should_receive(:request).with(:get, "offers/", {}).and_return("data" => {}) 36 | Paymill::Offer.all 37 | end 38 | end 39 | 40 | describe ".delete" do 41 | it "makes a new DELETE request using the correct API endpoint" do 42 | Paymill.should_receive(:request).with(:delete, "offers/123", {}).and_return(true) 43 | Paymill::Offer.delete("123") 44 | end 45 | end 46 | 47 | describe ".create" do 48 | it "makes a new POST request using the correct API endpoint" do 49 | Paymill.should_receive(:request).with(:post, "offers", valid_attributes).and_return("data" => {}) 50 | Paymill::Offer.create(valid_attributes) 51 | end 52 | end 53 | 54 | describe "#update_attributes" do 55 | it "makes a new PUT request using the correct API endpoint" do 56 | offer.id = "offer_123" 57 | Paymill.should_receive(:request).with(:put, "offers/offer_123", {:name => "Large Plan"}).and_return("data" => {}) 58 | 59 | offer.update_attributes({:name => "Large Plan"}) 60 | end 61 | 62 | it "updates the instance with the returned attributes" do 63 | changed_attributes = {:name => "Large Plan"} 64 | Paymill.should_receive(:request).and_return("data" => changed_attributes) 65 | offer.update_attributes(changed_attributes) 66 | 67 | offer.name.should eql("Large Plan") 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /spec/paymill/payment_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Payment do 4 | let(:valid_attributes) do 5 | { 6 | card_type: "visa", 7 | country: "germany", 8 | expire_month: 12, 9 | expire_year: 2012, 10 | card_holder: "Stefan Sprenger", 11 | last4: "1111" 12 | } 13 | end 14 | 15 | let (:payment) do 16 | Paymill::Payment.new(valid_attributes) 17 | end 18 | 19 | describe "#initialize" do 20 | it "initializes all attributes correctly" do 21 | payment.card_type.should eql("visa") 22 | payment.country.should eql("germany") 23 | payment.expire_month.should eql(12) 24 | payment.expire_year.should eq(2012) 25 | payment.card_holder.should eql("Stefan Sprenger") 26 | payment.last4.should eql("1111") 27 | end 28 | end 29 | 30 | describe ".find" do 31 | it "makes a new GET request using the correct API endpoint to receive a specific creditcard" do 32 | Paymill.should_receive(:request).with(:get, "payments/123", {}).and_return("data" => {}) 33 | Paymill::Payment.find("123") 34 | end 35 | end 36 | 37 | describe ".all" do 38 | it "makes a new GET request using the correct API endpoint to receive all payments" do 39 | Paymill.should_receive(:request).with(:get, "payments/", {}).and_return("data" => {}) 40 | Paymill::Payment.all 41 | end 42 | end 43 | 44 | describe ".create" do 45 | it "makes a new POST request using the correct API endpoint" do 46 | Paymill.should_receive(:request).with(:post, "payments", valid_attributes).and_return("data" => {}) 47 | Paymill::Payment.create(valid_attributes) 48 | end 49 | end 50 | 51 | describe ".delete" do 52 | it "makes a new DELETE request using the correct API endpoint" do 53 | Paymill.should_receive(:request).with(:delete, "payments/123", {}).and_return(true) 54 | Paymill::Payment.delete("123") 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /spec/paymill/preauthorization_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Preauthorization do 4 | let(:valid_attributes) do 5 | { 6 | payment: "pay_d43cf0ee969d9847512b", 7 | amount: 4200, 8 | currency: "EUR", 9 | source: "paymill-ruby" 10 | } 11 | end 12 | 13 | let (:preauthorization) do 14 | Paymill::Preauthorization.new(valid_attributes) 15 | end 16 | 17 | describe "#initialize" do 18 | it "initializes all attributes correctly" do 19 | preauthorization.payment.should eql("pay_d43cf0ee969d9847512b") 20 | preauthorization.amount.should eql(4200) 21 | preauthorization.currency.should eql("EUR") 22 | preauthorization.source.should eql("paymill-ruby") 23 | end 24 | end 25 | 26 | describe ".create" do 27 | it "makes a new POST request using the correct API endpoint" do 28 | Paymill.should_receive(:request).with(:post, "preauthorizations", valid_attributes).and_return("data" => {}) 29 | Paymill::Preauthorization.create(valid_attributes) 30 | end 31 | end 32 | 33 | describe ".delete" do 34 | it "makes a new DELETE request using the correct API endpoint" do 35 | Paymill.should_receive(:request).with(:delete, "preauthorizations/123", {}).and_return(true) 36 | Paymill::Preauthorization.delete("123") 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/paymill/refund_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Refund do 4 | let(:valid_attributes) do 5 | { 6 | id: "refund_87bc404a95d5ce616049", 7 | amount: "042", 8 | status: "refunded", 9 | description: nil, 10 | livemode: false, 11 | created_at: 1349947042, 12 | updated_at: 1349947042, 13 | transaction: { 14 | id: "tran_2848cb20a6bb578177db", 15 | amount: "378", 16 | origin_amount: 420, 17 | status: "partial_refunded", 18 | description: nil, 19 | livemode: false, 20 | created_at: 1349946216, 21 | updated_at: 1349947042, 22 | response_code: 20000, 23 | refunds: [ 24 | { 25 | id: "refund_87bc404a95d5ce616049", 26 | amount: "042", 27 | status: "refunded", 28 | description: nil, 29 | livemode: false, 30 | created_at: 1349947042, 31 | updated_at: 1349947042, 32 | response_code: 20000 33 | } 34 | ], 35 | payment: { 36 | id: "pay_95ba26ba2c613ebb0ca8", 37 | type: "debit", 38 | client: "client_64b025ee5955abd5af66", 39 | code: "860555000", 40 | holder: "Max Mustermann", 41 | account: "******2345", 42 | created_at: 1349945681, 43 | updated_at: 1349945681 44 | }, 45 | client: { 46 | id: "client_64b025ee5955abd5af66", 47 | email: "lovely-client@example.com", 48 | description: nil, 49 | created_at: 1349945644, 50 | updated_at: 1349945644, 51 | payment: [ 52 | "pay_95ba26ba2c613ebb0ca8" 53 | ], 54 | subscription: nil 55 | }, 56 | preauthorization: nil 57 | } 58 | } 59 | end 60 | 61 | let (:refund) do 62 | Paymill::Refund.new(valid_attributes) 63 | end 64 | 65 | describe "#initialize" do 66 | it "initializes all attributes correctly" do 67 | refund.id.should eql("refund_87bc404a95d5ce616049") 68 | refund.amount.should eql("042") 69 | refund.status.should eql("refunded") 70 | refund.description.should be_nil 71 | refund.livemode.should eql(false) 72 | =begin 73 | refund.transaction[:refunds].should eql( 74 | [ 75 | { 76 | id: "refund_87bc404a95d5ce616049", 77 | amount: "042", 78 | status: "refunded", 79 | description: nil, 80 | livemode: false, 81 | created_at: 1349947042, 82 | updated_at: 1349947042, 83 | response_code: 20000 84 | } 85 | ] 86 | ) 87 | refund.transaction[:payment].should eql( 88 | { 89 | id: "pay_95ba26ba2c613ebb0ca8", 90 | type: "debit", 91 | client: "client_64b025ee5955abd5af66", 92 | code: "860555000", 93 | holder: "Max Mustermann", 94 | account: "******2345", 95 | created_at: 1349945681, 96 | updated_at: 1349945681 97 | } 98 | ) 99 | refund.transaction[:client].should eql( 100 | id: "client_64b025ee5955abd5af66", 101 | email: "lovely-client@example.com", 102 | description: nil, 103 | created_at: 1349945644, 104 | updated_at: 1349945644, 105 | payment: [ 106 | "pay_95ba26ba2c613ebb0ca8" 107 | ], 108 | subscription: nil 109 | ) 110 | =end 111 | end 112 | end 113 | 114 | describe ".create" do 115 | it "makes a new POST request using the correct API endpoint" do 116 | Paymill.should_receive(:request).with(:post, "refunds", valid_attributes).and_return("data" => {}) 117 | Paymill::Refund.create(valid_attributes) 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /spec/paymill/request/base_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Request::Base do 4 | context "#perform" do 5 | it "performs an https request" do 6 | Paymill.stub(:api_key).and_return("some key") 7 | connection = double 8 | validator = double 9 | Paymill::Request::Connection.stub(:new).and_return(connection) 10 | Paymill::Request::Validator.stub(:new).and_return(validator) 11 | 12 | connection.should_receive(:setup_https) 13 | connection.should_receive(:request) 14 | validator.should_receive(:validated_data_for) 15 | 16 | Paymill::Request::Base.new(nil).perform 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/paymill/request/connection_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Request::Connection do 4 | describe "#setup_https" do 5 | it "creates a https object" do 6 | connection = Paymill::Request::Connection.new(nil) 7 | 8 | connection.setup_https 9 | 10 | connection.https.should_not be_nil 11 | end 12 | end 13 | 14 | describe "#request" do 15 | it "performs the actual request" do 16 | connection = Paymill::Request::Connection.new(nil) 17 | connection.setup_https 18 | connection.stub(:https_request) 19 | 20 | connection.https.should_receive(:request) 21 | 22 | connection.request 23 | end 24 | 25 | it 'logs information about the request' do 26 | info = double(http_method: :post, url: "/some/path", data: params) 27 | connection = Paymill::Request::Connection.new(info) 28 | connection.setup_https 29 | connection.stub(:https_request) 30 | connection.https.stub(:request).and_return(double(code: 200)) 31 | 32 | Paymill.logger.should_receive(:info) 33 | 34 | connection.request 35 | end 36 | end 37 | 38 | describe "#https_request" do 39 | it "correctly formats the form data" do 40 | info = double(http_method: :post, url: "/some/path", data: params) 41 | connection = Paymill::Request::Connection.new(info) 42 | connection.setup_https 43 | 44 | connection.__send__(:https_request).body.downcase.should eq("email=abc_abc.com&event_types%5b0%5d=transaction.created&event_types%5b1%5d=transaction.failed&event_types%5b2%5d=refund.created&event_types%5b3%5d=invoice.available") 45 | end 46 | end 47 | 48 | def params 49 | { 50 | email: "abc_abc.com", 51 | event_types: ["transaction.created","transaction.failed", "refund.created", "invoice.available"] 52 | } 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/paymill/request/info_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Request::Info do 4 | describe "#url" do 5 | it "constructs the url" do 6 | info = Paymill::Request::Info.new(:get, "random", OpenStruct.new(id: 1)) 7 | 8 | info.url.should =~ /random/ 9 | end 10 | end 11 | 12 | describe "#path_with_params" do 13 | it "does nothing when no params" do 14 | info = Paymill::Request::Info.new(:get, "random", nil) 15 | path = "/path/to/someplace" 16 | 17 | info.path_with_params(path, {}).should eq path 18 | end 19 | 20 | it "constructs the path with params" do 21 | info = Paymill::Request::Info.new(:get, "random", nil) 22 | path = "/path/to/someplace" 23 | 24 | info.path_with_params(path, {random: "stuff"}).should eq "#{path}?random=stuff" 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/paymill/request/validator_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Request::Validator do 4 | describe "#validated_data_for" do 5 | it "validates the data" do 6 | info = Paymill::Request::Info.new(:get, "random", OpenStruct.new(id: 1)) 7 | validator = Paymill::Request::Validator.new info 8 | response = OpenStruct.new(body: '{"response":"ok"}', code: 200) 9 | 10 | validator.validated_data_for(response).should eq "response" => "ok" 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/paymill/subscription_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Subscription do 4 | let(:valid_attributes) do 5 | { 6 | offer: { 7 | name: "Nerd special", 8 | amount: 123, 9 | interval: "week" 10 | }, 11 | livemode: false, 12 | next_capture_at: 1349945681, 13 | trial_start: 1349945681, 14 | trial_end: 1349945682, 15 | cancel_at_period_end: false, 16 | client: { 17 | email: "stefan.sprenger@dkd.de" 18 | }, 19 | payment: { 20 | id: "pay_3af44644dd6d25c820a8", 21 | } 22 | } 23 | end 24 | 25 | let (:subscription) do 26 | Paymill::Subscription.new(valid_attributes) 27 | end 28 | 29 | describe "#initialize" do 30 | it "initializes all attributes correctly" do 31 | subscription.offer[:name].should eql("Nerd special") 32 | subscription.offer[:amount].should eql(123) 33 | subscription.offer[:interval].should eql("week") 34 | subscription.livemode.should eql(false) 35 | subscription.cancel_at_period_end.should eql(false) 36 | subscription.client[:email].should eql("stefan.sprenger@dkd.de") 37 | subscription.payment[:id].should eql("pay_3af44644dd6d25c820a8") 38 | subscription.trial_start.to_i.should eql(1349945681) 39 | subscription.trial_end.to_i.should eql(1349945682) 40 | end 41 | end 42 | 43 | describe "#parse_timestamps" do 44 | context "given #canceled_at is present" do 45 | it "creates a Time object" do 46 | subscription = Paymill::Subscription.new(canceled_at: 1362823928) 47 | subscription.canceled_at.class.should eql(Time) 48 | end 49 | end 50 | 51 | context "given #trial_start is present" do 52 | it "creates a Time object" do 53 | subscription = Paymill::Subscription.new(trial_start: 1362823928) 54 | subscription.trial_start.class.should eql(Time) 55 | end 56 | end 57 | 58 | context "given #trial_end is present" do 59 | it "creates a Time object" do 60 | subscription = Paymill::Subscription.new(trial_end: 1362823928) 61 | subscription.trial_end.class.should eql(Time) 62 | end 63 | end 64 | 65 | context "given #next_capture_at is present" do 66 | it "creates a Time object" do 67 | subscription = Paymill::Subscription.new(next_capture_at: 1362823928) 68 | subscription.next_capture_at.class.should eql(Time) 69 | end 70 | end 71 | end 72 | 73 | describe ".find" do 74 | it "makes a new GET request using the correct API endpoint to receive a specific subscription" do 75 | Paymill.should_receive(:request).with(:get, "subscriptions/123", {}).and_return("data" => {}) 76 | Paymill::Subscription.find("123") 77 | end 78 | end 79 | 80 | describe ".all" do 81 | it "makes a new GET request using the correct API endpoint to receive all subscriptions" do 82 | Paymill.should_receive(:request).with(:get, "subscriptions/", {}).and_return("data" => {}) 83 | Paymill::Subscription.all 84 | end 85 | end 86 | 87 | describe ".delete" do 88 | it "makes a new DELETE request using the correct API endpoint" do 89 | Paymill.should_receive(:request).with(:delete, "subscriptions/123", {}).and_return(true) 90 | Paymill::Subscription.delete("123") 91 | end 92 | end 93 | 94 | describe ".create" do 95 | it "makes a new POST request using the correct API endpoint" do 96 | Paymill.should_receive(:request).with(:post, "subscriptions", valid_attributes).and_return("data" => {}) 97 | Paymill::Subscription.create(valid_attributes) 98 | end 99 | end 100 | 101 | describe ".update_attributes" do 102 | it "makes a new PUT request using the correct API endpoint" do 103 | Paymill.should_receive(:request).with(:put, "subscriptions/sub_123", {:offer => 50 }).and_return("data" => {}) 104 | Paymill::Subscription.update_attributes("sub_123", {:offer => 50 }) 105 | end 106 | end 107 | 108 | describe "#update_attributes" do 109 | it "makes a new PUT request using the correct API endpoint" do 110 | changed_attributes = {:cancel_at_period_end => true} 111 | subscription.id = "sub_123" 112 | 113 | Paymill.should_receive(:request).with(:put, "subscriptions/sub_123", changed_attributes).and_return("data" => changed_attributes) 114 | 115 | subscription.update_attributes(changed_attributes) 116 | end 117 | 118 | it "should set the returned attributes on the instance" do 119 | Paymill.should_receive(:request).and_return("data" => {:cancel_at_period_end => true}) 120 | subscription.update_attributes({}) 121 | subscription.cancel_at_period_end.should eql(true) 122 | end 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /spec/paymill/transaction_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Transaction do 4 | let(:valid_attributes) do 5 | { 6 | amount: 4200, 7 | origin_amount: 4200, 8 | currency: "EUR", 9 | status: "pending", 10 | description: "Test transaction.", 11 | livemode: false, 12 | response_code: 20000, 13 | short_id: "1234.1000.1230", 14 | payment: { 15 | card_type: "visa", 16 | country: "germany" 17 | }, 18 | client: "client_a013c", 19 | refunds: [ 20 | {:id => "refund_abc"} 21 | ], 22 | source: 'paymill-ruby' 23 | } 24 | end 25 | 26 | let (:transaction) do 27 | Paymill::Transaction.new(valid_attributes) 28 | end 29 | 30 | describe "#initialize" do 31 | it "initializes all attributes correctly" do 32 | transaction.amount.should eql(4200) 33 | transaction.origin_amount.should eql(4200) 34 | transaction.status.should eql("pending") 35 | transaction.description.should eql("Test transaction.") 36 | transaction.livemode.should eql(false) 37 | transaction.response_code.should eql(20000) 38 | transaction.payment[:card_type].should eql("visa") 39 | transaction.payment[:country].should eql("germany") 40 | transaction.client.should eql("client_a013c") 41 | transaction.currency.should eql("EUR") 42 | transaction.refunds.should_not be_nil 43 | transaction.refunds.should_not be_empty 44 | transaction.refunds.first.should_not be_nil 45 | transaction.refunds.first[:id].should eql("refund_abc") 46 | transaction.source.should eql("paymill-ruby") 47 | transaction.short_id.should eql("1234.1000.1230") 48 | end 49 | end 50 | 51 | describe ".find" do 52 | it "makes a new GET request using the correct API endpoint to receive a specific transaction" do 53 | Paymill.should_receive(:request).with(:get, "transactions/123", {}).and_return("data" => {}) 54 | Paymill::Transaction.find("123") 55 | end 56 | end 57 | 58 | describe ".all" do 59 | it "makes a new GET request using the correct API endpoint to receive all transactions" do 60 | Paymill.should_receive(:request).with(:get, "transactions/", {}).and_return("data" => {}) 61 | Paymill::Transaction.all 62 | end 63 | end 64 | 65 | describe ".all with options" do 66 | it "makes a new GET request using the correct API endpoint to receive all transactions" do 67 | Paymill.should_receive(:request).with(:get, "transactions/", { client: "client_id" }).and_return("data" => {}) 68 | Paymill::Transaction.all(client: "client_id") 69 | end 70 | end 71 | 72 | describe ".create" do 73 | it "makes a new POST request using the correct API endpoint" do 74 | Paymill.should_receive(:request).with(:post, "transactions", valid_attributes).and_return("data" => {}) 75 | Paymill::Transaction.create(valid_attributes) 76 | end 77 | end 78 | 79 | describe "#update_attributes" do 80 | it "makes a new PUT request using the correct API endpoint" do 81 | transaction.id = "trans_123" 82 | Paymill.should_receive(:request).with(:put, "transactions/trans_123", {:description => "Transaction Description"}).and_return("data" => {}) 83 | 84 | transaction.update_attributes({:description => "Transaction Description"}) 85 | end 86 | 87 | it "updates the instance with the returned attributes" do 88 | changed_attributes = {:description => "Transaction Description"} 89 | Paymill.should_receive(:request).and_return("data" => changed_attributes) 90 | transaction.update_attributes(changed_attributes) 91 | 92 | transaction.description.should eql("Transaction Description") 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/paymill/webhook_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill::Webhook do 4 | let(:valid_attributes) do 5 | { 6 | id: "hook_40237e20a7d5a231d99b", 7 | url: "", 8 | livemode: false, 9 | event_types: ["transaction.succeeded","transaction.failed"], 10 | created_at: 1360368749, 11 | updated_at: 1360368749, 12 | active: true, 13 | app_id: nil 14 | } 15 | end 16 | 17 | let (:webhook) do 18 | Paymill::Webhook.new(valid_attributes) 19 | end 20 | 21 | describe "#initialize" do 22 | it "initializes all attributes correctly" do 23 | webhook.id.should eql("hook_40237e20a7d5a231d99b") 24 | webhook.url.should eql("") 25 | webhook.livemode.should eql(false) 26 | webhook.event_types.should eql(["transaction.succeeded","transaction.failed"]) 27 | webhook.created_at.to_i.should eql(1360368749) 28 | webhook.updated_at.to_i.should eql(1360368749) 29 | webhook.active.should be_truthy 30 | webhook.app_id.should be_nil 31 | end 32 | end 33 | 34 | describe ".find" do 35 | it "makes a new GET request using the correct API endpoint to receive a specific webhook" do 36 | Paymill.should_receive(:request).with(:get, "webhooks/123", {}).and_return("data" => {}) 37 | Paymill::Webhook.find("123") 38 | end 39 | end 40 | 41 | describe ".all" do 42 | it "makes a new GET request using the correct API endpoint to receive all webhooks" do 43 | Paymill.should_receive(:request).with(:get, "webhooks/", {}).and_return("data" => {}) 44 | Paymill::Webhook.all 45 | end 46 | end 47 | 48 | describe ".create" do 49 | it "makes a new POST request using the correct API endpoint" do 50 | Paymill.should_receive(:request).with(:post, "webhooks", valid_attributes).and_return("data" => {}) 51 | Paymill::Webhook.create(valid_attributes) 52 | end 53 | end 54 | 55 | describe ".delete" do 56 | it "makes a new DELETE request using the correct API endpoint" do 57 | Paymill.should_receive(:request).with(:delete, "webhooks/123", {}).and_return(true) 58 | Paymill::Webhook.delete("123") 59 | end 60 | end 61 | 62 | describe "#update_attributes" do 63 | it "makes a new PUT request using the correct API endpoint" do 64 | changed_attributes = {:url => ""} 65 | webhook.id = "hook_123" 66 | Paymill.should_receive(:request).with(:put, "webhooks/hook_123", changed_attributes).and_return("data" => changed_attributes) 67 | webhook.update_attributes(changed_attributes) 68 | end 69 | 70 | it "should set the returned attributes on the instance" do 71 | Paymill.should_receive(:request).and_return("data" => {:url => ""}) 72 | webhook.update_attributes({}) 73 | webhook.url.should eql("") 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /spec/paymill_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | describe Paymill do 4 | describe ".request" do 5 | context "given no api key exists" do 6 | it "raises an authentication error" do 7 | WebMock.stub_request(:get, /#{Paymill.api_base}/).to_return(:body => "{}", :status => 401) 8 | expect { Paymill.request(:get, "clients", {}) }.to raise_error(Paymill::AuthenticationError) 9 | end 10 | end 11 | 12 | context "with an invalid api key" do 13 | before(:each) do 14 | WebMock.stub_request(:any, /#{Paymill.api_base}/).to_return(:body => "{}") 15 | Paymill.api_key = "your-api-key" 16 | end 17 | 18 | it "attempts to get a url with one param" do 19 | Paymill.request(:get, "transactions", { param_name: "param_value" }) 20 | WebMock.should have_requested(:get, "https://#{Paymill::api_key}:@#{Paymill::api_base}/#{Paymill::api_version}/transactions?param_name=param_value") 21 | end 22 | 23 | it "attempts to get a url with more than one param" do 24 | Paymill.request(:get, "transactions", { client: "client_id", order: "created_at_desc" }) 25 | WebMock.should have_requested(:get, "https://#{Paymill::api_key}:@#{Paymill::api_base}/#{Paymill::api_version}/transactions?client=client_id&order=created_at_desc") 26 | end 27 | 28 | it "doesn't add a question mark if no params" do 29 | Paymill.request(:get, "transactions", {}) 30 | WebMock.should have_requested(:get, "https://#{Paymill::api_key}:@#{Paymill::api_base}/#{Paymill::api_version}/transactions") 31 | end 32 | end 33 | end 34 | 35 | describe 'configurations' do 36 | it 'allows you to set an api key' do 37 | Paymill.api_key = 'xpto' 38 | expect(Paymill.api_key).to eq 'xpto' 39 | end 40 | 41 | it 'allows you to set an api base endpoint' do 42 | Paymill.api_base = 'xpto' 43 | expect(Paymill.api_base).to eq 'xpto' 44 | end 45 | 46 | it 'allows you to set an api version' do 47 | Paymill.api_version = 'v1' 48 | expect(Paymill.api_version).to eq 'v1' 49 | end 50 | 51 | it 'allows you to set an api port' do 52 | Paymill.api_port = 3000 53 | expect(Paymill.api_port).to eq 3000 54 | end 55 | 56 | it 'allows to choose a logger' do 57 | logger = double(:logger) 58 | Paymill.logger = logger 59 | expect(Paymill.logger).to eq logger 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 2 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib")) 3 | require "paymill" 4 | require "rspec" 5 | require "webmock/rspec" 6 | require "pry" 7 | 8 | require "fake_logger" 9 | Paymill.logger = FakeLogger.new 10 | 11 | RSpec.configure do |config| 12 | config.expect_with :rspec do |c| 13 | c.syntax = [:should, :expect] 14 | end 15 | config.mock_with :rspec do |c| 16 | c.syntax = [:should, :expect] 17 | end 18 | end 19 | --------------------------------------------------------------------------------