Skip to content
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
17 changes: 17 additions & 0 deletions app/controllers/requests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ def start
redirect_to new_distribution_path(request_id: request.id)
end

def print_picklist
request = current_organization
.requests
.includes(:item_requests, partner: [:profile])
.find(params[:id])

respond_to do |format|
format.any do
pdf = PicklistsPdf.new(current_organization, [request])
send_data pdf.compute_and_render,
filename: format("Picklists_%s.pdf", Time.current.to_fs(:long)),
type: "application/pdf",
disposition: "inline"
end
end
end

def print_unfulfilled
requests = current_organization
.requests
Expand Down
2 changes: 2 additions & 0 deletions app/pdfs/picklists_pdf.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "prawn/table"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lack of this was tossing an error for me locally


# Configures a Prawn PDF template for generating Distribution manifests
class PicklistsPdf
include Prawn::View
Expand Down
3 changes: 2 additions & 1 deletion app/views/requests/_request_row.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@
<td class="text-right">
<%= view_button_to request_path(request_row) %>
<%= button_to 'Cancel', new_request_cancelation_path(request_id: request_row.id), method: :get, class: 'btn btn-danger btn-xs' %>
</td>
<%= print_button_to print_picklist_request_path(request_row), { format: :pdf, text: "Print", size: "xs" } %>
</td>
</tr>
1 change: 1 addition & 0 deletions app/views/requests/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
<div class="card-footer flex flex-row space-x-2">
<%= submit_button_to start_request_path(@request), {text: "Fulfill request", size: "md"} unless @request.distribution %>
<%= view_button_to(distribution_path(@request.distribution), {text: "View Associated Distribution", size: "md"}) if @request.distribution %>
<%= print_button_to print_picklist_request_path(@request), { format: :pdf, text: "Print", size: "md" } %>
<%= button_to 'Cancel', new_request_cancelation_path(request_id: @request.id),
method: :get, form_class: 'd-inline', class: 'btn btn-danger btn-md' %>
</div>
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def set_up_flipper
post :start
end
get :print_unfulfilled, on: :collection
get :print_picklist, on: :member
end
resources :requests, except: %i(destroy) do
resource :cancelation, only: [:new, :create], controller: 'requests/cancelation'
Expand Down
10 changes: 10 additions & 0 deletions docs/user_guide/bank/essentials_requests.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ This will create a .csv file with the following information for each filtered Re
- the quantity requested
Note: If you use custom units, there will be a column for each item/unit that is available to be requested.

## Printing Request picklists
You can print out a "picklist" for any Request you can see. This function produces a pdf showing all items requested for the selected Request.

This is visible on the Request detail page:
![Print Picklist](images/essentials/requests/essentials_requests_print_picklist_navigation.png)


And also visible on the Request list page:
![Print Picklist](images/essentials/requests/essentials_requests_print_picklist_navigation2.png)

## Printing unfulfilled Request picklists

Finally, you can also print "picklists" for your unfulfilled Requests.
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 22 additions & 2 deletions spec/pdfs/picklists_pdf_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

describe "#compute_and_render" do
it "renders multiple requests correctly" do
request1 = create(:request, :pending, organization: organization)
request2 = create(:request, :pending, organization: organization)
request1 = create(:request, :pending, organization: organization, comments: "Request 1 comments")
request2 = create(:request, :pending, organization: organization, comments: "Request 2 comments")
create(:item_request, request: request1, item: item1, name: "Item 1")
create(:item_request, request: request2, item: item2, name: "Item 2")

Expand All @@ -19,6 +19,7 @@
expect(pdf_test.page(1).text).to include("Requested on:")
expect(pdf_test.page(1).text).to include("Items Received Year-to-Date:")
expect(pdf_test.page(1).text).to include("Comments")
expect(pdf_test.page(1).text).to include(request1.comments)
expect(pdf_test.page(1).text).to include("Items Requested")
expect(pdf_test.page(1).text).to include("Item 1")

Expand All @@ -28,10 +29,29 @@
expect(pdf_test.page(2).text).to include("Requested on:")
expect(pdf_test.page(2).text).to include("Items Received Year-to-Date:")
expect(pdf_test.page(2).text).to include("Comments")
expect(pdf_test.page(2).text).to include(request2.comments)
expect(pdf_test.page(2).text).to include("Items Requested")
expect(pdf_test.page(2).text).to include("Item 2")
end

context "when ytd_on_distribution_printout is enabled for the organization" do
before { organization.update(ytd_on_distribution_printout: true) }

it "renders the YTD quantity" do
partner = create(:partner)
request = create(:request, :pending, organization: organization, partner: partner)
create(:item_request, request: request, item: item1, name: "Item 1", quantity: 17)

