klarna 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.gitignore +9 -0
  2. data/.travis.yml +13 -0
  3. data/Gemfile +14 -0
  4. data/Guardfile +16 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.textile +139 -0
  7. data/Rakefile +22 -0
  8. data/TODO +30 -0
  9. data/examples/Gemfile +8 -0
  10. data/examples/config/initializer.rb +15 -0
  11. data/examples/console.rb +71 -0
  12. data/examples/public/images/klarna.png +0 -0
  13. data/examples/public/images/ruby.png +0 -0
  14. data/examples/views/_address.haml +22 -0
  15. data/examples/views/_articles.haml +21 -0
  16. data/examples/views/checkout_page_example.haml +2 -0
  17. data/examples/views/essential/add_transaction/_form.haml +32 -0
  18. data/examples/views/essential/add_transaction/result.haml +7 -0
  19. data/examples/views/essential/calculate_monthly_cost/_form.haml +16 -0
  20. data/examples/views/essential/calculate_monthly_cost/result.haml +7 -0
  21. data/examples/views/essential/get_addresses/_form.haml +9 -0
  22. data/examples/views/essential/get_addresses/result.haml +8 -0
  23. data/examples/views/index.haml +296 -0
  24. data/examples/views/layout.haml +48 -0
  25. data/examples/views/payment_terms_example.haml +102 -0
  26. data/examples/views/product_page_example.haml +2 -0
  27. data/examples/views/reservation/activate_reservation/_form.haml +54 -0
  28. data/examples/views/reservation/activate_reservation/result.haml +7 -0
  29. data/examples/views/reservation/cancel_reservation/_form.haml +8 -0
  30. data/examples/views/reservation/cancel_reservation/result.haml +7 -0
  31. data/examples/views/reservation/change_reservation/_form.haml +10 -0
  32. data/examples/views/reservation/change_reservation/result.haml +7 -0
  33. data/examples/views/reservation/reserve_amount/_form.haml +58 -0
  34. data/examples/views/reservation/reserve_amount/result.haml +7 -0
  35. data/examples/views/reservation/reserve_ocr_numbers/_form.haml +8 -0
  36. data/examples/views/reservation/reserve_ocr_numbers/result.haml +7 -0
  37. data/examples/views/reservation/split_reservation/_form.haml +14 -0
  38. data/examples/views/reservation/split_reservation/result.haml +7 -0
  39. data/examples/views/special/get_pclasses/_form.haml +8 -0
  40. data/examples/views/special/get_pclasses/result.haml +7 -0
  41. data/examples/views/special/invoice_address/_form.haml +8 -0
  42. data/examples/views/special/invoice_address/result.haml +7 -0
  43. data/examples/views/special/invoice_amount/_form.haml +8 -0
  44. data/examples/views/special/invoice_amount/result.haml +7 -0
  45. data/examples/views/special/is_invoice_paid/_form.haml +8 -0
  46. data/examples/views/special/is_invoice_paid/result.haml +7 -0
  47. data/examples/views/special/update_charge_amount/_form.haml +15 -0
  48. data/examples/views/special/update_charge_amount/result.haml +7 -0
  49. data/examples/views/special/update_goods_quantity/_form.haml +17 -0
  50. data/examples/views/special/update_goods_quantity/result.haml +7 -0
  51. data/examples/views/special/update_order_number/_form.haml +10 -0
  52. data/examples/views/special/update_order_number/result.haml +7 -0
  53. data/examples/views/useful/activate_invoice/_form.haml +9 -0
  54. data/examples/views/useful/activate_invoice/result.haml +7 -0
  55. data/examples/views/useful/credit_invoice/_form.haml +11 -0
  56. data/examples/views/useful/credit_invoice/result.haml +7 -0
  57. data/examples/views/useful/delete_invoice/_form.haml +9 -0
  58. data/examples/views/useful/delete_invoice/result.haml +7 -0
  59. data/examples/views/useful/email_invoice/_form.haml +9 -0
  60. data/examples/views/useful/email_invoice/result.haml +7 -0
  61. data/examples/views/useful/has_account/_form.haml +9 -0
  62. data/examples/views/useful/has_account/result.haml +7 -0
  63. data/examples/views/useful/return_amount/_form.haml +15 -0
  64. data/examples/views/useful/return_amount/result.haml +7 -0
  65. data/examples/views/useful/send_invoice/_form.haml +9 -0
  66. data/examples/views/useful/send_invoice/result.haml +7 -0
  67. data/examples/web.rb +349 -0
  68. data/klarna.gemspec +34 -0
  69. data/lib/klarna.rb +175 -0
  70. data/lib/klarna/api.rb +170 -0
  71. data/lib/klarna/api/client.rb +128 -0
  72. data/lib/klarna/api/constants.rb +638 -0
  73. data/lib/klarna/api/errors.rb +154 -0
  74. data/lib/klarna/api/methods.rb +16 -0
  75. data/lib/klarna/api/methods/cost_calculations.rb +134 -0
  76. data/lib/klarna/api/methods/invoicing.rb +304 -0
  77. data/lib/klarna/api/methods/reservation.rb +149 -0
  78. data/lib/klarna/api/methods/standard.rb +123 -0
  79. data/lib/klarna/version.rb +5 -0
  80. data/test/fixtures/api/companies.yml +97 -0
  81. data/test/fixtures/api/pclasses.yml +37 -0
  82. data/test/fixtures/api/persons.yml +144 -0
  83. data/test/fixtures/api/stores.yml +6 -0
  84. data/test/fixtures/klarna.yml +10 -0
  85. data/test/klarna/api/client_test.rb +272 -0
  86. data/test/klarna/api/errors_test.rb +46 -0
  87. data/test/klarna/api/methods/cost_calculations_test.rb +78 -0
  88. data/test/klarna/api/methods/invoicing_test.rb +409 -0
  89. data/test/klarna/api/methods/reservation_test.rb +66 -0
  90. data/test/klarna/api/methods/standard_test.rb +244 -0
  91. data/test/klarna/api_test.rb +137 -0
  92. data/test/klarna_test.rb +204 -0
  93. data/test/support/assertions_helper.rb +40 -0
  94. data/test/test_helper.rb +55 -0
  95. metadata +312 -0
