spree-kashflow 0.1.2 → 0.1.3
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/CHANGELOG.md +23 -0
- data/lib/spree/kashflow/client.rb +67 -4
- data/lib/spree/kashflow/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf3ea17173c688a2ae5facaa72f582c02b2bb56b3d013d4d64e7467104b200b6
|
|
4
|
+
data.tar.gz: 14b81280691c79a6d6501cb4ae1e173a1e094be9c504bf90bcfb7de9cb40bc93
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4909476c53475670965c33e28bf2ec279e7551bbac94a7a43ddd3777d72577569eb84ec7fc9d216f23afa79c7e2989efef18a3deb8757fea76c20fdc04c51d2e
|
|
7
|
+
data.tar.gz: 289bc0e640aab7cea52cb96c2b019a00dd11e9bc010035b45056d947990152317755863978b5d16e071b5196a19ffc24429d9544c1fd9de7dfd34244a300f19e
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.3
|
|
4
|
+
|
|
5
|
+
- **Fix: `upsert_customer` only ever inserted.** KashFlow publishes no
|
|
6
|
+
`InsertOrUpdateCustomer`, and the client called `InsertCustomer`
|
|
7
|
+
unconditionally with no lookup. 0.1.1 made customer codes stable per customer
|
|
8
|
+
— which is what keeps one KashFlow customer per Spree customer rather than one
|
|
9
|
+
per order — and that turned the missing lookup into a hard failure: the insert
|
|
10
|
+
succeeded exactly once, and the same customer's *second* order was rejected
|
|
11
|
+
with `Customer Code is not unique`, posting no invoice. `upsert_customer` now
|
|
12
|
+
looks the code up with `GetCustomer` and either `UpdateCustomer`s the existing
|
|
13
|
+
record or `InsertCustomer`s a new one, so it is idempotent across repeated
|
|
14
|
+
syncs.
|
|
15
|
+
- `CustomerID` is prepended to the update payload rather than merged onto the
|
|
16
|
+
end, because it is the first element of the WSDL's `Customer` sequence and an
|
|
17
|
+
ASMX endpoint enforcing that sequence drops or mis-binds an out-of-order
|
|
18
|
+
element rather than raising — an update whose id was dropped would write to
|
|
19
|
+
the wrong customer, or to none, and still return successfully.
|
|
20
|
+
- How KashFlow signals "no such customer" on `GetCustomer` is undocumented, so
|
|
21
|
+
both plausible shapes are treated as absent: an empty result, and an in-band
|
|
22
|
+
business rejection. Only `ApiError` is swallowed; an authentication or
|
|
23
|
+
transport failure keeps propagating rather than being read as "absent" and
|
|
24
|
+
turned back into a duplicate insert.
|
|
25
|
+
|
|
3
26
|
## 0.1.2
|
|
4
27
|
|
|
5
28
|
- **Fix: every order sync still failed against a live KashFlow account**, now on
|
|
@@ -87,14 +87,28 @@ module Spree
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
##
|
|
90
|
-
# Creates or updates a customer in KashFlow
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
90
|
+
# Creates or updates a customer in KashFlow, keyed on the customer `Code`.
|
|
91
|
+
#
|
|
92
|
+
# KashFlow publishes no `InsertOrUpdateCustomer`, so an upsert is a lookup
|
|
93
|
+
# followed by an `UpdateCustomer` or an `InsertCustomer`. The lookup is not
|
|
94
|
+
# optional: customer codes are stable per customer (that is what keeps one
|
|
95
|
+
# KashFlow customer per Spree customer rather than one per order), so an
|
|
96
|
+
# unconditional insert succeeds exactly once and every subsequent order for
|
|
97
|
+
# that customer is rejected with "Customer Code is not unique" — with no
|
|
98
|
+
# invoice posted.
|
|
99
|
+
#
|
|
100
|
+
# @param payload [Hash] a KashFlow `Customer` structure, whose `"Code"`
|
|
101
|
+
# identifies the customer
|
|
102
|
+
# @return [Integer] the KashFlow customer id, existing or newly assigned
|
|
94
103
|
# @raise [Spree::Kashflow::ApiError] when the request fails, or when
|
|
95
104
|
# KashFlow returns no usable customer id
|
|
105
|
+
# @raise [Spree::Kashflow::AuthenticationError] when KashFlow rejects the
|
|
106
|
+
# credentials
|
|
96
107
|
#
|
|
97
108
|
def upsert_customer(payload)
|
|
109
|
+
existing_id = customer_id_for_code(payload["Code"])
|
|
110
|
+
return update_customer(existing_id, payload) if existing_id
|
|
111
|
+
|
|
98
112
|
response = call(:insert_customer, {"custr" => payload})
|
|
99
113
|
result = response.dig("InsertCustomerResponse", "InsertCustomerResult")
|
|
100
114
|
assert_identifier!(result, "customer id")
|
|
@@ -196,6 +210,55 @@ module Spree
|
|
|
196
210
|
raise TransportError, e.message
|
|
197
211
|
end
|
|
198
212
|
|
|
213
|
+
##
|
|
214
|
+
# Looks a customer up by its KashFlow `Code`.
|
|
215
|
+
#
|
|
216
|
+
# How KashFlow signals "no such customer" here is undocumented, and no
|
|
217
|
+
# spec that stubs the SOAP layer can settle it, so both shapes it can
|
|
218
|
+
# plausibly take are treated as absent: an empty `GetCustomerResult`, and
|
|
219
|
+
# an in-band business rejection. Only {ApiError} is swallowed — an
|
|
220
|
+
# authentication or transport failure must keep propagating, since
|
|
221
|
+
# reading either as "absent" would turn it into a duplicate insert and
|
|
222
|
+
# put the caller back on the collision this method exists to avoid.
|
|
223
|
+
#
|
|
224
|
+
# @param code [String, nil] the KashFlow customer code
|
|
225
|
+
# @return [Integer, nil] the customer id, or nil when no customer holds
|
|
226
|
+
# that code
|
|
227
|
+
#
|
|
228
|
+
def customer_id_for_code(code)
|
|
229
|
+
return nil if code.to_s.strip.empty?
|
|
230
|
+
|
|
231
|
+
result = call(:get_customer, {"CustomerCode" => code})
|
|
232
|
+
.dig("GetCustomerResponse", "GetCustomerResult")
|
|
233
|
+
return nil unless result.is_a?(Hash)
|
|
234
|
+
|
|
235
|
+
identifier = result["CustomerID"].to_i
|
|
236
|
+
identifier.zero? ? nil : identifier
|
|
237
|
+
rescue ApiError
|
|
238
|
+
nil
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
##
|
|
242
|
+
# Updates an existing KashFlow customer in place.
|
|
243
|
+
#
|
|
244
|
+
# `CustomerID` is prepended rather than merged onto the end because it is
|
|
245
|
+
# the first element of the WSDL's `Customer` sequence, and an ASMX
|
|
246
|
+
# endpoint enforcing that sequence drops or mis-binds an out-of-order
|
|
247
|
+
# element rather than raising — an update whose id was dropped would write
|
|
248
|
+
# to the wrong customer, or to none, and still return successfully.
|
|
249
|
+
#
|
|
250
|
+
# `UpdateCustomerResult` is a `s:string`, not the customer id, so the id
|
|
251
|
+
# is carried over from the lookup instead of being read off the response.
|
|
252
|
+
#
|
|
253
|
+
# @param identifier [Integer] the KashFlow customer id
|
|
254
|
+
# @param payload [Hash] a KashFlow `Customer` structure
|
|
255
|
+
# @return [Integer] the customer id that was updated
|
|
256
|
+
#
|
|
257
|
+
def update_customer(identifier, payload)
|
|
258
|
+
call(:update_customer, {"custr" => {"CustomerID" => identifier}.merge(payload)})
|
|
259
|
+
identifier
|
|
260
|
+
end
|
|
261
|
+
|
|
199
262
|
##
|
|
200
263
|
# Rewrites every temporal value in an outgoing message to xsd `dateTime`.
|
|
201
264
|
#
|