transactionable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +29 -0
  5. data/app/assets/javascripts/transactionable/add_bank_account.js +45 -0
  6. data/app/assets/javascripts/transactionable/add_credit_card.js +87 -0
  7. data/app/assets/javascripts/transactionable/application.js +12 -0
  8. data/app/assets/stylesheets/transactionable/application.css +13 -0
  9. data/app/controllers/transactionable/application_controller.rb +4 -0
  10. data/app/helpers/transactionable/application_helper.rb +4 -0
  11. data/app/models/transactionable/bank_account.rb +35 -0
  12. data/app/models/transactionable/credit.rb +28 -0
  13. data/app/models/transactionable/credit_card.rb +39 -0
  14. data/app/models/transactionable/debit.rb +28 -0
  15. data/app/models/transactionable/refund.rb +5 -0
  16. data/app/models/transactionable/remote_bank_account.rb +4 -0
  17. data/app/models/transactionable/remote_credit_card.rb +7 -0
  18. data/app/models/transactionable/remote_customer.rb +39 -0
  19. data/app/models/transactionable/remote_entity.rb +42 -0
  20. data/app/models/transactionable/remote_transaction.rb +4 -0
  21. data/app/models/transactionable/reversal.rb +5 -0
  22. data/app/models/transactionable/transaction.rb +25 -0
  23. data/app/views/layouts/transactionable/application.html.erb +14 -0
  24. data/config/routes.rb +2 -0
  25. data/db/migrate/20140108145608_create_transactionable_remote_entities.rb +14 -0
  26. data/db/migrate/20140108182203_create_transactionable_credit_cards.rb +17 -0
  27. data/db/migrate/20140108190511_create_transactionable_transactions.rb +18 -0
  28. data/db/migrate/20140108213120_create_transactionable_bank_accounts.rb +17 -0
  29. data/lib/tasks/transactionable_tasks.rake +4 -0
  30. data/lib/transactionable.rb +9 -0
  31. data/lib/transactionable/acts_as_transactionable.rb +17 -0
  32. data/lib/transactionable/balanced_customer.rb +23 -0
  33. data/lib/transactionable/bank_account_transactionable.rb +23 -0
  34. data/lib/transactionable/credit_card_transactionable.rb +23 -0
  35. data/lib/transactionable/engine.rb +12 -0
  36. data/lib/transactionable/exceptions.rb +6 -0
  37. data/lib/transactionable/version.rb +3 -0
  38. data/spec/dummy/README.rdoc +28 -0
  39. data/spec/dummy/Rakefile +6 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  41. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  42. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  43. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  44. data/spec/dummy/app/models/user.rb +4 -0
  45. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  46. data/spec/dummy/bin/bundle +3 -0
  47. data/spec/dummy/bin/rails +4 -0
  48. data/spec/dummy/bin/rake +4 -0
  49. data/spec/dummy/config.ru +4 -0
  50. data/spec/dummy/config/application.rb +28 -0
  51. data/spec/dummy/config/boot.rb +5 -0
  52. data/spec/dummy/config/database.yml +25 -0
  53. data/spec/dummy/config/environment.rb +5 -0
  54. data/spec/dummy/config/environments/development.rb +29 -0
  55. data/spec/dummy/config/environments/production.rb +80 -0
  56. data/spec/dummy/config/environments/test.rb +36 -0
  57. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  58. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  59. data/spec/dummy/config/initializers/inflections.rb +16 -0
  60. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  61. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  62. data/spec/dummy/config/initializers/session_store.rb +3 -0
  63. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  64. data/spec/dummy/config/locales/en.yml +23 -0
  65. data/spec/dummy/config/routes.rb +4 -0
  66. data/spec/dummy/db/development.sqlite3 +0 -0
  67. data/spec/dummy/db/migrate/20140108162102_create_users.rb +8 -0
  68. data/spec/dummy/db/schema.rb +76 -0
  69. data/spec/dummy/db/test.sqlite3 +0 -0
  70. data/spec/dummy/log/development.log +471 -0
  71. data/spec/dummy/log/test.log +2875 -0
  72. data/spec/dummy/public/404.html +58 -0
  73. data/spec/dummy/public/422.html +58 -0
  74. data/spec/dummy/public/500.html +57 -0
  75. data/spec/dummy/public/favicon.ico +0 -0
  76. data/spec/factories/transactionable_credit_cards.rb +15 -0
  77. data/spec/factories/transactionable_debits.rb +6 -0
  78. data/spec/factories/transactionable_refunds.rb +6 -0
  79. data/spec/factories/transactionable_remote_credit_cards.rb +6 -0
  80. data/spec/factories/transactionable_remote_customers.rb +6 -0
  81. data/spec/factories/transactionable_remote_transactions.rb +6 -0
  82. data/spec/integration/acts_as_bank_account_transactionable_spec.rb +24 -0
  83. data/spec/integration/acts_as_credit_card_transactionable_spec.rb +46 -0
  84. data/spec/integration/models/bank_account_spec.rb +0 -0
  85. data/spec/integration/models/credit_card_spec.rb +28 -0
  86. data/spec/integration/models/credit_spec.rb +0 -0
  87. data/spec/integration/models/debit_spec.rb +0 -0
  88. data/spec/lib/transactionable_spec.rb +6 -0
  89. data/spec/models/transactionable/bank_account_spec.rb +7 -0
  90. data/spec/models/transactionable/credit_card_spec.rb +7 -0
  91. data/spec/models/transactionable/credit_spec.rb +7 -0
  92. data/spec/models/transactionable/debit_spec.rb +7 -0
  93. data/spec/models/transactionable/refund_spec.rb +7 -0
  94. data/spec/models/transactionable/remote_bank_account_spec.rb +7 -0
  95. data/spec/models/transactionable/remote_credit_card_spec.rb +7 -0
  96. data/spec/models/transactionable/remote_customer_spec.rb +7 -0
  97. data/spec/models/transactionable/remote_transaction_spec.rb +7 -0
  98. data/spec/models/transactionable/reversal_spec.rb +7 -0
  99. data/spec/models/transactionable/transaction_spec.rb +7 -0
  100. data/spec/spec_helper.rb +40 -0
  101. metadata +319 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 38e0184eda5b9abc7aeb8930c495815d91de289a
