rconomic 0.2.1 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/.travis.yml +1 -0
  2. data/Gemfile +8 -1
  3. data/Gemfile.lock +8 -1
  4. data/Guardfile +6 -0
  5. data/README.md +39 -14
  6. data/lib/economic/account.rb +25 -0
  7. data/lib/economic/cash_book.rb +39 -0
  8. data/lib/economic/cash_book_entry.rb +111 -0
  9. data/lib/economic/current_invoice.rb +33 -2
  10. data/lib/economic/current_invoice_line.rb +1 -1
  11. data/lib/economic/debtor.rb +2 -1
  12. data/lib/economic/debtor_contact.rb +1 -1
  13. data/lib/economic/entity/handle.rb +66 -0
  14. data/lib/economic/entity.rb +39 -36
  15. data/lib/economic/invoice.rb +58 -0
  16. data/lib/economic/proxies/account_proxy.rb +22 -0
  17. data/lib/economic/proxies/cash_book_entry_proxy.rb +53 -0
  18. data/lib/economic/proxies/cash_book_proxy.rb +47 -0
  19. data/lib/economic/proxies/current_invoice_line_proxy.rb +7 -1
  20. data/lib/economic/proxies/current_invoice_proxy.rb +18 -1
  21. data/lib/economic/proxies/debtor_contact_proxy.rb +36 -10
  22. data/lib/economic/proxies/debtor_proxy.rb +32 -1
  23. data/lib/economic/proxies/entity_proxy.rb +30 -3
  24. data/lib/economic/proxies/invoice_proxy.rb +31 -0
  25. data/lib/economic/session.rb +18 -1
  26. data/lib/economic/support/string.rb +19 -0
  27. data/lib/rconomic/version.rb +1 -1
  28. data/lib/rconomic.rb +10 -2
  29. data/spec/economic/cash_book_entry_spec.rb +20 -0
  30. data/spec/economic/cash_book_spec.rb +34 -0
  31. data/spec/economic/current_invoice_spec.rb +44 -1
  32. data/spec/economic/debtor_contact_spec.rb +2 -2
  33. data/spec/economic/debtor_spec.rb +6 -0
  34. data/spec/economic/entity/handle_spec.rb +116 -0
  35. data/spec/economic/entity_spec.rb +26 -22
  36. data/spec/economic/invoice_spec.rb +68 -0
  37. data/spec/economic/proxies/cash_book_entry_proxy_spec.rb +62 -0
  38. data/spec/economic/proxies/cash_book_proxy_spec.rb +54 -0
  39. data/spec/economic/proxies/current_invoice_line_proxy_spec.rb +1 -1
  40. data/spec/economic/proxies/current_invoice_proxy_spec.rb +66 -2
  41. data/spec/economic/proxies/debtor_proxy_spec.rb +39 -1
  42. data/spec/economic/proxies/invoice_proxy_spec.rb +75 -0
  43. data/spec/economic/session_spec.rb +11 -1
  44. data/spec/fixtures/cash_book_book/success.xml +10 -0
  45. data/spec/fixtures/cash_book_entry_create_debtor_payment/success.xml +11 -0
  46. data/spec/fixtures/cash_book_entry_create_finance_voucher/success.xml +11 -0
  47. data/spec/fixtures/cash_book_entry_create_from_data/success.xml +11 -0
  48. data/spec/fixtures/cash_book_entry_get_data/success.xml +73 -0
  49. data/spec/fixtures/cash_book_get_all/multiple.xml +15 -0
  50. data/spec/fixtures/cash_book_get_entries/success.xml +17 -0
  51. data/spec/fixtures/cash_book_get_name/success.xml +8 -0
  52. data/spec/fixtures/current_invoice_book/success.xml +10 -0
  53. data/spec/fixtures/current_invoice_find_by_date_interval/many.xml +15 -0
  54. data/spec/fixtures/current_invoice_find_by_date_interval/none.xml +8 -0
  55. data/spec/fixtures/current_invoice_find_by_date_interval/single.xml +12 -0
  56. data/spec/fixtures/current_invoice_get_all/multiple.xml +15 -0
  57. data/spec/fixtures/current_invoice_get_all/none.xml +8 -0
  58. data/spec/fixtures/current_invoice_get_all/single.xml +12 -0
  59. data/spec/fixtures/current_invoice_get_data_array/multiple.xml +141 -0
  60. data/spec/fixtures/current_invoice_get_data_array/single.xml +75 -0
  61. data/spec/fixtures/debtor_find_by_number/found.xml +10 -0
  62. data/spec/fixtures/debtor_find_by_number/not_found.xml +7 -0
  63. data/spec/fixtures/debtor_get_all/multiple.xml +15 -0
  64. data/spec/fixtures/debtor_get_all/single.xml +12 -0
  65. data/spec/fixtures/debtor_get_data_array/multiple.xml +103 -0
  66. data/spec/fixtures/invoice_find_by_date_interval/many.xml +15 -0
  67. data/spec/fixtures/invoice_find_by_date_interval/none.xml +9 -0
  68. data/spec/fixtures/invoice_find_by_date_interval/single.xml +12 -0
  69. data/spec/fixtures/invoice_get_data/success.xml +74 -0
  70. data/spec/fixtures/invoice_get_pdf/success.xml +8 -0
  71. data/spec/fixtures/invoice_get_remainder/success.xml +8 -0
  72. data/spec/fixtures/spec_entity_delete/success.xml +6 -0
  73. metadata +54 -6
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
+ - 1.9.3
5
6
  - ree
