-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FFS-2490 Wrap Argyle Data Fetch API's #496
base: main
Are you sure you want to change the base?
Changes from all commits
973101e
9bc2068
36a07fa
ee98bdb
ba1fd41
79f94e4
0224ae9
e069451
48a39eb
506d963
444fe29
7952367
57bcfce
bd2e454
daf83a2
dbea9db
99c59a1
4736834
16db288
cacc70a
d4e30cf
8c85c97
e002c24
e0c3db9
413ff47
f60e817
057f5d1
c9949c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
module ResponseObjects::FormatMethods::Argyle | ||
def self.format_employment_status(employment_status) | ||
return unless employment_status | ||
|
||
case employment_status | ||
when "active" | ||
"employed" | ||
when "inactive" | ||
"furloughed" | ||
else | ||
employment_status | ||
end | ||
end | ||
|
||
def self.format_date(date) | ||
return unless date | ||
|
||
DateTime.parse(date).strftime("%Y-%m-%d") | ||
end | ||
|
||
def self.format_currency(amount) | ||
return unless amount | ||
amount.to_f | ||
end | ||
|
||
def self.hours_by_earning_category(gross_pay_list) | ||
gross_pay_list | ||
.filter { |e| e["hours"].present? } | ||
.group_by { |e| e["type"] } | ||
.transform_values { |earnings| earnings.sum { |e| e["hours"].to_f } } | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module ResponseObjects::FormatMethods::Pinwheel | ||
def self.hours(earnings) | ||
base_hours = earnings | ||
.filter { |e| e["category"] != "overtime" } | ||
.map { |e| e["hours"] } | ||
.compact | ||
.max | ||
return unless base_hours | ||
|
||
# Add overtime hours to the base hours, because they tend to be additional | ||
# work beyond the other entries. (As opposed to category="premium", which | ||
# often duplicates other earnings' hours.) | ||
# | ||
# See FFS-1773. | ||
overtime_hours = earnings | ||
.filter { |e| e["category"] == "overtime" } | ||
.sum { |e| e["hours"] || 0.0 } | ||
|
||
base_hours + overtime_hours | ||
end | ||
|
||
def self.hours_by_earning_category(earnings) | ||
earnings | ||
.filter { |e| e["hours"] && e["hours"] > 0 } | ||
.group_by { |e| e["category"] } | ||
.transform_values { |earnings| earnings.sum { |e| e["hours"] } } | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
# frozen_string_literal: true | ||
|
||
require "faraday" | ||
require "fileutils" | ||
require "json" | ||
|
||
class ArgyleService | ||
ENVIRONMENTS = { | ||
|
@@ -11,7 +13,12 @@ class ArgyleService | |
} | ||
} | ||
|
||
USERS_ENDPOINT = "https://api-sandbox.argyle.com/v2/users" | ||
ITEMS_ENDPOINT = "items" | ||
PAYSTUBS_ENDPOINT = "paystubs" | ||
IDENTITIES_ENDPOINT = "identities" | ||
USERS_ENDPOINT = "users" | ||
ACCOUNTS_ENDPOINT = "accounts" | ||
EMPLOYMENTS_ENDPOINT = "employments" | ||
|
||
def initialize(environment, api_key_id = nil, api_key_secret = nil) | ||
@api_key_id = api_key_id || ENVIRONMENTS.fetch(environment.to_sym)[:api_key_id] | ||
|
@@ -38,12 +45,108 @@ def initialize(environment, api_key_id = nil, api_key_secret = nil) | |
end | ||
end | ||
|
||
def fetch_paystubs(**params) | ||
json = fetch_paystubs_api(**params) | ||
json["results"].map { |paystub_json| ResponseObjects::Paystub.from_argyle(paystub_json) } | ||
end | ||
|
||
def fetch_employments(**params) | ||
# Note: we actually fetch Argyle's identity API instead of employment for the correct data | ||
json = fetch_identities_api(**params) | ||
json["results"].map { |identity_json| ResponseObjects::Employment.from_argyle(identity_json) } | ||
end | ||
|
||
def fetch_incomes(**params) | ||
# Note: we actually fetch Argyle's identity API instead of employment for the correct data | ||
json = fetch_identities_api(**params) | ||
json["results"].map { |identity_json| ResponseObjects::Income.from_argyle(identity_json) } | ||
end | ||
|
||
# https://docs.argyle.com/api-reference/identities#retrieve | ||
def fetch_identities(**params) | ||
# todo: paginate | ||
json = fetch_identities_api(**params) | ||
json["results"].map { |identity_json| ResponseObjects::Identity.from_argyle(identity_json) } | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hopefully we can rework this when we do the AggregatorDataHelper method so that we're not making the same API call three times in succession. |
||
|
||
# Fetch all Argyle items | ||
# https://docs.argyle.com/api-reference/items#list | ||
def items(query = nil) | ||
@http.get("items", { q: query }).body | ||
@http.get(ITEMS_ENDPOINT, { q: query }).body | ||
end | ||
|
||
# https://docs.argyle.com/api-reference/users#retrieve | ||
def fetch_user_api(user:) | ||
@http.get(build_url("#{USERS_ENDPOINT}/#{user}")).body | ||
end | ||
|
||
# https://docs.argyle.com/api-reference/identities#list | ||
def fetch_identities_api(**params) | ||
# todo: paginate | ||
@http.get(IDENTITIES_ENDPOINT, params).body | ||
end | ||
|
||
# https://docs.argyle.com/api-reference/accounts#list | ||
def fetch_accounts_api(**params) | ||
# TODO: paginate | ||
# json["data"].map { |paystub_json| ResponseObjects::Paystub.from_pinwheel(paystub_json) } | ||
@http.get(ACCOUNTS_ENDPOINT, params).body | ||
end | ||
|
||
# https://docs.argyle.com/api-reference/paystubs#list | ||
def fetch_paystubs_api(**params) | ||
# TODO: paginate | ||
@http.get(PAYSTUBS_ENDPOINT, params).body | ||
end | ||
|
||
def create_user | ||
@http.post("users").body | ||
@http.post(USERS_ENDPOINT).body | ||
end | ||
|
||
# https://docs.argyle.com/api-reference/employments#list | ||
def fetch_employments_api(**params) | ||
# json["data"].map { |paystub_json| ResponseObjects::Paystub.from_pinwheel(paystub_json) } | ||
@http.get(EMPLOYMENTS_ENDPOINT, params).body | ||
end | ||
|
||
# TODO: refactor this into common function between argyle_service/pinwheel_service | ||
def build_url(endpoint) | ||
@http.build_url(endpoint).to_s | ||
end | ||
|
||
def store_mock_response(responsePayload:, folderName: "other", fileName:) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. idiomatic ruby would have these as snake_case. I'm going to follow up with a Rubocop rule to enforce this automatically. |
||
FileUtils.mkdir_p "spec/support/fixtures/argyle/#{folderName}" | ||
|
||
File.open("spec/support/fixtures/argyle/#{folderName}/#{fileName}.json", "wb") do | ||
|f| f.puts(JSON.pretty_generate(responsePayload)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Style nitpick - generally the block's argument is on the same line as the File.open(...) do |f| # <--- |f| goes on this line
f.puts(...)
end I couldn't find a rubocop rule for this. |
||
end | ||
end | ||
|
||
# Only for use in sandbox environment for test mocking | ||
def fetch__and_store_mock_data_for_user(argyle_user_id:, folderName:) | ||
store_mock_response( | ||
folderName: folderName, | ||
fileName: "request_user", | ||
responsePayload: fetch_user_api(user: argyle_user_id)) | ||
|
||
store_mock_response( | ||
folderName: folderName, | ||
fileName: "request_identity", | ||
responsePayload: fetch_identities_api(user: argyle_user_id)) | ||
|
||
store_mock_response( | ||
folderName: folderName, | ||
fileName: "request_employment", | ||
responsePayload: fetch_employment_api(user: argyle_user_id)) | ||
|
||
store_mock_response( | ||
folderName: folderName, | ||
fileName: "request_accounts", | ||
responsePayload: fetch_accounts_api(user: argyle_user_id)) | ||
|
||
store_mock_response( | ||
folderName: folderName, | ||
fileName: "request_paystubs", | ||
responsePayload: fetch_paystubs_api(user: argyle_user_id)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, maybe at some point we should move these methods into a helper module of some sort so they're not chilling on |
||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whew, the module name is a bit of a mouthful, but scoping it here makes the intention clear so it seems good to me.