braintree 3.2.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/braintree.gemspec +3 -3
- data/lib/braintree.rb +6 -1
- data/lib/braintree/account_updater_daily_report.rb +1 -1
- data/lib/braintree/address.rb +2 -1
- data/lib/braintree/apple_pay.rb +1 -1
- data/lib/braintree/apple_pay_card.rb +1 -1
- data/lib/braintree/apple_pay_options.rb +1 -1
- data/lib/braintree/authorization_adjustment.rb +1 -1
- data/lib/braintree/client_token.rb +1 -1
- data/lib/braintree/configuration.rb +11 -11
- data/lib/braintree/connected_merchant_paypal_status_changed.rb +1 -1
- data/lib/braintree/connected_merchant_status_transitioned.rb +1 -1
- data/lib/braintree/credit_card.rb +2 -2
- data/lib/braintree/credit_card_gateway.rb +14 -4
- data/lib/braintree/credit_card_verification.rb +5 -5
- data/lib/braintree/credit_card_verification_search.rb +1 -1
- data/lib/braintree/customer.rb +6 -4
- data/lib/braintree/customer_gateway.rb +2 -0
- data/lib/braintree/customer_search.rb +1 -1
- data/lib/braintree/disbursement.rb +1 -1
- data/lib/braintree/dispute.rb +15 -1
- data/lib/braintree/dispute/paypal_message.rb +15 -0
- data/lib/braintree/dispute_gateway.rb +2 -2
- data/lib/braintree/dispute_search.rb +3 -2
- data/lib/braintree/document_upload.rb +1 -1
- data/lib/braintree/error_codes.rb +10 -6
- data/lib/braintree/google_pay_card.rb +1 -1
- data/lib/braintree/granted_payment_instrument_update.rb +1 -1
- data/lib/braintree/graphql_client.rb +7 -7
- data/lib/braintree/http.rb +3 -3
- data/lib/braintree/local_payment_completed.rb +1 -1
- data/lib/braintree/local_payment_reversed.rb +19 -0
- data/lib/braintree/merchant.rb +1 -1
- data/lib/braintree/merchant_account.rb +1 -1
- data/lib/braintree/merchant_account_gateway.rb +1 -1
- data/lib/braintree/merchant_gateway.rb +1 -1
- data/lib/braintree/modification.rb +1 -1
- data/lib/braintree/oauth_credentials.rb +1 -1
- data/lib/braintree/oauth_gateway.rb +5 -5
- data/lib/braintree/payment_instrument_type.rb +10 -10
- data/lib/braintree/payment_method_gateway.rb +10 -7
- data/lib/braintree/payment_method_nonce.rb +7 -4
- data/lib/braintree/payment_method_nonce_details.rb +37 -0
- data/lib/braintree/payment_method_nonce_details_payer_info.rb +32 -0
- data/lib/braintree/payment_method_nonce_gateway.rb +1 -1
- data/lib/braintree/plan.rb +1 -1
- data/lib/braintree/processor_response_types.rb +3 -3
- data/lib/braintree/revoked_payment_method_metadata.rb +1 -1
- data/lib/braintree/risk_data.rb +3 -1
- data/lib/braintree/samsung_pay_card.rb +1 -1
- data/lib/braintree/settlement_batch_summary.rb +2 -2
- data/lib/braintree/subscription.rb +6 -6
- data/lib/braintree/three_d_secure_info.rb +22 -12
- data/lib/braintree/transaction.rb +32 -24
- data/lib/braintree/transaction_gateway.rb +24 -5
- data/lib/braintree/transaction_line_item.rb +1 -1
- data/lib/braintree/transaction_search.rb +3 -1
- data/lib/braintree/unknown_payment_method.rb +1 -1
- data/lib/braintree/us_bank_account.rb +3 -3
- data/lib/braintree/us_bank_account_verification.rb +1 -1
- data/lib/braintree/us_bank_account_verification_gateway.rb +1 -1
- data/lib/braintree/util.rb +4 -4
- data/lib/braintree/venmo_account.rb +1 -1
- data/lib/braintree/version.rb +1 -1
- data/lib/braintree/visa_checkout_card.rb +2 -2
- data/lib/braintree/webhook_notification.rb +30 -20
- data/lib/braintree/webhook_notification_gateway.rb +5 -5
- data/lib/braintree/webhook_testing_gateway.rb +30 -0
- data/lib/braintree/xml/generator.rb +5 -4
- data/lib/braintree/xml/libxml.rb +0 -1
- data/lib/braintree/xml/parser.rb +22 -12
- data/lib/braintree/xml/rexml.rb +70 -0
- data/spec/integration/braintree/add_on_spec.rb +1 -1
- data/spec/integration/braintree/address_spec.rb +28 -24
- data/spec/integration/braintree/advanced_search_spec.rb +45 -45
- data/spec/integration/braintree/apple_pay_spec.rb +3 -3
- data/spec/integration/braintree/braintree_gateway_spec.rb +2 -1
- data/spec/integration/braintree/client_api/client_token_spec.rb +14 -14
- data/spec/integration/braintree/client_api/spec_helper.rb +5 -5
- data/spec/integration/braintree/credit_card_spec.rb +213 -122
- data/spec/integration/braintree/credit_card_verification_search_spec.rb +2 -2
- data/spec/integration/braintree/credit_card_verification_spec.rb +1 -1
- data/spec/integration/braintree/customer_search_spec.rb +8 -8
- data/spec/integration/braintree/customer_spec.rb +282 -165
- data/spec/integration/braintree/dispute_search_spec.rb +28 -3
- data/spec/integration/braintree/dispute_spec.rb +6 -6
- data/spec/integration/braintree/error_codes_spec.rb +1 -1
- data/spec/integration/braintree/http_spec.rb +2 -2
- data/spec/integration/braintree/merchant_account_spec.rb +25 -26
- data/spec/integration/braintree/merchant_spec.rb +14 -14
- data/spec/integration/braintree/oauth_spec.rb +11 -11
- data/spec/integration/braintree/payment_method_nonce_spec.rb +28 -35
- data/spec/integration/braintree/payment_method_spec.rb +269 -165
- data/spec/integration/braintree/payment_method_us_bank_account_spec.rb +9 -9
- data/spec/integration/braintree/paypal_account_spec.rb +28 -28
- data/spec/integration/braintree/samsung_pay_card_spec.rb +9 -9
- data/spec/integration/braintree/settlement_batch_summary_spec.rb +8 -8
- data/spec/integration/braintree/subscription_spec.rb +133 -133
- data/spec/integration/braintree/test/transaction_amounts_spec.rb +2 -2
- data/spec/integration/braintree/test_transaction_spec.rb +10 -10
- data/spec/integration/braintree/transaction_search_spec.rb +93 -67
- data/spec/integration/braintree/transaction_spec.rb +574 -360
- data/spec/integration/braintree/transaction_us_bank_account_spec.rb +20 -20
- data/spec/integration/braintree/us_bank_account_spec.rb +6 -6
- data/spec/integration/braintree/us_bank_account_verification_search_spec.rb +7 -7
- data/spec/integration/braintree/us_bank_account_verification_spec.rb +8 -8
- data/spec/integration/braintree/visa_checkout_card_spec.rb +5 -5
- data/spec/integration/spec_helper.rb +9 -3
- data/spec/oauth_test_helper.rb +1 -1
- data/spec/script/httpsd.rb +6 -6
- data/spec/spec_helper.rb +6 -3
- data/spec/unit/braintree/address_spec.rb +1 -1
- data/spec/unit/braintree/apple_pay_card_spec.rb +1 -1
- data/spec/unit/braintree/client_token_spec.rb +2 -2
- data/spec/unit/braintree/configuration_spec.rb +42 -42
- data/spec/unit/braintree/credit_card_spec.rb +13 -13
- data/spec/unit/braintree/credit_card_verification_search_spec.rb +1 -1
- data/spec/unit/braintree/credit_card_verification_spec.rb +8 -4
- data/spec/unit/braintree/customer_spec.rb +20 -10
- data/spec/unit/braintree/disbursement_spec.rb +7 -7
- data/spec/unit/braintree/dispute_search_spec.rb +1 -0
- data/spec/unit/braintree/dispute_spec.rb +34 -9
- data/spec/unit/braintree/error_result_spec.rb +5 -5
- data/spec/unit/braintree/errors_spec.rb +8 -8
- data/spec/unit/braintree/http_spec.rb +5 -5
- data/spec/unit/braintree/merchant_account_spec.rb +1 -1
- data/spec/unit/braintree/payment_method_nonce_details_payer_info_spec.rb +31 -0
- data/spec/unit/braintree/payment_method_nonce_details_spec.rb +43 -0
- data/spec/unit/braintree/payment_method_nonce_spec.rb +40 -0
- data/spec/unit/braintree/payment_method_spec.rb +1 -1
- data/spec/unit/braintree/paypal_account_spec.rb +2 -2
- data/spec/unit/braintree/resource_collection_spec.rb +9 -9
- data/spec/unit/braintree/risk_data_spec.rb +9 -5
- data/spec/unit/braintree/subscription_search_spec.rb +1 -1
- data/spec/unit/braintree/successful_result_spec.rb +1 -1
- data/spec/unit/braintree/three_d_secure_info_spec.rb +32 -14
- data/spec/unit/braintree/transaction/credit_card_details_spec.rb +3 -3
- data/spec/unit/braintree/transaction/customer_details_spec.rb +1 -1
- data/spec/unit/braintree/transaction/deposit_details_spec.rb +2 -2
- data/spec/unit/braintree/transaction/paypal_details_spec.rb +1 -1
- data/spec/unit/braintree/transaction_search_spec.rb +12 -12
- data/spec/unit/braintree/transaction_spec.rb +25 -17
- data/spec/unit/braintree/util_spec.rb +18 -18
- data/spec/unit/braintree/validation_error_collection_spec.rb +36 -36
- data/spec/unit/braintree/webhook_notification_spec.rb +88 -56
- data/spec/unit/braintree/xml/rexml_spec.rb +51 -0
- data/spec/unit/braintree/xml_spec.rb +31 -31
- metadata +16 -8
- data/lib/braintree/settlement_batch.rb +0 -0
@@ -18,7 +18,7 @@ module Braintree
|
|
18
18
|
ErrorResult.new(@gateway, response[:api_error_response])
|
19
19
|
else
|
20
20
|
SuccessfulResult.new(
|
21
|
-
:us_bank_account_verification => UsBankAccountVerification._new(response[:us_bank_account_verification])
|
21
|
+
:us_bank_account_verification => UsBankAccountVerification._new(response[:us_bank_account_verification]),
|
22
22
|
)
|
23
23
|
end
|
24
24
|
rescue NotFoundError
|
data/lib/braintree/util.rb
CHANGED
@@ -14,13 +14,13 @@ module Braintree
|
|
14
14
|
else
|
15
15
|
url_encode(full_key) + "=" + url_encode(value)
|
16
16
|
end
|
17
|
-
end.sort *
|
17
|
+
end.sort * "&"
|
18
18
|
end
|
19
19
|
|
20
20
|
def self.parse_query_string(qs)
|
21
|
-
qs.split(
|
22
|
-
pair = couplet.split(
|
23
|
-
result[CGI.unescape(pair[0]).to_sym] = CGI.unescape(pair[1] ||
|
21
|
+
qs.split("&").inject({}) do |result, couplet|
|
22
|
+
pair = couplet.split("=")
|
23
|
+
result[CGI.unescape(pair[0]).to_sym] = CGI.unescape(pair[1] || "")
|
24
24
|
result
|
25
25
|
end
|
26
26
|
end
|
data/lib/braintree/version.rb
CHANGED
@@ -39,7 +39,7 @@ module Braintree
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def _most_recent_verification(attributes)
|
42
|
-
verification = (attributes[:verifications] || []).sort_by{ |verification| verification[:created_at] }.reverse.first
|
42
|
+
verification = (attributes[:verifications] || []).sort_by { |verification| verification[:created_at] }.reverse.first
|
43
43
|
CreditCardVerification._new(verification) if verification
|
44
44
|
end
|
45
45
|
|
@@ -84,7 +84,7 @@ module Braintree
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def self._new(*args) # :nodoc:
|
87
|
-
self.new
|
87
|
+
self.new(*args)
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -1,12 +1,17 @@
|
|
1
|
-
require
|
1
|
+
require "ostruct"
|
2
2
|
|
3
3
|
module Braintree
|
4
4
|
class WebhookNotification
|
5
5
|
include BaseModule
|
6
6
|
|
7
7
|
module Kind
|
8
|
+
|
9
|
+
AccountUpdaterDailyReport = "account_updater_daily_report"
|
10
|
+
|
8
11
|
Check = "check"
|
9
12
|
|
13
|
+
ConnectedMerchantPayPalStatusChanged = "connected_merchant_paypal_status_changed"
|
14
|
+
ConnectedMerchantStatusTransitioned = "connected_merchant_status_transitioned"
|
10
15
|
Disbursement = "disbursement"
|
11
16
|
DisbursementException = "disbursement_exception"
|
12
17
|
|
@@ -17,6 +22,24 @@ module Braintree
|
|
17
22
|
DisputeDisputed = "dispute_disputed"
|
18
23
|
DisputeExpired = "dispute_expired"
|
19
24
|
|
25
|
+
GrantedPaymentInstrumentRevoked = "granted_payment_instrument_revoked"
|
26
|
+
|
27
|
+
GrantorUpdatedGrantedPaymentMethod = "grantor_updated_granted_payment_method"
|
28
|
+
GrantedPaymentMethodRevoked = "granted_payment_method_revoked"
|
29
|
+
|
30
|
+
LocalPaymentCompleted = "local_payment_completed"
|
31
|
+
LocalPaymentReversed = "local_payment_reversed"
|
32
|
+
|
33
|
+
OAuthAccessRevoked = "oauth_access_revoked"
|
34
|
+
|
35
|
+
PartnerMerchantConnected = "partner_merchant_connected"
|
36
|
+
PartnerMerchantDisconnected = "partner_merchant_disconnected"
|
37
|
+
PartnerMerchantDeclined = "partner_merchant_declined"
|
38
|
+
|
39
|
+
PaymentMethodRevokedByCustomer = "payment_method_revoked_by_customer"
|
40
|
+
|
41
|
+
RecipientUpdatedGrantedPaymentMethod = "recipient_updated_granted_payment_method"
|
42
|
+
|
20
43
|
SubscriptionCanceled = "subscription_canceled"
|
21
44
|
SubscriptionChargedSuccessfully = "subscription_charged_successfully"
|
22
45
|
SubscriptionChargedUnsuccessfully = "subscription_charged_unsuccessfully"
|
@@ -27,25 +50,10 @@ module Braintree
|
|
27
50
|
|
28
51
|
SubMerchantAccountApproved = "sub_merchant_account_approved"
|
29
52
|
SubMerchantAccountDeclined = "sub_merchant_account_declined"
|
53
|
+
|
30
54
|
TransactionDisbursed = "transaction_disbursed"
|
31
55
|
TransactionSettlementDeclined = "transaction_settlement_declined"
|
32
56
|
TransactionSettled = "transaction_settled"
|
33
|
-
PartnerMerchantConnected = "partner_merchant_connected"
|
34
|
-
PartnerMerchantDisconnected = "partner_merchant_disconnected"
|
35
|
-
PartnerMerchantDeclined = "partner_merchant_declined"
|
36
|
-
|
37
|
-
AccountUpdaterDailyReport = "account_updater_daily_report"
|
38
|
-
|
39
|
-
OAuthAccessRevoked = "oauth_access_revoked"
|
40
|
-
ConnectedMerchantStatusTransitioned = "connected_merchant_status_transitioned"
|
41
|
-
ConnectedMerchantPayPalStatusChanged = "connected_merchant_paypal_status_changed"
|
42
|
-
|
43
|
-
GrantorUpdatedGrantedPaymentMethod = "grantor_updated_granted_payment_method"
|
44
|
-
RecipientUpdatedGrantedPaymentMethod = "recipient_updated_granted_payment_method"
|
45
|
-
GrantedPaymentInstrumentRevoked = "granted_payment_instrument_revoked"
|
46
|
-
PaymentMethodRevokedByCustomer = "payment_method_revoked_by_customer"
|
47
|
-
|
48
|
-
LocalPaymentCompleted = "local_payment_completed"
|
49
57
|
end
|
50
58
|
|
51
59
|
attr_reader :account_updater_daily_report
|
@@ -57,6 +65,7 @@ module Braintree
|
|
57
65
|
attr_reader :revoked_payment_method_metadata
|
58
66
|
attr_reader :kind
|
59
67
|
attr_reader :local_payment_completed
|
68
|
+
attr_reader :local_payment_reversed
|
60
69
|
attr_reader :oauth_access_revocation
|
61
70
|
attr_reader :partner_merchant
|
62
71
|
attr_reader :source_merchant_id
|
@@ -87,8 +96,9 @@ module Braintree
|
|
87
96
|
@connected_merchant_status_transitioned = ConnectedMerchantStatusTransitioned._new(@subject[:connected_merchant_status_transitioned]) if @subject.has_key?(:connected_merchant_status_transitioned)
|
88
97
|
@connected_merchant_paypal_status_changed = ConnectedMerchantPayPalStatusChanged._new(@subject[:connected_merchant_paypal_status_changed]) if @subject.has_key?(:connected_merchant_paypal_status_changed)
|
89
98
|
@granted_payment_instrument_update = GrantedPaymentInstrumentUpdate._new(@subject[:granted_payment_instrument_update]) if @subject.has_key?(:granted_payment_instrument_update)
|
90
|
-
@revoked_payment_method_metadata = RevokedPaymentMethodMetadata._new(gateway, @subject) if [Kind::GrantedPaymentInstrumentRevoked, Kind::PaymentMethodRevokedByCustomer].include?(@kind)
|
91
|
-
@local_payment_completed = LocalPaymentCompleted._new(@subject[:local_payment]) if @subject.has_key?(:local_payment)
|
99
|
+
@revoked_payment_method_metadata = RevokedPaymentMethodMetadata._new(gateway, @subject) if [Kind::GrantedPaymentInstrumentRevoked, Kind::PaymentMethodRevokedByCustomer, Kind::GrantedPaymentMethodRevoked].include?(@kind)
|
100
|
+
@local_payment_completed = LocalPaymentCompleted._new(@subject[:local_payment]) if @subject.has_key?(:local_payment) && Kind::LocalPaymentCompleted == @kind
|
101
|
+
@local_payment_reversed = LocalPaymentReversed._new(@subject[:local_payment_reversed]) if @subject.has_key?(:local_payment_reversed) && Kind::LocalPaymentReversed == @kind
|
92
102
|
end
|
93
103
|
|
94
104
|
def merchant_account
|
@@ -110,7 +120,7 @@ module Braintree
|
|
110
120
|
class << self
|
111
121
|
protected :new
|
112
122
|
def _new(*args) # :nodoc:
|
113
|
-
self.new
|
123
|
+
self.new(*args)
|
114
124
|
end
|
115
125
|
end
|
116
126
|
end
|
@@ -7,8 +7,8 @@ module Braintree
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def parse(signature_string, payload)
|
10
|
-
raise InvalidSignature,
|
11
|
-
raise InvalidSignature,
|
10
|
+
raise InvalidSignature, "signature cannot be nil" if signature_string.nil?
|
11
|
+
raise InvalidSignature, "payload cannot be nil" if payload.nil?
|
12
12
|
if payload =~ /[^A-Za-z0-9+=\/\n]/
|
13
13
|
raise InvalidSignature, "payload contains illegal characters"
|
14
14
|
end
|
@@ -18,7 +18,7 @@ module Braintree
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def verify(challenge)
|
21
|
-
raise InvalidChallenge,
|
21
|
+
raise InvalidChallenge, "challenge contains non-hex characters" unless challenge =~ /\A[a-f0-9]{20,32}\z/
|
22
22
|
digest = Braintree::Digest.hexdigest(@config.private_key, challenge)
|
23
23
|
"#{@config.public_key}|#{digest}"
|
24
24
|
end
|
@@ -34,13 +34,13 @@ module Braintree
|
|
34
34
|
|
35
35
|
def _verify_signature(signature_string, payload)
|
36
36
|
public_key, signature = _matching_signature_pair(signature_string)
|
37
|
-
raise InvalidSignature,
|
37
|
+
raise InvalidSignature, "no matching public key" if public_key.nil?
|
38
38
|
|
39
39
|
signature_matches = [payload, payload + "\n"].any? do |payload|
|
40
40
|
payload_signature = Braintree::Digest.hexdigest(@config.private_key, payload)
|
41
41
|
Braintree::Digest.secure_compare(signature, payload_signature)
|
42
42
|
end
|
43
|
-
raise InvalidSignature,
|
43
|
+
raise InvalidSignature, "signature does not match payload - one has been modified" unless signature_matches
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -82,10 +82,14 @@ module Braintree
|
|
82
82
|
_granted_payment_instrument_update_sample_xml(id)
|
83
83
|
when Braintree::WebhookNotification::Kind::RecipientUpdatedGrantedPaymentMethod
|
84
84
|
_granted_payment_instrument_update_sample_xml(id)
|
85
|
+
when Braintree::WebhookNotification::Kind::GrantedPaymentMethodRevoked
|
86
|
+
_granted_payment_method_revoked_xml(id)
|
85
87
|
when Braintree::WebhookNotification::Kind::PaymentMethodRevokedByCustomer
|
86
88
|
_payment_method_revoked_by_customer_sample_xml(id)
|
87
89
|
when Braintree::WebhookNotification::Kind::LocalPaymentCompleted
|
88
90
|
_local_payment_completed_sample_xml(id)
|
91
|
+
when Braintree::WebhookNotification::Kind::LocalPaymentReversed
|
92
|
+
_local_payment_reversed_sample_xml(id)
|
89
93
|
else
|
90
94
|
_subscription_sample_xml(id)
|
91
95
|
end
|
@@ -875,6 +879,24 @@ module Braintree
|
|
875
879
|
XML
|
876
880
|
end
|
877
881
|
|
882
|
+
def _granted_payment_method_revoked_xml(id)
|
883
|
+
<<-XML
|
884
|
+
<venmo-account>
|
885
|
+
<created-at type='dateTime'>2018-10-11T21:28:37Z</created-at>
|
886
|
+
<updated-at type='dateTime'>2018-10-11T21:28:37Z</updated-at>
|
887
|
+
<default type='boolean'>true</default>
|
888
|
+
<image-url>https://assets.braintreegateway.com/payment_method_logo/venmo.png?environment=test</image-url>
|
889
|
+
<token>#{id}</token>
|
890
|
+
<source-description>Venmo Account: venmojoe</source-description>
|
891
|
+
<username>venmojoe</username>
|
892
|
+
<venmo-user-id>456</venmo-user-id>
|
893
|
+
<subscriptions type='array'/>
|
894
|
+
<customer-id>venmo_customer_id</customer-id>
|
895
|
+
<global-id>cGF5bWVudG1ldGhvZF92ZW5tb2FjY291bnQ</global-id>
|
896
|
+
</venmo-account>
|
897
|
+
XML
|
898
|
+
end
|
899
|
+
|
878
900
|
def _payment_method_revoked_by_customer_sample_xml(id)
|
879
901
|
<<-XML
|
880
902
|
<paypal-account>
|
@@ -912,5 +934,13 @@ module Braintree
|
|
912
934
|
</local-payment>
|
913
935
|
XML
|
914
936
|
end
|
937
|
+
|
938
|
+
def _local_payment_reversed_sample_xml(id)
|
939
|
+
<<-XML
|
940
|
+
<local-payment-reversed>
|
941
|
+
<payment-id>PAY-XYZ123</payment-id>
|
942
|
+
</local-payment-reversed>
|
943
|
+
XML
|
944
|
+
end
|
915
945
|
end
|
916
946
|
end
|
@@ -12,6 +12,7 @@ module Braintree
|
|
12
12
|
"Date" => "datetime",
|
13
13
|
"DateTime" => "datetime",
|
14
14
|
"Time" => "datetime",
|
15
|
+
"ActiveSupport::TimeWithZone" => "datetime"
|
15
16
|
}
|
16
17
|
|
17
18
|
XML_FORMATTING_NAMES = {
|
@@ -25,7 +26,7 @@ module Braintree
|
|
25
26
|
date_or_time.respond_to?(:xmlschema) ? date_or_time.xmlschema : date_or_time.to_s
|
26
27
|
end,
|
27
28
|
"bigdecimal" => Proc.new do |bigdecimal|
|
28
|
-
str = bigdecimal.to_s(
|
29
|
+
str = bigdecimal.to_s("F")
|
29
30
|
if str =~ /\.\d$/
|
30
31
|
str += "0"
|
31
32
|
end
|
@@ -61,15 +62,15 @@ module Braintree
|
|
61
62
|
else
|
62
63
|
type_name = XML_TYPE_NAMES[value.class.name]
|
63
64
|
|
64
|
-
attributes = ((value.nil? || type_name.nil?) ? {} : {
|
65
|
+
attributes = ((value.nil? || type_name.nil?) ? {} : {:type => type_name})
|
65
66
|
if value.nil?
|
66
67
|
attributes[:nil] = true
|
67
68
|
end
|
68
69
|
|
69
|
-
|
70
|
+
formatting_name = XML_FORMATTING_NAMES[value.class.name]
|
70
71
|
options[:builder].tag!(_xml_escape(key),
|
71
72
|
XML_FORMATTING[formatting_name] ? XML_FORMATTING[formatting_name].call(value) : value,
|
72
|
-
attributes
|
73
|
+
attributes,
|
73
74
|
)
|
74
75
|
end
|
75
76
|
end
|
data/lib/braintree/xml/libxml.rb
CHANGED
data/lib/braintree/xml/parser.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
|
3
3
|
module Braintree
|
4
4
|
module Xml # :nodoc:
|
5
|
-
CONTENT_ROOT =
|
5
|
+
CONTENT_ROOT = "__content__"
|
6
6
|
|
7
7
|
module Parser # :nodoc:
|
8
8
|
XML_PARSING = {
|
@@ -11,18 +11,28 @@ module Braintree
|
|
11
11
|
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
|
12
12
|
}
|
13
13
|
|
14
|
-
def self.hash_from_xml(xml)
|
15
|
-
standardized_hash_structure =
|
14
|
+
def self.hash_from_xml(xml, parser = _determine_parser)
|
15
|
+
standardized_hash_structure = parser.parse(xml)
|
16
16
|
transformed_xml = _transform_xml(standardized_hash_structure)
|
17
17
|
Util.symbolize_keys(transformed_xml)
|
18
18
|
end
|
19
19
|
|
20
|
+
def self._determine_parser
|
21
|
+
# If LibXML is not available, we fall back to REXML
|
22
|
+
# This allows us to be compatible with JRuby, which LibXML does not support
|
23
|
+
if defined?(::LibXML::XML) && ::LibXML::XML.respond_to?(:default_keep_blanks=)
|
24
|
+
::Braintree::Xml::Libxml
|
25
|
+
else
|
26
|
+
::Braintree::Xml::Rexml
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
20
30
|
# Transform into standard Ruby types and convert all keys to snake_case instead of dash-case
|
21
31
|
def self._transform_xml(value)
|
22
32
|
case value.class.to_s
|
23
|
-
when
|
24
|
-
if value[
|
25
|
-
child_key, entries = value.detect { |k,v| k !=
|
33
|
+
when "Hash"
|
34
|
+
if value["type"] == "array"
|
35
|
+
child_key, entries = value.detect { |k,v| k != "type" } # child_key is throwaway
|
26
36
|
if entries.nil? || ((c = value[CONTENT_ROOT]) && c.strip.empty?)
|
27
37
|
[]
|
28
38
|
else
|
@@ -37,21 +47,21 @@ module Braintree
|
|
37
47
|
end
|
38
48
|
elsif value.has_key?(CONTENT_ROOT)
|
39
49
|
content = value[CONTENT_ROOT]
|
40
|
-
if parser = XML_PARSING[value["type"]]
|
50
|
+
if (parser = XML_PARSING[value["type"]])
|
41
51
|
XML_PARSING[value["type"]].call(content)
|
42
52
|
else
|
43
53
|
content
|
44
54
|
end
|
45
|
-
elsif value[
|
55
|
+
elsif value["type"] == "string" && value["nil"] != "true"
|
46
56
|
""
|
47
57
|
elsif value == {}
|
48
58
|
""
|
49
|
-
elsif value.nil? || value[
|
59
|
+
elsif value.nil? || value["nil"] == "true"
|
50
60
|
nil
|
51
61
|
# If the type is the only element which makes it then
|
52
62
|
# this still makes the value nil, except if type is
|
53
63
|
# a XML node(where type['value'] is a Hash)
|
54
|
-
elsif value[
|
64
|
+
elsif value["type"] && value.size == 1 && !value["type"].is_a?(::Hash)
|
55
65
|
raise "is this needed?"
|
56
66
|
nil
|
57
67
|
else
|
@@ -61,14 +71,14 @@ module Braintree
|
|
61
71
|
end
|
62
72
|
xml_value
|
63
73
|
end
|
64
|
-
when
|
74
|
+
when "Array"
|
65
75
|
value.map! { |i| _transform_xml(i) }
|
66
76
|
case value.length
|
67
77
|
when 0 then nil
|
68
78
|
when 1 then value.first
|
69
79
|
else value
|
70
80
|
end
|
71
|
-
when
|
81
|
+
when "String"
|
72
82
|
value
|
73
83
|
else
|
74
84
|
raise "can't transform #{value.class.name} - #{value.inspect}"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Portions of this code were copied and modified from Ruby on Rails, released
|
2
|
+
# under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
|
3
|
+
module Braintree
|
4
|
+
module Xml # :nodoc:
|
5
|
+
module Rexml # :nodoc:
|
6
|
+
|
7
|
+
CONTENT_KEY = "__content__".freeze
|
8
|
+
|
9
|
+
def self.parse(string)
|
10
|
+
require "rexml/document" unless defined?(REXML::Document)
|
11
|
+
doc = REXML::Document.new(string)
|
12
|
+
_merge_element!({}, doc.root)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self._merge_element!(hash, element)
|
16
|
+
_merge!(hash, element.name, _collapse(element))
|
17
|
+
end
|
18
|
+
|
19
|
+
def self._collapse(element)
|
20
|
+
hash = _get_attributes(element)
|
21
|
+
|
22
|
+
if element.has_elements?
|
23
|
+
element.each_element { |child| _merge_element!(hash, child) }
|
24
|
+
_merge_texts!(hash, element) unless _empty_content?(element)
|
25
|
+
hash
|
26
|
+
else
|
27
|
+
_merge_texts!(hash, element)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self._merge_texts!(hash, element)
|
32
|
+
unless element.has_text?
|
33
|
+
hash
|
34
|
+
else
|
35
|
+
# must use value to prevent double-escaping
|
36
|
+
_merge!(
|
37
|
+
hash,
|
38
|
+
CONTENT_KEY,
|
39
|
+
element.texts.map { |t| t.value }.join,
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self._merge!(hash, key, value)
|
45
|
+
if hash.has_key?(key)
|
46
|
+
if hash[key].instance_of?(Array)
|
47
|
+
hash[key] << value
|
48
|
+
else
|
49
|
+
hash[key] = [hash[key], value]
|
50
|
+
end
|
51
|
+
elsif value.instance_of?(Array)
|
52
|
+
hash[key] = [value]
|
53
|
+
else
|
54
|
+
hash[key] = value
|
55
|
+
end
|
56
|
+
hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def self._get_attributes(element)
|
60
|
+
attributes = {}
|
61
|
+
element.attributes.each { |n,v| attributes[n] = v }
|
62
|
+
attributes
|
63
|
+
end
|
64
|
+
|
65
|
+
def self._empty_content?(element)
|
66
|
+
element.texts.join.strip == ""
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|