4
+ data.tar.gz: 603cef288a2633938f229905a004ad0947c207c5
5
+ SHA512:
6
+ metadata.gz: 862efeab377c63bde79712bc32dcc2191126c3ec962c3203a721b6afd8a6c7dc2b0b2b73a75b744aa2ac470c97d56eb56de0a64f66d5d491264317380aae2e3e
7
+ data.tar.gz: 67c979751972a0862f4440f1e61c9aa72ed8e8a569aaf77c9c50327bf677b44b02bc17c5c7986abfc4df32054b3e94613e821d2cf89371e43618004d344d2180
@@ -0,0 +1,20 @@
1
+ Copyright 2014 TANOOKI SUIT LABS
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Transactionable
2
+
3
+ This project rocks and uses MIT-LICENSE.
@@ -0,0 +1,29 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Transactionable'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ Bundler::GemHelper.install_tasks
21
+
22
+ require 'rspec/core'
23
+ require 'rspec/core/rake_task'
24
+
25
+ desc "Run all specs in spec directory (excluding plugin specs)"
26
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
27
+
28
+ task :default => :spec
29
+
@@ -0,0 +1,45 @@
1
+ $(document).ready(function() {
2
+ var bankAcctNumberField = $(".acct-number");
3
+ var bankAcctRoutingNumberField = $(".acct-routing-number");
4
+ var bankAcctTypeField = $(".acct-type");
5
+ var bankAcctNameField = $(".acct-name");
6
+ var bankAcctBalancedUriField = $(".acct-balanced-uri");
7
+ var $bankAcctForm = $(".acct-info-form");
8
+ var bankAcctSubmitButton = $(".submit-bank-acct-info");
9
+
10
+ bankAcctCallbackHandler = function(response) {
11
+ console.log(response.status);
12
+ console.log(response);
13
+
14
+ switch (response.status) {
15
+ case 201:
16
+ bankAcctBalancedUriField.val(response.data.uri);
17
+ bankAcctNumberField.val(response.data.account_number);
18
+ bankAcctRoutingNumberField.val(null);
19
+ bankAcctSubmitButton.unbind('click');
20
+ bankAcctSubmitButton.click();
21
+ break;
22
+ default:
23
+ alert("There was an error with the bank account information you supplied. Please verify that all fields are correct and try again.");
24
+ break;
25
+ }
26
+ }
27
+
28
+ if ($bankAcctForm.length > 0 && bankAcctBalancedUriField.val() == "") {
29
+ bankAcctSubmitButton.click(function(e) {
30
+ e.preventDefault();
31
+
32
+ var acctData = {
33
+ name: bankAcctNameField.val(),
34
+ routing_number: bankAcctRoutingNumberField.val(),
35
+ account_number: bankAcctNumberField.val(),
36
+ type: bankAcctTypeField.val()
37
+ }
38
+
39
+ console.log(acctData);
40
+
41
+ balanced.bankAccount.create(acctData, bankAcctCallbackHandler);
42
+ });
43
+ }
44
+
45
+ });
@@ -0,0 +1,87 @@
1
+ $(document).ready(function() {
2
+ var ccNumberField = $(".cc-number");
3
+ var ccSecurityCodeField = $(".cc-csc");
4
+ var ccExpirationDateField = $(".cc-exp-date");
5
+ var ccExpirationYearField = $(".cc-exp-year");
6
+ var ccExpirationMonthField = $(".cc-exp-month");
7
+ var ccNameField = $(".cc-name");
8
+ var ccPostalCodeField = $(".cc-postal-code");
9
+ var balancedUriField = $(".cc-balanced-uri");
10
+ var submitButton = $(".submit-cc-info");
11
+ var ccAddressFields = $(".cc-address");
12
+ var $form = $(".cc-info-form");
13
+
14
+ Array.prototype.clean = function(deleteValue) {
15
+ for (var i = 0; i < this.length; i++) {
16
+ if (this[i] == deleteValue) {
17
+ this.splice(i, 1);
18
+ i--;
19
+ }
20
+ }
21
+ return this;
22
+ };
23
+
24
+ callbackHandler = function(response) {
25
+ console.log(response.status);
26
+ console.log(response);
27
+ window.resp = response;
28
+
29
+ switch (response.status) {
30
+ case 201:
31
+ balancedUriField.val(response.data.uri);
32
+ ccNumberField.val(response.data.brand + ' (' + response.data.last_four + ')');
33
+ ccSecurityCodeField.val(null);
34
+ submitButton.unbind('click');
35
+ submitButton.click();
36
+ break;
37
+ default:
38
+ alert("There was an error with the credit card information you supplied. Please verify that all fields are correct and try again.");
39
+ break;
40
+ }
41
+ }
42
+
43
+ function composeCCData() {
44
+ var ccName = ccNameField.val();
45
+ var ccNumber = ccNumberField.val();
46
+ var ccCSC = ccSecurityCodeField.val();
47
+ var ccZip = ccPostalCodeField.val();
48
+ var ccAddress;
49
+ var ccExpYear;
50
+ var ccExpMo;
51
+
52
+ var ccAddressVals = ccAddressFields.map(function() { return this.value.trim() });
53
+ ccAddress = ccAddressVals.toArray().clean("").join(", ");
54
+
55
+ if (ccExpirationDateField.length > 0) {
56
+ ccExpMo = ccExpirationDateField.val().split("/")[0];
57
+ ccExpYear = ccExpirationDateField.val().split("/")[1];
58
+ } else {
59
+ ccExpMo = ccExpirationMonthField.val();
60
+ ccExpYear = ccExpirationYearField.val();
61
+ }
62
+
63
+ data = {
64
+ card_number: ccNumber,
65
+ expiration_month: ccExpMo,
66
+ expiration_year: ccExpYear,
67
+ security_code: ccCSC,
68
+ name: ccName,
69
+ address: ccAddress,
70
+ postal_code: ccZip
71
+ }
72
+
73
+ return data;
74
+ }
75
+
76
+ if ($form.length > 0 && balancedUriField.val() == "") {
77
+ submitButton.click(function(e) {
78
+ e.preventDefault();
79
+
80
+ var ccData = composeCCData();
81
+ console.log(ccData);
82
+
83
+ balanced.card.create(ccData, callbackHandler);
84
+ });
85
+ }
86
+
87
+ });
@@ -0,0 +1,12 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ module Transactionable
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Transactionable
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,35 @@
1
+ module Transactionable
2
+ class BankAccount < ActiveRecord::Base
3
+ belongs_to :bank_accountable, polymorphic: true
4
+ has_one :remote_bank_account, as: :local_entity, dependent: :destroy
5
+ has_many :transactions, as: :transactionable
6
+ has_many :credits, as: :transactionable
7
+ has_many :reversals, as: :transactionable
8
+
9
+ def remote
10
+ if remote_bank_account && remote_bank_account.synced?
11
+ remote_bank_account.fetch
12
+ end
13
+ end
14
+
15
+ def sync
16
+ balanced_bank_account = remote
17
+ self.bank_name = balanced_bank_account.bank_name
18
+ self.description = balanced_bank_account.account_number
19
+ self.name = balanced_bank_account.name
20
+ self.can_debit = balanced_bank_account.can_debit
21
+ self.account_type = balanced_bank_account.type
22
+ save
23
+ end
24
+
25
+ def credit!(amount)
26
+ remote_credit = remote.credit(amount: amount_in_cents(amount))
27
+ transaction = Credit.create_from_remote(remote_credit)
28
+ credits << transaction
29
+ end
30
+
31
+ def amount_in_cents(amount)
32
+ (amount * 100).to_i
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ module Transactionable
2
+ class Credit < Transaction
3
+ has_many :reversals
4
+
5
+ def reverse!(reversal_amount = nil)
6
+ ensure_valid_reversal(reversal_amount)
7
+ remote_reversal = reversal_amount ? remote.reverse(amount: amount_in_cents(reversal_amount)) : remote.reverse
8
+ transaction = Reversal.create_from_remote(remote_reversal)
9
+ reversals << transaction
10
+ transactionable.transactions << transaction
11
+ end
12
+
13
+ def max_reversal_amount
14
+ amount - reversals.sum(:amount)
15
+ end
16
+
17
+ private
18
+
19
+ def ensure_valid_reversal(reversal_amount)
20
+ reversal_amount = reversal_amount ? reversal_amount : amount
21
+ raise Exceptions::InvalidReversalAmount if reversal_amount > max_reversal_amount
22
+ end
23
+
24
+ def amount_in_cents(dollar_amount)
25
+ (dollar_amount * 100).to_i
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ module Transactionable
2
+ class CreditCard < ActiveRecord::Base
3
+ belongs_to :credit_cardable, polymorphic: true
4
+ has_one :remote_credit_card, as: :local_entity, dependent: :destroy
5
+ has_many :transactions, as: :transactionable
6
+ has_many :debits, as: :transactionable
7
+ has_many :refunds, as: :transactionable
8
+
9
+ def remote
10
+ if remote_credit_card && remote_credit_card.synced?
11
+ remote_credit_card.fetch
12
+ end
13
+ end
14
+
15
+ def debit!(amount)
16
+ # TODO: Consider whether to assume that this method takes
17
+ # decimal/float dollar values
18
+ remote_debit = remote.debit(amount: amount_in_cents(amount))
19
+ transaction = Debit.create_from_remote(remote_debit)
20
+ debits << transaction
21
+ end
22
+
23
+ def amount_in_cents(amount)
24
+ (amount*100).to_i
25
+ end
26
+
27
+ def sync
28
+ remote_cc = self.remote
29
+ self.name = remote_cc.name
30
+ self.description = "#{remote_cc.brand} (#{remote_cc.last_four})"
31
+ self.last_four = remote_cc.last_four
32
+ self.brand = remote_cc.brand
33
+ self.expiration_month = remote_cc.expiration_month
34
+ self.expiration_year = remote_cc.expiration_year
35
+ self.expiration_date = Date.parse("#{expiration_month}/#{expiration_year}")
36
+ save
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,28 @@
1
+ module Transactionable
2
+ class Debit < Transaction
3
+ has_many :refunds
4
+
5
+ def refund!(refund_amount = nil)
6
+ ensure_valid_refund(refund_amount)
7
+ remote_refund = refund_amount ? remote.refund(amount: amount_in_cents(refund_amount)) : remote.refund
8
+ transaction = Refund.create_from_remote(remote_refund)
9
+ refunds << transaction
10
+ transactionable.transactions << transaction
11
+ end
12
+
13
+ def max_refund_amount
14
+ amount - refunds.sum(:amount)
15
+ end
16
+
17
+ private
18
+
19
+ def ensure_valid_refund(refund_amount)
20
+ refund_amount = refund_amount ? refund_amount : amount
21
+ raise Exceptions::InvalidRefundAmount if refund_amount > max_refund_amount
22
+ end
23
+
24
+ def amount_in_cents(dollar_amount)
25
+ (dollar_amount * 100).to_i
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ module Transactionable
2
+ class Refund < Transaction
3
+ belongs_to :credit
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Transactionable
2
+ class RemoteBankAccount < RemoteEntity
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module Transactionable
2
+ class RemoteCreditCard < RemoteEntity
3
+ def remote_entity_type
4
+ "Card"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,39 @@
1
+ module Transactionable
2
+ class RemoteCustomer < RemoteEntity
3
+ before_create :build_or_update_remote
4
+
5
+ def build_or_update_remote
6
+ build_remote unless synced?
7
+ update_remote
8
+ end
9
+
10
+ def build_remote
11
+ balanced_customer = Balanced::Customer.new.save
12
+ self.uri = balanced_customer.uri
13
+ self.synced_at = Time.now
14
+ end
15
+
16
+ def update_remote
17
+ balanced_customer = fetch
18
+ if self.local_entity.respond_to?(:sync_attributes)
19
+ balanced_customer_attributes = local_entity.sync_attributes
20
+ non_address_keys = [:name, :email, :phone]
21
+ new_customer_attributes = balanced_customer_attributes.reject { |k,v| v.blank? }
22
+ address = new_customer_attributes.slice!(*non_address_keys)
23
+ new_customer_attributes.merge!(address: address)
24
+ new_customer_attributes.each { |k,v| balanced_customer.send("#{k}=", v) }
25
+ balanced_customer.save
26
+ else
27
+ balanced_customer = fetch
28
+ balanced_customer.name = "#{self.local_entity_type} #{self.local_entity_id}"
29
+ balanced_customer.meta = {
30
+ entity: self.local_entity_type,
31
+ entity_id: self.local_entity_id
32
+ }
33
+ balanced_customer.save
34
+ end
35
+ update_attribute(:synced_at, Time.now) unless new_record?
36
+ balanced_customer
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ module Transactionable
2
+ class RemoteEntity < ActiveRecord::Base
3
+ belongs_to :local_entity, polymorphic: true
4
+
5
+ before_destroy :destroy_remote
6
+
7
+ def build_or_update_remote
8
+ raise "Not Implemented"
9
+ end
10
+
11
+ def service_name
12
+ read_attribute(:service_name) || "Balanced"
13
+ end
14
+
15
+ def build_remote
16
+ raise "Not Implemented"
17
+ end
18
+
19
+ def update_remote
20
+ raise "Not Implemented"
21
+ end
22
+
23
+ def synced?
24
+ !!self.uri
25
+ end
26
+
27
+ def fetch
28
+ if synced?
29
+ "#{self.service_name}::#{remote_entity_type}".constantize.find(self.uri)
30
+ end
31
+ end
32
+
33
+ def remote_entity_type
34
+ "#{self.class.name.gsub("Transactionable::Remote","")}"
35
+ end
36
+
37
+ def destroy_remote
38
+ re = self.fetch
39
+ re.unstore if re
40
+ end
41
+ end
42
+ end