Skip to content
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

change submission status checking to handle out of order xml #5499

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions app/services/efile/poll_for_acknowledgments_service.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

StatusRecordGroup = Struct.new(:irs_submission_id, :state, :xml)

module Efile
Expand Down Expand Up @@ -103,8 +102,9 @@ def self._handle_submission_status_response(response)
submissions = EfileSubmission.where(irs_submission_id: groups_by_irs_submission_id.keys)
submissions.each do |submission|
status_updates += 1
xml_node = groups_by_irs_submission_id[submission.irs_submission_id]
status = xml_node.css('SubmissionStatusTxt').text.strip
xml_nodes = groups_by_irs_submission_id[submission.irs_submission_id]
xml_node = xml_node_with_most_recent_submission_status(xml_nodes)
status = status_from_xml_node(xml_node)
new_state = submission_status_to_state(status)
last_raw_response = submission.efile_submission_transitions.last&.metadata["raw_response"]
submission.transition_to(new_state, raw_response: xml_node.to_xml) unless xml_node.to_xml == last_raw_response
Expand All @@ -115,13 +115,32 @@ def self._handle_submission_status_response(response)

def self.group_status_records_by_submission_id(doc)
# The service returns multiple status records for the each submission id. It looks like they are in reverse
# chronological order (But are not properly date stamped), so we grab the first ones.
# chronological order (But are not properly date stamped), although we have seen examples where they are out of
# order. Regardless, we return each submission ID's list of statuses in the order they are encountered in the XML
doc.css('StatusRecordGrp').each_with_object({}) do |xml, groups_by_irs_submission_id|
irs_submission_id = xml.css("SubmissionId").text.strip
unless groups_by_irs_submission_id[irs_submission_id]
groups_by_irs_submission_id[irs_submission_id] = xml
if groups_by_irs_submission_id[irs_submission_id]
groups_by_irs_submission_id[irs_submission_id].append(xml)
else
groups_by_irs_submission_id[irs_submission_id] = [xml]
end
end
end

def self.xml_node_with_most_recent_submission_status(submission_status_xml_nodes)
# We might see out-of-order statuses in the list, so search the list for more-progresses statuses first
preferred_status_order = [READY_FOR_ACK_STATUSES, TRANSMITTED_STATUSES]
preferred_status_order.each do |statuses_to_look_for|
most_recent_status_node = submission_status_xml_nodes.find do |xml_node|
statuses_to_look_for.include? status_from_xml_node(xml_node)
end
return most_recent_status_node if most_recent_status_node.present?
end
nil
end

def self.status_from_xml_node(xml_node)
xml_node&.css('SubmissionStatusTxt')&.text&.strip
end

def self.submission_status_to_state(status)
Expand Down
222 changes: 187 additions & 35 deletions spec/services/efile/poll_for_acknowledgments_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,160 @@
let!(:fed_efile_submission1) { create(:efile_submission, :transmitted, submission_bundle: { filename: "sensible-filename.zip", io: StringIO.new("i am a zip file") }) }
let!(:fed_efile_submission2) { create(:efile_submission, :transmitted, submission_bundle: { filename: "sensible-filename.zip", io: StringIO.new("i am a zip file") }) }

let(:correctly_ordered_statuses_multiple_submissions_transmitted) {
Nokogiri::XML(
<<~XML
<?xml version='1.0' encoding='UTF-8'?>
<StatusRecordList xmlns="http://www.irs.gov/efile" xmlns:efile="http://www.irs.gov/efile">
<Cnt>4</Cnt>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received by State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>abcdefghijklmnopqrst</SubmissionId>
<SubmissionStatusTxt>Received by State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>abcdefghijklmnopqrst</SubmissionId>
<SubmissionStatusTxt>Sent to State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Sent to State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>abcdefghijklmnopqrst</SubmissionId>
<SubmissionStatusTxt>Ready for Pick-Up</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>abcdefghijklmnopqrst</SubmissionId>
<SubmissionStatusTxt>Received</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Ready for Pick-Up</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
</StatusRecordList>
XML
)
}

let(:correctly_ordered_statuses_transmitted) {
Nokogiri::XML(
<<~XML
<?xml version='1.0' encoding='UTF-8'?>
<StatusRecordList xmlns="http://www.irs.gov/efile" xmlns:efile="http://www.irs.gov/efile">
<Cnt>4</Cnt>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received by State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Sent to State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Ready for Pick-Up</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
</StatusRecordList>
XML
)
}

let(:correctly_ordered_statuses_ready_for_ack) {
Nokogiri::XML(
<<~XML
<?xml version='1.0' encoding='UTF-8'?>
<StatusRecordList xmlns="http://www.irs.gov/efile" xmlns:efile="http://www.irs.gov/efile">
<Cnt>5</Cnt>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Acknowledgement Received from State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received by State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Sent to State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Ready for Pick-Up</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
</StatusRecordList>
XML
)
}

