-
Notifications
You must be signed in to change notification settings - Fork 0
/
SymphonyServerAddon.lua
279 lines (213 loc) · 10.9 KB
/
SymphonyServerAddon.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
-- =========================================================
-- Load settings and .NET Assemblies
-- =========================================================
local Settings = {}
Settings.RequestMonitorQueue = GetSetting("RequestMonitorQueue")
Settings.SuccessRouteQueue = GetSetting("SuccessRouteQueue")
Settings.ErrorRouteQueue = GetSetting("ErrorRouteQueue")
-- Declaring WebServiceUrl here, so it will be globally accessible
Settings.SymphonyWebServiceUrl = nil
Settings.LookupSourceField = GetSetting("LookupSourceField")
Settings.LocationDestinationField = GetSetting("LocationDestinationField")
Settings.BarcodeDestinationField = GetSetting("BarcodeDestinationField")
Settings.ShelfLocationDestinationField = GetSetting("ShelfLocationDestinationField")
luanet.load_assembly("System")
luanet.load_assembly("log4net")
luanet.load_assembly("Mscorlib")
local types = {}
types["System.Type"] = luanet.import_type("System.Type")
types["log4net.LogManager"] = luanet.import_type("log4net.LogManager")
-- =========================================================
-- Main
-- =========================================================
local isCurrentlyProcessing = false
local rootLogger = "AtlasSystems.Addons.Aeon.SymphonyImportAddon";
local log = types["log4net.LogManager"].GetLogger(rootLogger)
function Init ()
RegisterSystemEventHandler("SystemTimerElapsed", "TimerElapsed")log:Debug("Addon Settings: ")
-- Setting the WebServiceUrl in Init, so PrepServiceUrl can be called
Settings.SymphonyWebServiceUrl = PrepServiceUrl(GetSetting("SymphonyWebServiceUrl"))
LogSettings()
end
function TimerElapsed (eventArgs)
--[[
Function that is called whenever the
system manager triggers server addon
execution.
]]
if (not isCurrentlyProcessing) then
isCurrentlyProcessing = true
local successfulAddonExecution, error = pcall(function()
ProcessDataContexts("TransactionStatus", Settings.RequestMonitorQueue, "HandleRequests")
end)
if not successfulAddonExecution then
log:Error("Unsuccessful addon execution.")
log:Error(error.Message or error)
LogSettings()
end
isCurrentlyProcessing = false
else
log:Debug("Addon is still executing.")
end
end
function LogSettings()
for settingKey, settingValue in pairs(Settings) do
log:DebugFormat("{0}: {1}", settingKey, settingValue)
end
end
function PrepServiceUrl(url)
-- Make sure that a question mark is on the end of the web service url
if not string.find(url, "?", -1) then
log:Debug("Appending question mark to web service url")
url = url .. "?"
end
return url
end
-- =========================================================
-- ProcessDataContext functionality
-- =========================================================
function HandleRequests ()
--[[
Must be called from a ProcessDataContexts function.
Runs for every transaction that meets the criteria specified
by the ProcessDataContexts function.
]]
local transactionNumber = GetFieldValue("Transaction", "TransactionNumber")
log:DebugFormat("Found transaction number {0} in \"{1}\"", transactionNumber, Settings.RequestMonitorQueue)
local success, result = pcall(
function()
local fieldFetchSuccess, transactionCallNumber = pcall(
function()
local lookupValue = Utility.StringSplit(" ", Settings.LookupSourceField);
local transactionCallNumber = nil;
if not lookupValue or lookupValue == "" then
log:ErrorFormat("Lookup Value from Transaction {0} is empty.", transactionNumber);
error({Message = "Lookup Value is empty."});
end
log:DebugFormat("Lookup Value Count = {0}", #lookupValue);
if #lookupValue == 2 then
local callNumber = GetFieldValue("Transaction", lookupValue[1]);
local location = GetFieldValue("Transaction", lookupValue[2]);
if callNumber and location then
transactionCallNumber = callNumber .. " " .. location;
elseif callNumber then
transactionCallNumber = callNumber;
end
elseif #lookupValue == 1 then
transactionCallNumber = GetFieldValue("Transaction", lookupValue[1]);
else
log:ErrorFormat("Incorrect number of Lookup Values on Transaction {0}.", transactionNumber);
end
log:DebugFormat("Returning Transaction Call Number: {0}", transactionCallNumber);
return transactionCallNumber;
end
)
if not(fieldFetchSuccess) then
log:ErrorFormat("Error fetching Call Number from Transaction {0}.", transactionNumber)
error({ Message = "Error fetching Call Number from the Transactions table." })
end
log:DebugFormat("Call Number : {0}", transactionCallNumber)
log:Info("Searching for Symphony records.")
local success, symphonyRecord = pcall(GetSymphonyRecordByCallNumber,transactionCallNumber);
if not success then
error({ Message = symphonyRecord.Message });
end
if (symphonyRecord.CallNumber ~= transactionCallNumber) and
(symphonyRecord.CallNumber == nil or transactionCallNumber == nil or string.upper(symphonyRecord.CallNumber) ~= string.upper(transactionCallNumber)) then
log:ErrorFormat("Call Number from web service ({0}) does not match provided call number ({1})", symphonyRecord.CallNumber, transactionCallNumber)
error({Message = "Call Number from web service does not match provided call number"});
end
if Settings.LocationDestinationField and Settings.LocationDestinationField ~= "" then
log:Debug("Populating location destination field")
if (not type(symphonyRecord.Location) == "string") or symphonyRecord.Location == "" then
error({ Message = "Cannot populate location from Symphony. Location is either missing or blank." })
end
SetFieldValue("Transaction", Settings.LocationDestinationField, symphonyRecord.Location)
SaveDataSource("Transaction")
end
if Settings.BarcodeDestinationField and Settings.BarcodeDestinationField ~= "" then
log:Debug("Populating barcode destination field")
if (not type(symphonyRecord.Barcode) == "string") or symphonyRecord.Barcode == "" then
error({ Message = "Cannot populate barcode from Symphony. Barcode is either missing or blank." })
end
SetFieldValue("Transaction", Settings.BarcodeDestinationField, symphonyRecord.Barcode)
SaveDataSource("Transaction")
end
if Settings.ShelfLocationDestinationField and Settings.ShelfLocationDestinationField ~= "" then
if ((symphonyRecord.ShelfLocation) and (type(symphonyRecord.ShelfLocation) == "string") and (symphonyRecord.ShelfLocation ~= "")) then
log:Debug("Populating shelf location destination field")
SetFieldValue("Transaction", Settings.ShelfLocationDestinationField, symphonyRecord.ShelfLocation)
SaveDataSource("Transaction");
else
log:Warn("Cannot populate shelf location from Symphony. Shelf location is either missing or blank.");
end
end
return nil
end
)
if success then
log:InfoFormat("Addon successfully populated Transaction {0} with data from Symphony", transactionNumber)
ExecuteCommand("Route", { transactionNumber, Settings.SuccessRouteQueue })
else
log:ErrorFormat("Failed to populate transaction {0} with data from Symphony. Routing transaction to \"{1}\".", transactionNumber, Settings.ErrorRouteQueue)
log:Error(result.Message or result)
ExecuteCommand("AddNote", { transactionNumber, result.Message or result })
ExecuteCommand("Route", { transactionNumber, Settings.ErrorRouteQueue })
end
end
function GetSymphonyRecordByCallNumber(callNumber)
if ((callNumber == nil) or (callNumber == "")) then
log:Error("Invalid callnumber");
error({ Message = "Error getting Symphony Record: Invalid call number" });
end
local url = Settings.SymphonyWebServiceUrl .. "callnum=" .. FormatSymphonyQueryString(callNumber);
log:DebugFormat("Requesting {0} from {1}", callNumber, url);
local result = WebClient.GetRequest(url, {});
log:DebugFormat("Web Request Result = {0}", result);
if not result then
log:Error("Web request resulted in an error");
error({ Message = "Web request resulted in an error" });
end
local success, record = pcall(ParseWebServiceResult, result);
if not success then
log:ErrorFormat("Error getting Symphony Record: {0}", record.Message or record);
error({ Message = record.Message });
end
return record;
end
function FormatSymphonyQueryString(queryString)
-- Replaces encoded `nbsp;` with `+`
return string.gsub(Utility.URLEncode(queryString), "%%C2%%A0", "+")
end
function ParseWebServiceResult(result)
local errorMessage = "invalid call number as input";
local record = nil;
local data = Utility.StringSplit('|', result);
log:DebugFormat("Data's Length = {0}", #data);
if #data >= 3 then
log:Debug("Creating record...");
-- Only taking the first record's data
record = {
Barcode = Utility.Trim(data[1]),
Location = Trim(data[2]),
CallNumber = Trim(data[3]),
ShelfLocation = nil;
};
log:DebugFormat("Barcode: {0}", record.Barcode);
log:DebugFormat("Location: {0}", record.Location);
log:DebugFormat("CallNumber: {0}", record.CallNumber);
if #data >= 4 then
record.ShelfLocation = Trim(data[4]);
log:DebugFormat("Shelf Location: {0}", record.ShelfLocation);
else
log:Warn("Record did not contain Shelf Location");
end
elseif data == errorMessage then
log:Error(errorMessage);
error({ Message = errorMessage });
else
log:ErrorFormat("Web Service result is invalid: {0}", result);
error({ Message = "Web Service result is invalid: " .. result });
end
return record;
end