6
7
  - rbx
7
8
 
data/Gemfile CHANGED
@@ -5,4 +5,11 @@ gemspec
5
5
  group :test do
6
6
  gem 'rake'
7
7
  gem 'savon_spec', '0.1.6'
8
- end
8
+ end
9
+
10
+ # Not required to develop rconomic, but useful. See file
11
+ # mappings in Guardfile
12
+ group :guard do
13
+ gem 'guard'
14
+ gem 'guard-rspec'
15
+ end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rconomic (0.1.0)
4
+ rconomic (0.3)
5
5
  activesupport (~> 3.0)
6
6
  savon (= 0.9.5)
7
7
 
@@ -13,6 +13,10 @@ GEM
13
13
  gyoku (>= 0.4.0)
14
14
  builder (3.0.0)
15
15
  diff-lcs (1.1.2)
16
+ guard (0.8.8)
17
+ thor (~> 0.14.6)
18
+ guard-rspec (0.5.0)
19
+ guard (>= 0.8.4)
16
20
  gyoku (0.4.4)
17
21
  builder (>= 2.1.2)
18
22
  httpi (0.9.5)
@@ -42,6 +46,7 @@ GEM
42
46
  mocha (>= 0.9.8)
43
47
  rspec (>= 2.0.0)
44
48
  savon (>= 0.8.0)
49
+ thor (0.14.6)
45
50
  wasabi (1.0.0)
46
51
  nokogiri (>= 1.4.0)
47
52
 
@@ -49,6 +54,8 @@ PLATFORMS
49
54
  ruby
50
55
 
51
56
  DEPENDENCIES
57
+ guard
58
+ guard-rspec
52
59
  rake
53
60
  rconomic!
54
61
  savon_spec (= 0.1.6)
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2, :cli => "--color", :all_after_pass => false, :all_on_start => false, :keep_failed => false do
2
+ watch('spec/spec_helper.rb') { "spec" }
3
+ watch(%r{^spec/.+_spec\.rb$})
4
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
5
+ end
6
+
data/README.md CHANGED
@@ -31,11 +31,11 @@ Usage example
31
31
  debtor.save
32
32
 
33
33
  # Create invoice for debtor:
34
- invoice = economic.current_invoices.build
35
- invoice.date = Time.now
36
- invoice.due_date = Time.now + 15
37
- invoice.exchange_rate = 100
38
- invoice.is_vat_included = false
34
+ current_invoice = economic.current_invoices.build
35
+ current_invoice.date = Time.now
36
+ current_invoice.due_date = Time.now + 15
37
+ current_invoice.exchange_rate = 100
38
+ current_invoice.is_vat_included = false
39
39
 