let(:out_of_order_statuses_ready_for_ack) {
Nokogiri::XML(
<<~XML
<?xml version='1.0' encoding='UTF-8'?>
<StatusRecordList xmlns="http://www.irs.gov/efile" xmlns:efile="http://www.irs.gov/efile">
<Cnt>5</Cnt>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received by State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Acknowledgement Received from State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Sent to State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Ready for Pick-Up</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
</StatusRecordList>
XML
)
}

before do
fed_efile_submission1.update!(irs_submission_id: irs_submission_id1)
fed_efile_submission2.update!(irs_submission_id: irs_submission_id2)
Expand All @@ -286,49 +440,47 @@
context "getting status from state" do
it "interprets ready_for_ack successfully" do
["Denied by IRS", "Acknowledgement Received from State", "Acknowledgement Retrieved", "Notified"].each do |status|
expect(Efile::PollForAcknowledgmentsService.submission_status_to_state(status)).to eq :ready_for_ack
expect(described_class.submission_status_to_state(status)).to eq :ready_for_ack
end
end
it "interprets transmitted successfully" do
expect(Efile::PollForAcknowledgmentsService.submission_status_to_state("Received")).to eq :transmitted
expect(described_class.submission_status_to_state("Received")).to eq :transmitted
end
it "interprets unknown states as failed" do
expect(Efile::PollForAcknowledgmentsService.submission_status_to_state("My dog ate it")).to eq :failed
expect(described_class.submission_status_to_state("My dog ate it")).to eq :failed
end
end

context "statuses for submission_id" do
it "groups statuses by submission_id" do
doc = Nokogiri::XML(<<-TEXT
<?xml version='1.0' encoding='UTF-8'?>
<StatusRecordList xmlns="http://www.irs.gov/efile" xmlns:efile="http://www.irs.gov/efile">
<Cnt>4</Cnt>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received by State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Sent to State</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-04</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Ready for Pick-Up</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
<StatusRecordGrp>
<SubmissionId>4414662024003wte794o</SubmissionId>
<SubmissionStatusTxt>Received</SubmissionStatusTxt>
<SubmsnStatusAcknowledgementDt>2024-01-03</SubmsnStatusAcknowledgementDt>
</StatusRecordGrp>
</StatusRecordList>
TEXT
)
result = Efile::PollForAcknowledgmentsService.group_status_records_by_submission_id(doc)
expect(result.keys.length).to eq 1
expect(result["4414662024003wte794o"].css("SubmissionStatusTxt").text).to eq "Received by State"
describe ".group_status_records_by_submission_id" do
it "groups statuses by submission_id, preserving their order" do
result = described_class.group_status_records_by_submission_id(correctly_ordered_statuses_multiple_submissions_transmitted)
expect(result.keys.length).to eq 2
submission_ids = %w[4414662024003wte794o abcdefghijklmnopqrst]
submission_ids.each do |submission_id|
expect(result[submission_id].length).to eq 4
expect(result[submission_id].first.css("SubmissionStatusTxt").text).to eq "Received by State"
expect(result[submission_id].last.css("SubmissionStatusTxt").text).to eq "Received"
end
end
end

describe ".xml_node_with_most_recent_submission_status" do
it "gets the most recent xml node indicating a transmitted state in a correctly ordered list of statuses" do
xml_nodes = described_class.group_status_records_by_submission_id(correctly_ordered_statuses_transmitted)["4414662024003wte794o"]
xml_node = described_class.xml_node_with_most_recent_submission_status(xml_nodes)
expect(xml_node.css("SubmissionStatusTxt").text).to eq "Received by State"
end

it "gets the most recent xml node indicating a ready-for-ack state in a correctly ordered list of statuses" do
xml_nodes = described_class.group_status_records_by_submission_id(correctly_ordered_statuses_ready_for_ack)["4414662024003wte794o"]
xml_node = described_class.xml_node_with_most_recent_submission_status(xml_nodes)
expect(xml_node.css("SubmissionStatusTxt").text).to eq "Acknowledgement Received from State"
end

it "gets the most recent xml node indicating a ready-for-ack state in an incorrectly ordered list of statuses" do
xml_nodes = described_class.group_status_records_by_submission_id(out_of_order_statuses_ready_for_ack)["4414662024003wte794o"]
xml_node = described_class.xml_node_with_most_recent_submission_status(xml_nodes)
expect(xml_node.css("SubmissionStatusTxt").text).to eq "Acknowledgement Received from State"
end
end
end
Expand Down
Loading