Class: Spree::Kashflow::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/spree/kashflow/client.rb

Overview

Stateless SOAP client for the KashFlow API. Only this class may reference Savon — every public method returns plain Ruby (Integer, Array, TrueClass) so no SOAP object crosses the gem boundary. KashFlow has no session token: credentials are sent on every call, so nothing is cached between calls.

Constant Summary collapse

WSDL =

Returns the WSDL endpoint KashFlow publishes for the SOAP API.

Returns:

  • (String)

    the WSDL endpoint KashFlow publishes for the SOAP API

"https://securedwebapp.com/api/service.asmx?WSDL"
AUTH_FAULT =

Returns matches SOAP faults caused by bad credentials.

Returns:

  • (Regexp)

    matches SOAP faults caused by bad credentials

/invalid.*(username|password)|not authori[sz]ed/i
SUCCESS_STATUS =

The WSDL declares Status as a bare s:string on every *Response element (minOccurs="0"), with no <s:enumeration> and no <wsdl:documentation> naming the success value — so this constant is KashFlow's documented convention ("OK"), not something the schema pins down. Comparison is case-insensitive, and an absent Status (legal, since minOccurs="0") is treated as success; only a present Status that is not "OK" is a business-level rejection.

Returns:

  • (String)

    the in-band Status value KashFlow returns on success.

"OK"

Instance Method Summary collapse

Constructor Details

#initialize(username:, password:) ⇒ Client

Returns a new instance of Client.

Parameters:

  • username (String)

    the KashFlow API username

  • password (String)

    the KashFlow API password



35
36
37
38
# File 'lib/spree/kashflow/client.rb', line 35

def initialize(username:, password:)
  @username = username
  @password = password
end

Instance Method Details

#apply_credit_note(credit_note_number:, invoice_number:) ⇒ TrueClass

Applies a credit note to an invoice in KashFlow.

The WSDL declares applyCreditNoteToInvoiceResult as an s:boolean. A false is a refusal to link, and swallowing it produces exactly the orphan credit note SyncRefundJob's precondition guard exists to prevent — a credit note sitting in KashFlow attached to nothing.

Parameters:

  • credit_note_number (Integer)

    the KashFlow credit note id

  • invoice_number (Integer)

    the KashFlow invoice id

Returns:

  • (TrueClass)

    true when the credit note was applied

Raises:



151
152
153
154
155
156
# File 'lib/spree/kashflow/client.rb', line 151

def apply_credit_note(credit_note_number:, invoice_number:)
  response = call(:apply_credit_note_to_invoice, {"InvoiceID" => invoice_number, "CreditNoteID" => credit_note_number})
  result = response.dig("applyCreditNoteToInvoiceResponse", "applyCreditNoteToInvoiceResult")
  assert_accepted!(result, "did not apply credit note #{credit_note_number} to invoice #{invoice_number}")
  true
end

#bank_accountsArray<Hash>

Returns bank accounts as {id:, name:} hashes.

Returns:

  • (Array<Hash>)

    bank accounts as {id:, name:} hashes

Raises:



75
76
77
78
# File 'lib/spree/kashflow/client.rb', line 75

def bank_accounts
  rows = extract_rows(call(:get_bank_accounts), "GetBankAccountsResponse", "GetBankAccountsResult", "BankAccount")
  rows.map { |row| {id: row["AccountID"].to_i, name: row["AccountName"]} }
end

#create_invoice(payload) ⇒ Integer

Creates an invoice in KashFlow.

Parameters:

  • payload (Hash)

    a KashFlow Invoice_TypeDefined structure

Returns:

  • (Integer)

    the invoice number KashFlow assigned

Raises:



111
112
113
114
115
# File 'lib/spree/kashflow/client.rb', line 111

def create_invoice(payload)
  response = call(:insert_invoice_type_defined, {"Inv_TD" => payload})
  result = response.dig("InsertInvoice_TypeDefinedResponse", "InsertInvoice_TypeDefinedResult")
  assert_identifier!(result, "invoice number")
end

#currenciesArray<Hash>

Returns currencies as {code:, id:} hashes.

Returns:

  • (Array<Hash>)

    currencies as {code:, id:} hashes

Raises:



57
58
59
60
# File 'lib/spree/kashflow/client.rb', line 57

def currencies
  rows = extract_rows(call(:get_currencies), "GetCurrenciesResponse", "GetCurrenciesResult", "Currencies")
  rows.map { |row| {code: row["CurrencyCode"], id: row["CurrencyId"].to_i} }
end

#nominal_codesArray<Hash>

Returns nominal codes as {id:, name:} hashes.

Returns:

  • (Array<Hash>)

    nominal codes as {id:, name:} hashes

Raises:



66
67
68
69
# File 'lib/spree/kashflow/client.rb', line 66

def nominal_codes
  rows = extract_rows(call(:get_nominal_codes), "GetNominalCodesResponse", "GetNominalCodesResult", "NominalCode")
  rows.map { |row| {id: row["id"].to_i, name: row["Name"]} }
end

#payment_methodsArray<Hash>

Returns invoice payment methods as {id:, name:} hashes.

Returns:

  • (Array<Hash>)

    invoice payment methods as {id:, name:} hashes

Raises:



84
85
86
87
# File 'lib/spree/kashflow/client.rb', line 84

def payment_methods
  rows = extract_rows(call(:get_inv_pay_methods), "GetInvPayMethodsResponse", "GetInvPayMethodsResult", "PaymentMethod")
  rows.map { |row| {id: row["MethodID"].to_i, name: row["MethodName"]} }
end

#record_invoice_payment(payload) ⇒ TrueClass

Records a payment against an invoice in KashFlow.

The WSDL declares InsertInvoicePaymentResult as an s:int — the id of the payment KashFlow created. A 0 is therefore a rejection reported without a Status, and returning true regardless would leave the invoice permanently unpaid while the caller recorded a successful sync.

Parameters:

  • payload (Hash)

    a KashFlow Payment structure

Returns:

  • (TrueClass)

    true when the payment was recorded

Raises:



130
131
132
133
134
135
# File 'lib/spree/kashflow/client.rb', line 130

def record_invoice_payment(payload)
  response = call(:insert_invoice_payment, {"InvoicePayment" => payload})
  result = response.dig("InsertInvoicePaymentResponse", "InsertInvoicePaymentResult")
  assert_identifier!(result, "payment id")
  true
end

#upsert_customer(payload) ⇒ Integer

Creates or updates a customer in KashFlow.

Parameters:

  • payload (Hash)

    a KashFlow Customer structure

Returns:

  • (Integer)

    the KashFlow customer id

Raises:



97
98
99
100
101
# File 'lib/spree/kashflow/client.rb', line 97

def upsert_customer(payload)
  response = call(:insert_customer, {"custr" => payload})
  result = response.dig("InsertCustomerResponse", "InsertCustomerResult")
  assert_identifier!(result, "customer id")
end

#verify_credentialsTrueClass, FalseClass

Verifies the configured credentials against the KashFlow API. Does not rescue — the caller decides how to handle a raised error.

Returns:

  • (TrueClass, FalseClass)

    true when KashFlow accepts the credentials

Raises:



48
49
50
51
# File 'lib/spree/kashflow/client.rb', line 48

def verify_credentials
  call(:get_currencies)
  true
end