# stub out the quantity_year_to_date method, it's not the PDF's job to make sure the calculation is correct
allow(partner).to receive(:quantity_year_to_date).and_return(17827)
pdf = described_class.new(organization, [request])
pdf_test = PDF::Reader.new(StringIO.new(pdf.compute_and_render))

expect(pdf_test.page(1).text).to include("Items Received Year-to-Date:")
expect(pdf_test.page(1).text).to include("17827")
end
end

context "When partner pickup person is set" do
it "renders pickup person details" do
partner = create(:partner)
Expand Down
106 changes: 106 additions & 0 deletions spec/requests/partners/requests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,112 @@
end
end

describe "GET #print_unfulfilled" do
let(:item1) { create(:item, name: "Good item") }
let(:item2) { create(:item, name: "Crap item") }
let(:partner1) { create(:partner, organization: organization) }
let(:partner_user) { partner1.primary_user }
let!(:pending_request) { create(:request, :with_item_requests, :pending, partner: partner1, request_items: [{ item_id: item1.id, quantity: '100' }]) }
let!(:started_request) { create(:request, :with_item_requests, :started, partner: partner1, request_items: [{ item_id: item2.id, quantity: '50' }]) }
let!(:discarded_request) { create(:request, :with_item_requests, :discarded, partner: partner1, request_items: [{ item_id: item2.id, quantity: '30' }]) }
let!(:fulfilled_request) { create(:request, :with_item_requests, :fulfilled, partner: partner1, request_items: [{ item_id: item2.id, quantity: '20' }]) }

before do
partner_user.add_role(Role::ORG_ADMIN, organization)
sign_in(partner_user)
get print_unfulfilled_requests_path(format: :pdf)
end

it "returns a PDF file" do
PDF::Reader.new(StringIO.new(response.body))
expect(response.content_type).to eq('application/pdf')
expect(response.headers['Content-Disposition']).to include('inline')
expect(response.body.bytes[0..3]).to eq('%PDF'.bytes)
end

it "includes only 'pending' and 'started' requests" do
pdf_content = PDF::Reader.new(StringIO.new(response.body))
# this is a semi-lazy check, since we're ensuring 1 page for each request. In real world,
# it's possible that there could be more than 1 page per request if the request is long.

expect(pdf_content.page_count).to eq(2)
end

it "calls compute_and_render with the 2 matching requests" do
# Create a double for the PDF instance
pdf_double = double("PicklistsPdf")

# Expect PicklistsPdf.new to be called with correct args and return our double
expect(PicklistsPdf).to receive(:new)
.with(organization, kind_of(ActiveRecord::Relation))
.and_return(pdf_double)

# Expect compute_and_render to be called on our double and return some PDF data
# We don't really care about the content, the PDF model is tested elsewhere
expect(pdf_double).to receive(:compute_and_render)
.and_return("fake pdf content")

# Make the request
get print_unfulfilled_requests_path(format: :pdf)

# Verify the response
expect(response).to be_successful
expect(response.content_type).to eq("application/pdf")
expect(response.headers["Content-Disposition"]).to include("inline")
expect(response.body).to eq("fake pdf content")
end
end

describe "GET #print_picklist" do
let(:organization) { create(:organization) }
let(:partner) { create(:partner, organization: organization) }
let(:partner_user) { partner.primary_user }
let(:org_admin) { create(:organization_admin, organization: organization) }
let(:request) { create(:request, :with_item_requests, organization: organization, partner: partner, partner_user: org_admin) }

before do
sign_in(org_admin)
end

it "generates a PDF for a single request" do
# Create a double for the PDF instance
pdf_double = double("PicklistsPdf")

# Expect PicklistsPdf.new to be called with correct args and return our double
expect(PicklistsPdf).to receive(:new)
.with(organization, [request])
.and_return(pdf_double)

# Expect compute_and_render to be called on our double and return some PDF data
expect(pdf_double).to receive(:compute_and_render)
.and_return("fake pdf content")

# Make the request
get print_picklist_request_path(request, format: :pdf)

# Verify the response
expect(response).to be_successful
expect(response.content_type).to eq("application/pdf")
expect(response.headers["Content-Disposition"]).to include("inline")
expect(response.headers["Content-Disposition"]).to include("Picklists_")
expect(response.body).to eq("fake pdf content")
end

it "includes correct associations in the query" do
pdf_double = double("PicklistsPdf", compute_and_render: "pdf content")

expect(PicklistsPdf).to receive(:new) do |org, requests|
# Verify the request includes the necessary associations
expect(requests.first.association(:item_requests)).to be_loaded
expect(requests.first.association(:partner)).to be_loaded
expect(requests.first.partner.association(:profile)).to be_loaded
pdf_double
end

get print_picklist_request_path(request, format: :pdf)
end
end

describe 'POST #validate' do
it 'should handle missing CSRF gracefully' do
sign_in(partner_user)
Expand Down