@@ -0,0 +1,154 @@
1
+ # encoding: utf-8
2
+ require 'xmlrpc/client'
3
+
4
+ module Klarna
5
+ module API
6
+ module Errors
7
+
8
+ ERROR_CODES = {
9
+ 1103 => :estore_overrun,
10
+ 1104 => :estore_blacklisted,
11
+ 1999 => :misc_estore_error,
12
+ 2101 => :credit,
13
+ 2102 => :amount,
14
+ 2103 => :customer_credit_overrun,
15
+ 2104 => :blocked,
16
+ 2105 => :unpaid_bills,
17
+ 2106 => :customer_not_accepted,
18
+ 2107 => :customer_blacklisted,
19
+ 2201 => :pno,
20
+ 2202 => :invalid_pno,
21
+ 2203 => :pno_not_real_person,
22
+ 2204 => :dead,
23
+ 2205 => :under_aged,
24
+ 2206 => :customer_not_18,
25
+ 2301 => :no_such_person,
26
+ 2302 => :customer_missing,
27
+ 2303 => :no_such_customer,
28
+ 2304 => :unknown_customer,
29
+ 2305 => :bad_customer_password,
30
+ 2401 => :tno_not_found,
31
+ 2402 => :pin_error,
32
+ 2403 => :wrong_pin,
33
+ 2404 => :no_pin,
34
+ 2405 => :orgno,
35
+ 2999 => :misc_customer_error,
36
+ 3101 => :foreign_addr,
37
+ 3102 => :bad_addr,
38
+ 3103 => :bad_address,
39
+ 3104 => :postno,
40
+ 3105 => :bad_postno,
41
+ 3106 => :bad_name,
42
+ 3107 => :address,
43
+ 3108 => :no_address,
44
+ 3201 => :cellno,
45
+ 3202 => :telno,
46
+ 3203 => :email,
47
+ 3204 => :country,
48
+ 3205 => :city,
49
+ 3206 => :postno,
50
+ 3207 => :street,
51
+ 3208 => :client_ip,
52
+ 3209 => :proto_vsn,
53
+ 3210 => :goods_list,
54
+ 3211 => :artnos,
55
+ 3301 => :bad_name_and_address,
56
+ 3302 => :bad_last_name,
57
+ 3303 => :bad_first_name,
58
+ 3304 => :bad_first_name_and_last_name,
59
+ 3999 => :misc_submission_error,
60
+ 6101 => :orgno_pclass_not_allowed,
61
+ 6102 => :sum_low_for_pclass,
62
+ 6103 => :unknown_pclass,
63
+ 6104 => :not_annuity_pclass,
64
+ 6999 => :misc_pclass_error,
65
+ 7101 => :no_such_subscription,
66
+ 7102 => :not_unique_subscription_no,
67
+ 7103 => :terminated,
68
+ 7104 => :already_set,
69
+ 7105 => :need_email_addr,
70
+ 7999 => :misc_subscription_error,
71
+ 8101 => :unknown_invoice,
72
+ 8102 => :negative_invoice,
73
+ 8103 => :invoice_not_active,
74
+ 8104 => :invoice_bad_status,
75
+ 8105 => :invoice_is_passive,
76
+ 8106 => :invoice_is_archived,
77
+ 8107 => :invoice_is_suspect,
78
+ 8108 => :invoice_is_frozen,
79
+ 8109 => :invoice_is_pre_pay,
80
+ 8110 => :invoice_stale,
81
+ 8111 => :invoice_not_passive_or_frozen,
82
+ 8112 => :invoice_in_test_mode,
83
+ 8113 => :invoice_not_passive,
84
+ 8114 => :invno,
85
+ 8999 => :misc_invoice_error,
86
+ 9101 => :cno_already_in_use,
87
+ 9102 => :unknown_csid,
88
+ 9103 => :not_allowed_operation,
89
+ 9104 => :ip_from_wrong_country,
90
+ 9105 => :bad_type,
91
+ 9106 => :unknown_type,
92
+ 9107 => :bad_artnolist,
93
+ 9108 => :unknown_artno,
94
+ 9109 => :rno,
95
+ 9110 => :split,
96
+ 9111 => :bad_order_no,
97
+ 9112 => :bad_ocr,
98
+ 9113 => :unknown_estore,
99
+ 9114 => :invalid_estore_secret,
100
+ 9115 => :bad_module_vsn,
101
+ 9116 => :pno_encoding,
102
+ 9117 => :currency,
103
+ 9118 => :currency_country_pnoencoding,
104
+ 9119 => :timeout
105
+ }.freeze
106
+
107
+ class KlarnaStandardError < ::StandardError
108
+ def initialize(message)
109
+ ::Klarna.log message, :error
110
+ super(message)
111
+ end
112
+ end
113
+
114
+ class KlarnaArgumentError < ::ArgumentError
115
+ def initialize(message)
116
+ ::Klarna.log message, :error
117
+ super(message)
118
+ end
119
+ end
120
+
121
+ class KlarnaCredentialsError < KlarnaStandardError
122
+ end
123
+
124
+ class KlarnaServiceError < ::XMLRPC::FaultException
125
+ alias :error_code :faultCode
126
+ alias :error_message :faultString
127
+
128
+ def initialize(error_code, error_key)
129
+ localized_error_message = ::Klarna::API::Errors.error_message(error_key)
130
+ message = ::Klarna.mode == :test ? "#{error_key} (#{[error_code, ERROR_CODES[error_code]].compact.join(' - ')})" : localized_error_message
131
+ ::Klarna.log message, :error
132
+ super(error_code, message)
133
+ end
134
+
135
+ def to_h
136
+ {:error_code => self.error_code, :error_message => self.error_message}
137
+ end
138
+ end
139
+
140
+ class << self
141
+
142
+ # Lookup localized string value for a specified error/exception code or key.
143
+ #
144
+ def error_message(id_or_key)
145
+ key = id_or_key.is_a?(Fixnum) ? ERROR_CODES[id_or_key] : id_or_key
146
+ key
147
+ end
148
+ alias :localized_error_message :error_message
149
+
150
+ end
151
+
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ require 'klarna/api/methods/standard'
3
+ require 'klarna/api/methods/invoicing'
4
+ require 'klarna/api/methods/reservation'
5
+ require 'klarna/api/methods/cost_calculations'
6
+
7
+ module Klarna
8
+ module API
9
+ module Methods
10
+ include ::Klarna::API::Methods::Standard
11
+ include ::Klarna::API::Methods::Invoicing
12
+ include ::Klarna::API::Methods::Reservation
13
+ include ::Klarna::API::Methods::CostCalculations
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,134 @@
1
+ # encoding: utf-8
2
+
3
+ module Klarna
4
+ module API
5
+ module Methods
6
+ module CostCalculations
7
+
8
+ # Purpose: Obtain pclass values from Klarna.
9
+ #
10
+ # == Note:
11
+ #
12
+ # This function is only to be used to obtain pclass values for stores ONE TIME ONLY.
13
+ # It is not allowed to use this function for continuous calculation of monthly costs or
14
+ # with every purchase in the checkout. The pclass values do NOT change.
15
+ #
16
+ def fetch_pclasses(currency_code)
17
+ # params = [
18
+ # self.store_id,
19
+ # currency_code,
20
+ # self.digest(currency_code)
21
+ # ]
22
+ # self.call(:fetch_pclasses, *params)
23
+ raise NotImplementedError
24
+ end
25
+
26
+ # Calculate monthly cost "in the most proper way".
27
+ #
28
+ def calculate_monthly_cost(sum, currency, pclass_id, flags = nil)
29
+ # # TODO: OpenStruct this
30
+ # pclasses = ::Klarna.store_pclasses[currency.to_s.underscore]
31
+ # month_count = pclasses[pclass_id][:months]
32
+ # monthly_fee = pclasses[pclass_id][:invoice_fee]
33
+ # start_fee = pclasses[pclass_id][:start_fee]
34
+ # rate = pclasses[pclass_id][:interest_rate]
35
+ # type = pclasses[pclass_id][:type] # QUESTION: Where do I get this from - not in API-call.
36
+ #
37
+ # # TODO: Call Klarna and ask where I get "type" from - not with pclasses.
38
+ # case type
39
+ # when ::Klarna::API::PClassFlags::ANNUITY
40
+ # self.periodic_cost(sum, month_count, monthly_fee, start_fee, rate, currency, flags)
41
+ # when ::Klarna::API::PClassFlags::DIVISOR
42
+ # self.monthly_cost(sum, month_count, monthly_fee, start_fee, rate, currency, flags)
43
+ # else
44
+ # raise InvalidArgumentError, "Invalid Klarna campaign/pclass type: #{type.inspect}"
45
+ # end
46
+ raise NotImplementedError
47
+ end
48
+
49
+ # Calculate the monthly cost for goods which can be paid for by part payment.
50
+ #
51
+ def periodic_cost(sum, month_count, monthly_fee, start_fee, rate, currency, flags = nil)
52
+ # daily_rate = self.calculate_daily_rate(rate)
53
+ # monthly_payment = self.calculate_monthly_payment(sum + start_fee, daily_rate, month_count)
54
+ # monthly_cost = monthly_payment + monthly_fee
55
+ # monthly_cost.round
56
+ raise NotImplementedError
57
+ end
58
+
59
+ # Calculate the monthly cost for account purchases.
60
+ #
61
+ def monthly_cost(sum, month_count, monthly_fee, start_fee, rate, currency, flags = nil)
62
+ # interest_cost = self.calculate_interest_cost(sum, rate)
63
+ # period_cost = (sum + interest_cost) / month_count
64
+ # flags ||= ::Klarna::API::MonthlyCostFlags::LIMIT
65
+ #
66
+ # # TODO: Remove this line - after debugging.
67
+ # ::Klarna.log [::Klarna::API::AVERAGE_INTEREST_PERIOD, calc_rate, interest_cost, period_cost].join(', ')
68
+ #
69
+ # monthly_cost = case flags
70
+ # when ::Klarna::API::MonthlyCostFlags::LIMIT
71
+ # period_cost
72
+ # when ::Klarna::API::MonthlyCostFlags::ACTUAL
73
+ # begin
74
+ # lowest_monthly_payment = ::Klarna::API::LOWEST_PAYMENT_BY_CURRENCY[currency]
75
+ # rescue
76
+ # raise ::Klarna::API::KlarnaStandardError,
77
+ # "No such currency: #{currency.inspect}. Valid currencies: SEK:1, NOK:2, EUR:3, DKK:4"
78
+ # end
79
+ # period_cost += monthly_fee
80
+ # (period_cost < lowest_monthly_payment) ? lowest_monthly_payment : period_cost
81
+ # else
82
+ # raise ::Klarna::API::KlarnaStandardError,
83
+ # "Invalid flag: #{flags.inspect}. Valid flags: LIMIT:0, ACTUAL:1"
84
+ # end
85
+ # ::Klarna.log_result("Calculation: monthly_cost = %s") do
86
+ # self.round_up(monthly_cost, currency)
87
+ # end
88
+ raise NotImplementedError
89
+ end
90
+
91
+ protected
92
+
93
+ def calculate_interest_cost(sum, rate)
94
+ # rate *= 100.0 if rate < 100.0
95
+ # calc_rate = (rate / 10000)
96
+ # (::Klarna::API::AVERAGE_INTEREST_PERIOD / ::Klarna::API::DAYS_IN_A_YEAR) * calc_rate * sum
97
+ raise NotImplementedError
98
+ end
99
+
100
+ def calculate_monthly_payment(sum, daily_rate, month_count)
101
+ # sum = sum.to_double
102
+ # total_dates = (month_count - 1) * 30
103
+ # denominator = self.get_denominator(dailyrate, total_dates)
104
+ # total_dates += 60
105
+ # (dailyrate ** totdates) * sum / denominator
106
+ raise NotImplementedError
107
+ end
108
+
109
+ def calculate_daily_rate(rate)
110
+ # ((rate.to_decimal / 10000.0) + 1.0) ** (1 / ::Klarna::API::DAYS_IN_A_YEAR)
111
+ raise NotImplementedError
112
+ end
113
+
114
+ def get_denominator(daily_rate, total_dates)
115
+ # start_dates = 0.0
116
+ # sum = 1.0
117
+ # while total_dates > start_dates
118
+ # start_dates += 30
119
+ # sum += total_dates ** start_dates
120
+ # end
121
+ # sum
122
+ raise NotImplementedError
123
+ end
124
+
125
+ def round_up(amount, currency)
126
+ # divisor = currency == ::Klarna::API::Currencies::EUR ? 10.0 : 100.0
127
+ # (((divisor / 2) + amount) / divisor) #.round
128
+ raise NotImplementedError
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,304 @@
1
+ # encoding: utf-8
2
+
3
+ module Klarna
4
+ module API
5
+ module Methods
6
+ module Invoicing
7
+
8
+ # == TODO:
9
+ #
10
+ # * #total_credit_purchase_cost
11
+ #
12
+
13
+ # Create an invoice.
14
+ #
15
+ def add_invoice(store_user_id, order_id, articles, shipping_fee,
16
+ handling_fee, shipment_type, pno, first_name, last_name, address, client_ip,
17
+ currency, country, language, pno_encoding, pclass = nil, annual_salary = nil,
18
+ password = nil, ready_date = nil, comment = nil, rand_string = nil, new_password = nil, flags = nil)
19
+ shipment_type = ::Klarna::API.id_for(:shipment_type, shipment_type)
20
+ currency = ::Klarna::API.id_for(:currency, currency)
21
+ country = ::Klarna::API.id_for(:country, country)
22
+ language = ::Klarna::API.id_for(:language, language)
23
+ pno_encoding = ::Klarna::API.id_for(:pno_format, pno_encoding)
24
+ pclass = pclass ? ::Klarna::API.id_for(:pclass, pclass) : -1
25
+ flags = ::Klarna::API.parse_flags(:INVOICE, flags)
26
+ articles = Array.wrap(articles).compact
27
+
28
+ params = [
29
+ self.store_id,
30
+ store_user_id,
31
+ self.digest(articles.collect { |g| g[:goods][:title] }, :store_id => false),
32
+ order_id,
33
+ articles,
34
+ shipping_fee,
35
+ shipment_type,
36
+ handling_fee,
37
+ pno,
38
+ first_name,
39
+ last_name,
40
+ address,
41
+ password.to_s,
42
+ client_ip.to_s,
43
+ new_password.to_s,
44
+ flags.to_i,
45
+ comment.to_s,
46
+ ready_date.to_s,
47
+ rand_string.to_s,
48
+ currency,
49
+ country,
50
+ language,
51
+ pno_encoding,
52
+ pclass,
53
+ annual_salary.to_i
54
+ ]
55
+
56
+ self.call(:add_invoice, *params)
57
+ end
58
+ alias :add_transaction :add_invoice
59
+
60
+ # Activate a passive invoice - optionally only partly.
61
+ #
62
+ # == Note:
63
+ #
64
+ # This function call cannot activate an invoice created in test mode. It is however possible
65
+ # to manually activate such an invoice.
66
+ #
67
+ # When partially activating an invoice only the articles and quantities specified by
68
+ # you will be activated. A passive invoice is created containing the articles on the
69
+ # original invoice not activated.
70
+ #
71
+ def activate_invoice(invoice_no, articles = nil)
72
+ # TODO: Parse/Validate invoice_no as :integer
73
+ # TODO: Parse/Valdiate articles as array of articles
74
+ articles = Array.wrap(articles).compact
75
+
76
+ params = [
77
+ self.store_id,
78
+ invoice_no
79
+ ]
80
+
81
+ # Only partly?
82
+ if articles.present?
83
+ params << articles
84
+ params << self.digest(invoice_no, articles.collect { |a| [a[:goods][:artno], a[:qty]].join(':') }.join(':'))
85
+ method = :activate_part
86
+ else
87
+ params << self.digest(invoice_no)
88
+ method = :activate_invoice
89
+ end
90
+
91
+ self.call(method, *params)
92
+ end
93
+ alias :activate_part :activate_invoice
94
+
95
+ # Delete a passive invoice.
96
+ #
97
+ def delete_invoice(invoice_no)
98
+ # TODO: Parse/Validate invoice_no as :integer
99
+
100
+ params = [
101
+ self.store_id,
102
+ invoice_no,
103
+ self.digest(invoice_no)
104
+ ]
105
+
106
+ self.call(:delete_invoice, *params)
107
+ end
108
+
109
+ # Give discounts for invoices.
110
+ #
111
+ def return_amount(invoice_no, amount, vat)
112
+ params = [
113
+ self.store_id,
114
+ invoice_no,
115
+ amount,
116
+ vat,
117
+ self.digest(invoice_no)
118
+ ]
119
+ self.call(:return_amount, *params) # raise NotImplementedError
120
+ end
121
+
122
+ # Return a invoice - optionally only partly.
123
+ #
124
+ def credit_invoice(invoice_no, credit_id, articles = nil)
125
+ articles = Array.wrap(articles).compact
126
+
127
+ params = [
128
+ self.store_id,
129
+ invoice_no,
130
+ credit_id,
131
+ ]
132
+
133
+ if articles.present? # Only partly?
134
+ params << articles
135
+ params << self.digest(invoice_no, articles.collect { |a| [a[:goods][:artno], a[:qty]].join(':') }.join(':'))
136
+ method = :credit_part
137
+ else
138
+ params << self.digest(invoice_no)
139
+ method = :credit_invoice
140
+ end
141
+
142
+ self.call(method, *params)
143
+ end
144
+
145
+ # Send an active invoice to the customer via e-mail.
146
+ #
147
+ # == Note:
148
+ #
149
+ # Regular postal service is used if the customer lacks an e-mail address.
150
+ #
151
+ def email_invoice(invoice_no)
152
+ # TODO: Parse/Validate invoice_no as integer
153
+
154
+ params = [
155
+ self.store_id,
156
+ invoice_no,
157
+ self.digest(invoice_no)
158
+ ]
159
+
160
+ self.call(:email_invoice, *params)
161
+ end
162
+
163
+ # Request a postal send-out of an active invoice to a customer by Klarna.
164
+ #
165
+ def send_invoice(invoice_no)
166
+ # TODO: Parse/Validate invoice_no as integer
167
+
168
+ params = [
169
+ self.store_id,
170
+ invoice_no,
171
+ self.digest(invoice_no)
172
+ ]
173
+
174
+ self.call(:send_invoice, *params)
175
+ end
176
+
177
+ # Create quantity and article number (i.e. the +articles+ argument for the
178
+ # +activate_part+ and +credit_part+ function).
179
+ #
180
+ def make_article(quantity, article_no)
181
+ quantity = quantity.to_i
182
+ article_no = article_no.to_s
183
+ [quantity, article_no]
184
+ end
185
+
186
+ # Change the quantity of a specific item in a passive invoice.
187
+ #
188
+ def update_goods_quantity(invoice_no, article_no, new_quantity)
189
+ # TODO: Parse/Validate invoice_no as integer
190
+ # TODO: Parse/Validate article_no as string
191
+ # TODO: Parse/Validate new_quantity as integer
192
+
193
+ params = [
194
+ self.store_id,
195
+ self.digest(invoice_no, article_no, new_quantity, :store_id => false),
196
+ invoice_no,
197
+ article_no,
198
+ new_quantity
199
+ ]
200
+
201
+ self.call(:update_goods_qty, *params)
202
+ end
203
+
204
+ # Change the amount of a fee (for example the invoice fee) in a passive invoice.
205
+ #
206
+ def update_charge_amount(invoice_no, charge_type, new_amount)
207
+ # TODO: Parse/Validate invoice_no as integer
208
+ # TODO: Parse/Validate charge_type as integer/charge-type
209
+ # TODO: Parse/Validate new_amount as integer (or parse from decimal)
210
+
211
+ params = [
212
+ self.store_id,
213
+ self.digest(invoice_no, charge_type, new_amount),
214
+ invoice_no,
215
+ charge_type,
216
+ new_amount
217
+ ]
218
+
219
+ self.call(:update_charge_amount, *params)
220
+ end
221
+
222
+ # Change the store’s order number for a specific invoice.
223
+ #
224
+ def update_order_no(invoice_no, new_order_no)
225
+ # TODO: Parse/Validate invoice_no as integer
226
+ # TODO: Parse/Validate new_order_no as integer
227
+
228
+ params = [
229
+ self.store_id,
230
+ invoice_no,
231
+ self.digest(invoice_no, new_order_no),
232
+ new_order_no
233
+ ]
234
+
235
+ self.call(:update_orderno, *params)
236
+ end
237
+
238
+ # Retrieve the address for an invoice.
239
+ #
240
+ def invoice_address(invoice_no)
241
+ # TODO: Parse/Validate invoice_no as integer
242
+
243
+ params = [
244
+ self.store_id,
245
+ invoice_no,
246
+ self.digest(invoice_no)
247
+ ]
248
+
249
+ self.call(:invoice_address, *params).tap do |result|
250
+ result[5] = result[5].to_s.upcase
251
+ end
252
+ end
253
+ alias :get_invoice_address :invoice_address
254
+
255
+ # Retrieve the total amount of an invoice - optionally only partly.
256
+ #
257
+ def invoice_amount(invoice_no, articles = nil)
258
+ # TODO: Parse/Validate invoice_no as integer
259
+ articles = Array.wrap(articles).compact
260
+ artnos =
261
+ if articles.first.respond_to?(:key?) && articles.first.key?(:qty) && articles.first.key?(:artno)
262
+ articles
263
+ else
264
+ articles.collect { |a| {:artno => a[:goods][:artno], :qty => a[:qty]} }
265
+ end
266
+
267
+ params = [
268
+ self.store_id,
269
+ invoice_no
270
+ ]
271
+
272
+ # Only partly?
273
+ if articles.present?
274
+ params << artnos
275
+ params << self.digest(invoice_no, artnos.collect { |an| [an[:artno], an[:qty]].join(':') }.join(':'))
276
+ method = :invoice_part_amount
277
+ else
278
+ params << self.digest(invoice_no)
279
+ method = :invoice_amount
280
+ end
281
+
282
+ self.call(method, *params)
283
+ end
284
+ alias :get_invoice_amount :invoice_amount
285
+
286
+ # Check if invoice is paid.
287
+ #
288
+ def invoice_paid?(invoice_no)
289
+ # TODO: Parse/Validate invoice_no as numeric value (string)
290
+
291
+ params = [
292
+ invoice_no,
293
+ self.store_id,
294
+ self.digest(invoice_no)
295
+ ]
296
+
297
+ result = self.call(:is_invoice_paid, *params)
298
+ result == 'unpaid' ? false : true
299
+ end
300
+
301
+ end
302
+ end
303
+ end
304
+ end