40
40
  invoice_line = Economic::CurrentInvoiceLine.new
41
41
  invoice_line.description = 'Line on invoice'
@@ -43,9 +43,31 @@ Usage example
43
43
  invoice_line.product_handle = { :number => 101 }
44
44
  invoice_line.quantity = 12
45
45
  invoice_line.unit_net_price = 19.95
46
- invoice.lines << invoice_line
47
-
48
- invoice.save
46
+ current_invoice.lines << invoice_line
47
+
48
+ current_invoice.save
49
+
50
+ # You can delete it by doing:
51
+ # current_invoice.destroy
52
+
53
+ invoice = current_invoice.book
54
+
55
+ # Create a debtor payment
56
+
57
+ cash_book = economic.cash_books.all.last # Or find it by its number
58
+
59
+ # The reason debtor payments are done this way is because we don't want to specify the voucher number. If we build the cash book entry ourselves,
60
+ # without specifying the voucher number, the API will complain. This way, E-Conomics will assign a voucher number for us.
61
+
62
+ cash_book_entry = cash_book.entries.create_debtor_payment(:debtor_handle => debtor.handle, :contra_account_handle => { :number => '1920' })
63
+ cash_book_entry.cash_book_entry_type = "DebtorPayment" # For some reason, we need to specify this.
64
+ cash_book_entry.amount = -123.45
65
+ cash_book_entry.currency_handle = { "Code" => "DKK" }
66
+ cash_book_entry.debtor_invoice_number = invoice.number
67
+ cash_book_entry.text = "Payment, invoice #{ invoice.number }"
68
+ cash_book_entry.save
69
+
70
+ cash_book.book
49
71
 
50
72
 
51
73
  How to enable e-conomic API access
@@ -61,12 +83,15 @@ It doesn't do everything
61
83
 
62
84
  Not even remotely... For now, limited to a small subset of all the [available operations](https://www.e-conomic.com/secure/api1/EconomicWebService.asmx):
63
85
 
64
- | Create | Read | Update
65
- -------------------+--------+------+-------
66
- CurrentInvoice | X | X | X
67
- CurrentInvoiceLine | X | X | X
68
- Debtor | X | X | X
69
- DebtorContact | X | X | X
86
+ | Create | Read | Update | Delete
87
+ -------------------+--------+------+--------+-------
88
+ CashBook | X | X | X | X
89
+ CashBookEntry | X | X | X | X
90
+ CurrentInvoice | X | X | X | X
91
+ CurrentInvoiceLine | X | X | X | X
92
+ Debtor | X | X | X | X
93
+ DebtorContact | X | X | X | X
94
+ Invoice | X | X | |
70
95
 
71
96
 
72
97
  Credits
@@ -0,0 +1,25 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+ class Account < Entity
5
+ has_properties :name, :number, :balance, :block_direct_entries, :contra_account, :debit_credit, :department, :distribution_key, :is_accessible, :opening_account, :total_from, :type, :vat_account
6
+
7
+
8
+ def handle
9
+ Handle.new({:name => @name})
10
+ end
11
+
12
+
13
+ protected
14
+
15
+ def build_soap_data
16
+ data = ActiveSupport::OrderedHash.new
17
+
18
+ data['Handle'] = handle.to_hash
19
+ data['Name'] = handle.number
20
+ data['Number'] = number
21
+
22
+ return data
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,39 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+
5
+ # Represents a cash book in E-conomic.
6
+ #
7
+ # API documentation: http://www.e-conomic.com/apidocs/Documentation/T_Economic_Api_ICashBook.html
8
+ class CashBook < Entity
9
+ has_properties :name, :number
10
+
11
+ def handle
12
+ Handle.new({:number => @number})
13
+ end
14
+
15
+ def entries
16
+ CashBookEntryProxy.new(self)
17
+ end
18
+
19
+ # Books all entries in the cashbook. Returns book result.
20
+ def book
21
+ response = session.request(soap_action(:book)) do
22
+ soap.body = { "cashBookHandle" => handle.to_hash }
23
+ end
24
+ response[:number].to_i
25
+ end
26
+
27
+ protected
28
+
29
+ def build_soap_data
30
+ data = ActiveSupport::OrderedHash.new
31
+
32
+ data['Handle'] = handle.to_hash
33
+ data['Name'] = name
34
+ data['Number'] = number
35
+
36
+ return data
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,111 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+
5
+ # Represents a cash book in E-conomic.
6
+ #
7
+ # API documentation: http://www.e-conomic.com/apidocs/Documentation/T_Economic_Api_ICashBook.html
8
+ class CashBookEntry < Entity
9
+ has_properties :id1,
10
+ :id2,
11
+ :account_handle,
12
+ :amount,
13
+ :amount_default_currency,
14
+ :bank_payment_creditor_id,
15
+ :bank_payment_creditor_invoice_id,
16
+ :bank_payment_type_handle,
17
+ :capitalise_handle,
18
+ :cash_book_handle,
19
+ :contra_account_handle,
20
+ :contra_vat_account_handle,
21
+ :cost_type_handle,
22
+ :creditor_handle,
23
+ :creditor_invoice_number,
24
+ :currency_handle,
25
+ :date,
26
+ :debtor_handle,
27
+ :debtor_invoice_number,
28
+ :department_handle,
29
+ :distribution_key_handle,
30
+ :due_date,
31
+ :employee_handle,
32
+ :end_date,
33
+ :project_handle,
34
+ :start_date,
35
+ :text,
36
+ :cash_book_entry_type,
37
+ :vat_account_handle,
38
+ :voucher_number
39
+
40
+ def initialize_defaults
41
+ self.account_handle = nil
42
+ self.amount = 0
43
+ self.amount_default_currency = 0
44
+ self.bank_payment_creditor_id = 0
45
+ self.bank_payment_creditor_invoice_id = 0
46
+ self.bank_payment_type_handle = nil
47
+ self.capitalise_handle = nil
48
+ self.cash_book_handle = nil
49
+ self.contra_account_handle = nil
50
+ self.contra_vat_account_handle = nil
51
+ self.cost_type_handle = nil
52
+ self.creditor_handle = nil
53
+ self.creditor_invoice_number = nil
54
+ self.currency_handle = nil
55
+ self.date = Time.now
56
+ self.debtor_handle = nil
57
+ self.debtor_invoice_number = nil
58
+ self.department_handle = nil
59
+ self.distribution_key_handle = nil
60
+ self.due_date = nil
61
+ self.employee_handle = nil
62
+ self.end_date = nil
63
+ self.project_handle = nil
64
+ self.start_date = Time.now
65
+ self.text = ""
66
+ self.cash_book_entry_type = ""
67
+ self.vat_account_handle = nil
68
+ self.voucher_number = 0
69
+ end
70
+
71
+ def handle
72
+ Handle.new(:id1 => @id1, :id2 => @id2)
73
+ end
74
+
75
+ def build_soap_data
76
+ data = ActiveSupport::OrderedHash.new
77
+
78
+ data['Handle'] = handle.to_hash
79
+ data['Type'] = cash_book_entry_type unless cash_book_entry_type.blank?
80
+ data['CashBookHandle'] = { 'Number' => cash_book_handle[:number] } unless cash_book_handle.blank?
81
+ data['DebtorHandle'] = { 'Number' => debtor_handle[:number] } unless debtor_handle.blank?
82
+ data['CreditorHandle'] = { 'Number' => creditor_handle[:number] } unless creditor_handle.blank?
83
+ data['AccountHandle'] = { 'Number' => account_handle[:number] } unless account_handle.blank?
84
+ data['ContraAccountHandle'] = { 'Number' => contra_account_handle[:number] } unless contra_account_handle.blank?
85
+ data['Date'] = date
86
+ data['VoucherNumber'] = voucher_number
87
+ data['Text'] = text
88
+ data['AmountDefaultCurrency'] = amount_default_currency
89
+ data['CurrencyHandle'] = { 'Code' => currency_handle[:code] } unless currency_handle.blank?
90
+ data['Amount'] = amount
91
+ data['VatAccountHandle'] = { 'Number' => vat_account_handle[:number] } unless vat_account_handle.blank?
92
+ data['ContraVatAccountHandle'] = { 'Number' => contra_vat_account_handle[:number] } unless contra_vat_account_handle.blank?
93
+ data['DebtorInvoiceNumber'] = debtor_invoice_number unless debtor_invoice_number.blank?
94
+ data['CreditorInvoiceNumber'] = creditor_invoice_number unless creditor_invoice_number.blank?
95
+ data['DueDate'] = due_date
96
+ data['DepartmentHandle'] = { 'Number' => department_handle[:number] } unless department_handle.blank?
97
+ data['DistributionKeyHandle'] = { 'Number' => distribution_key_handle[:number] } unless distribution_key_handle.blank?
98
+ data['ProjectHandle'] = { 'Number' => project_handle[:number] } unless project_handle.blank?
99
+ data['CostTypeHandle'] = { 'Number' => cost_type_handle[:number] } unless cost_type_handle.blank?
100
+ data['BankPaymentTypeHandle'] = { 'Number' => bank_payment_type_handle[:number] } unless bank_payment_type_handle.blank?
101
+ data['BankPaymentCreditorId'] = bank_payment_creditor_id
102
+ data['BankPaymentCreditorInvoiceId'] = bank_payment_creditor_invoice_id
103
+ data['CapitaliseHandle'] = { 'Number' => capitalise_handle[:number] } unless capitalise_handle.blank?
104
+ data['StartDate'] = start_date
105
+ data['EndDate'] = end_date
106
+ data['EmployeeHandle'] = { 'Number' => employee_handle[:number] } unless employee_handle.blank?
107
+
108
+ return data
109
+ end
110
+ end
111
+ end
@@ -26,12 +26,40 @@ module Economic
26
26
  #
27
27
  # invoice.save
28
28
  class CurrentInvoice < Entity
29
- has_properties :id, :debtor_handle, :debtor_name, :debtor_address, :debtor_postal_code, :debtor_city, :debtor_country, :date, :term_of_payment_handle, :due_date, :currency_handle, :exchange_rate, :is_vat_included, :layout_handle, :delivery_date, :net_amount, :vat_amount, :gross_amount, :margin, :margin_as_percent
29
+ has_properties :id, :debtor_handle, :debtor_name, :debtor_address, :debtor_postal_code, :debtor_city, :debtor_country, :attention_handle, :date, :term_of_payment_handle, :due_date, :currency_handle, :exchange_rate, :is_vat_included, :layout_handle, :delivery_date, :net_amount, :vat_amount, :gross_amount, :margin, :margin_as_percent, :heading
30
30
 
31
31
  def initialize(properties = {})
32
32
  super
33
33
  end
34
34
 
35
+ def attention
36
+ return nil if attention_handle.blank?
37
+ @attention ||= session.contacts.find(attention_handle)
38
+ end
39
+
40
+ def attention=(contact)
41
+ self.attention_handle = contact.handle
42
+ @attention = contact
43
+ end
44
+
45
+ def attention_handle=(handle)
46
+ @attention = nil unless handle == @attention_handle
47
+ @attention_handle = handle
48
+ end
49
+
50
+ # Books a current invoice. An invoice number greater than all other invoice numbers will be
51
+ # assigned to the resulting Economic::Invoice.
52
+ #
53
+ # Returns the resulting Economic::Invoice object
54
+ def book
55
+ response = session.request soap_action(:book) do
56
+ soap.body = { "currentInvoiceHandle" => handle.to_hash }
57
+ end
58
+
59
+ # Find the created Invoice
60
+ session.invoices.find(response[:number])
61
+ end
62
+
35
63
  def debtor
36
64
  return nil if debtor_handle.blank?
37
65
  @debtor ||= session.debtors.find(debtor_handle)
@@ -66,6 +94,7 @@ module Economic
66
94
  self.is_vat_included = nil
67
95
  self.layout_handle = nil
68
96
  self.delivery_date = nil
97
+ self.heading = nil
69
98
  self.net_amount = 0
70
99
  self.vat_amount = 0
71
100
  self.gross_amount = 0
@@ -85,6 +114,7 @@ module Economic
85
114
  data['DebtorPostalCode'] = debtor_postal_code unless debtor_postal_code.blank?
86
115
  data['DebtorCity'] = debtor_city unless debtor_city.blank?
87
116
  data['DebtorCountry'] = debtor_country unless debtor_country.blank?
117
+ data['AttentionHandle'] = { 'Id' => attention_handle[:id] } unless attention_handle.blank?
88
118
  data['Date'] = date.iso8601 unless date.blank?
89
119
  data['TermOfPaymentHandle'] = { 'Id' => term_of_payment_handle[:id] } unless term_of_payment_handle.blank?
90
120
  data['DueDate'] = (due_date.blank? ? nil : due_date.iso8601)
@@ -93,6 +123,7 @@ module Economic
93
123
  data['IsVatIncluded'] = is_vat_included
94
124
  data['LayoutHandle'] = { 'Id' => layout_handle[:id] } unless layout_handle.blank?
95
125
  data['DeliveryDate'] = delivery_date ? delivery_date.iso8601 : nil
126
+ data['Heading'] = heading unless heading.blank?
96
127
  data['NetAmount'] = net_amount
97
128
  data['VatAmount'] = vat_amount
98
129
  data['GrossAmount'] = gross_amount
@@ -114,4 +145,4 @@ module Economic
114
145
  end
115
146
  end
116
147
 
117
- end
148
+ end
@@ -68,4 +68,4 @@ module Economic
68
68
  end
69
69
  end
70
70
 
71
- end
71
+ end
@@ -31,11 +31,12 @@ module Economic
31
31
  Handle.new({:number => @number})
32
32
  end
33
33
 
34
+ # Returns the Debtors contacts
34
35
  def contacts
35
36
  @contacts ||= DebtorContactProxy.new(self)
36
37
  end
37
38
 
38
- # Provides access to the current invoices - ie invoices that haven't yet been booked
39
+ # Provides access to the current invoices for Debtor - ie invoices that haven't yet been booked
39
40
  def current_invoices
40
41
  @current_invoices ||= CurrentInvoiceProxy.new(self)
41
42
  end
@@ -22,7 +22,7 @@ module Economic
22
22
 
23
23
  def debtor
24
24
  return nil if debtor_handle.blank?
25
- @debtor ||= session.debtors.find(debtor_handle)
25
+ @debtor ||= session.debtors.find(debtor_handle[:number])
26
26
  end
27
27
 
28
28
  def debtor=(debtor)
@@ -0,0 +1,66 @@
1
+ class Economic::Entity
2
+ class Handle
3
+ attr_accessor :id, :id1, :id2, :number
4
+
5
+ def initialize(hash)
6
+ verify_sanity_of_arguments!(hash)
7
+ hash = prepare_hash_argument(hash) unless hash.is_a?(self.class)
8
+
9
+ @id = hash[:id].to_i if hash[:id]
10
+ @id1 = hash[:id1].to_i if hash[:id1]
11
+ @id2 = hash[:id2].to_i if hash[:id2]
12
+ @number = hash[:number].to_i if hash[:number]
13
+ end
14
+
15
+ def to_hash
16
+ hash = {}
17
+ hash['Id'] = id unless id.blank?
18
+ hash['Id1'] = id1 unless id1.blank?
19
+ hash['Id2'] = id2 unless id2.blank?
20
+ hash['Number'] = number unless number.blank?
21
+ hash
22
+ end
23
+
24
+ def [](key)
25
+ {:id => @id, :id1 => @id1, :id2 => @id2, :number => @number}[key]
26
+ end
27
+
28
+ def ==(other)
29
+ return false if other.nil?
30
+ return false unless other.respond_to?(:id) && other.respond_to?(:number)
31
+ self.id == other.id && self.number == other.number
32
+ end
33
+
34
+ private
35
+
36
+ # Raises exceptions if hash doesn't contain values we can use to construct a new handle
37
+ def verify_sanity_of_arguments!(hash)
38
+ return if hash.is_a?(self.class)
39
+
40
+ if hash.nil? || (!hash.respond_to?(:to_i) && (!hash.respond_to?(:keys) && !hash.respond_to?(:values)))
41
+ raise ArgumentError.new("Expected Number, Hash or Economic::Entity::Handle - got #{hash.inspect}")
42
+ end
43
+
44
+ if hash.respond_to?(:keys)
45
+ unknown_keys = hash.keys - [:id, :id1, :id2, :number, "Number", "Id", "Id1", "Id2"]
46
+ raise ArgumentError.new("Unknown keys in handle: #{unknown_keys.inspect}") unless unknown_keys.empty?
47
+
48
+ not_to_iable = hash.select { |k, v| !v.respond_to?(:to_i) }
49
+ raise ArgumentError.new("All values must respond to to_i. #{not_to_iable.inspect} didn't") unless not_to_iable.empty?
50
+ end
51
+ end
52
+
53
+ # Examples
54
+ #
55
+ # prepare_hash_argument(12) #=> {:id => 12}
56
+ # prepare_hash_argument(:id => 12) #=> {:id => 12}
57
+ # prepare_hash_argument('Id' => 12) #=> {:id => 12}
58
+ # prepare_hash_argument('Id' => 12, 'Number' => 13) #=> {:id => 12, :number => 13}
59
+ def prepare_hash_argument(hash)
60
+ hash = {:id => hash.to_i} if hash.respond_to?(:to_i) unless hash.blank?
61
+ hash[:id] ||= hash['Id']
62
+ hash[:number] ||= hash['Number']
63
+ hash
64
+ end
65
+ end
66
+ end
@@ -1,31 +1,7 @@
1
+ require 'economic/entity/handle'
2
+
1
3
  module Economic
2
4
  class Entity
3
- class Handle
4
- attr_accessor :id, :number
5
-
6
- def initialize(hash)
7
- @id = hash[:id]
8
- @number = hash[:number]
9
- end
10
-
11
- def to_hash
12
- hash = {}
13
- hash['Id'] = id unless id.blank?
14
- hash['Number'] = number unless number.blank?
15
- hash
16
- end
17
-
18
- def [](key)
19
- {:id => @id, :number => @number}[key]
20
- end
21
-
22
- def ==(other)
23
- return false if other.nil?
24
- return false unless other.respond_to?(:id) && other.respond_to?(:number)
25
- self.id == other.id && self.number == other.number
26
- end
27
- end
28
-
29
5
  # Internal accessors
30
6
  attr_accessor :persisted, :session, :partial
31
7
 
@@ -71,6 +47,17 @@ module Economic
71
47
  class_name_without_modules = class_name.split('::').last
72
48
  "#{class_name_without_modules.snakecase}_#{action.to_s.snakecase}".intern
73
49
  end
50
+
51
+ # Returns a symbol based on the name of the entity. Used to request and read data responses.
52
+ #
53
+ # Entity.key #=> :entity
54
+ # CurrentInvoice.key #=> :current_invoice
55
+ def key
56
+ key = self.name
57
+ key = Economic::Support::String.demodulize(key)
58
+ key = Economic::Support::String.underscore(key)
59
+ key.intern
60
+ end
74
61
  end
75
62
 
76
63
  def handle
@@ -90,12 +77,12 @@ module Economic
90
77
 
91
78
  # Updates Entity with its data from the API
92
79
  def get_data
93
- response = proxy.get_data(number)
80
+ response = proxy.get_data(handle)
94
81
  self.update_properties(response)
95
82
  self.partial = false
96
83
  self.persisted = true
97
84
  end
98
-
85
+
99
86
  # Returns the number of Entity. This does not trigger a load from the API even if Entity is partial
100
87
  def number
101
88
  @number
@@ -106,13 +93,6 @@ module Economic
106
93
  @id
107
94
  end
108
95
 
109
- def handle
110
- handle = {}
111
- handle[:id] = id unless id.blank?
112
- handle[:number] = number unless number.blank?
113
- handle
114
- end
115
-
116
96
  # Returns true if CurrentInvoiceLine has been persisted in e-conomic
117
97
  def persisted?
118
98
  !!@persisted
@@ -141,6 +121,19 @@ module Economic
141
121
  create_or_update
142
122
  end
143
123
 
124
+ # Deletes entity permanently from E-conomic.
125
+ def destroy
126
+ handleKey = "#{camel_back(class_name)}Handle"
127
+ response = session.request soap_action(:delete) do
128
+ soap.body = { handleKey => handle.to_hash }
129
+ end
130
+
131
+ @persisted = false
132
+ @partial = true
133
+
134
+ response
135
+ end
136
+
144
137
  # Updates properties of Entity with the values from hash
145
138
  def update_properties(hash)
146
139
  hash.each do |key, value|
@@ -169,6 +162,8 @@ module Economic
169
162
  if response
170
163
  @number = response[:number]
171
164
  @id = response[:id]
165
+ @id1 = response[:id1]
166
+ @id2 = response[:id2]
172
167
  end
173
168
 
174
169
  @persisted = true
@@ -196,6 +191,14 @@ module Economic
196
191
  self.class.soap_action(action)
197
192
  end
198
193
 
194
+ def class_name
195
+ self.class.to_s.split("::").last
196
+ end
197
+
198
+ def camel_back(name)
199
+ name[0,1].downcase + name[1..-1]
200
+ end
201
+
199
202
  end
200
203
 
201
- end
204
+ end
@@ -0,0 +1,58 @@
1
+ require 'economic/entity'
2
+
3
+ module Economic
4
+ class Invoice < Entity
5
+ has_properties :number, :net_amount, :vat_amount, :due_date, :debtor_handle, :debtor_name, :debtor_name, :debtor_address, :debtor_postal_code, :debtor_city, :debtor_country, :debtor_ean, :attention_handle, :heading
6
+
7
+ def attention
8
+ return nil if attention_handle.blank?
9
+ @attention ||= session.contacts.find(attention_handle)
10
+ end
11
+
12
+ def attention=(contact)
13
+ self.attention_handle = contact.handle
14
+ @attention = contact
15
+ end
16
+
17
+ def attention_handle=(handle)
18
+ @attention = nil unless handle == @attention_handle
19
+ @attention_handle = handle
20
+ end
21
+
22
+ def debtor
23
+ return nil if debtor_handle.blank?
24
+ @debtor ||= session.debtors.find(debtor_handle)
25
+ end
26
+
27
+ def debtor=(debtor)
28
+ self.debtor_handle = debtor.handle
29
+ @debtor = debtor
30
+ end
31
+
32
+ def debtor_handle=(handle)
33
+ @debtor = nil unless handle == @debtor_handle
34
+ @debtor_handle = handle
35
+ end
36
+
37
+ def remainder
38
+ session.request(soap_action(:get_remainder)) do
39
+ soap.body = { "invoiceHandle" => handle.to_hash }
40
+ end
41
+ end
42
+
43
+ # Returns the PDF version of Invoice as a String.
44
+ #
45
+ # To get it as a file you can do:
46
+ #
47
+ # File.open("invoice.pdf", 'wb') do |file|
48
+ # file << invoice.pdf
49
+ # end
50
+ def pdf
51
+ response = session.request soap_action(:get_pdf) do
52
+ soap.body = { "invoiceHandle" => handle.to_hash }
53
+ end
54
+
55
+ Base64.decode64(response)
56
+ end
57
+ end
58
+ end