From 0259fb2904f1f411e6cd024b278156184aa0f23e Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Fri, 16 Aug 2024 21:06:22 -0700 Subject: [PATCH 01/15] Add print button, route, and placeholder method --- app/controllers/requests_controller.rb | 3 +++ app/views/requests/index.html.erb | 6 ++++++ config/routes.rb | 1 + 3 files changed, 10 insertions(+) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index d44f022e3d..829fcaef48 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -40,6 +40,9 @@ def start redirect_to new_distribution_path(request_id: request.id) end + def print_unfulfilled + end + private def load_items diff --git a/app/views/requests/index.html.erb b/app/views/requests/index.html.erb index 5e02fc6b4e..0f923245f9 100644 --- a/app/views/requests/index.html.erb +++ b/app/views/requests/index.html.erb @@ -61,6 +61,12 @@ <%= clear_filter_button %> <%= modal_button_to("#calculateTotals", {text: "Calculate Product Totals", icon: nil, size: "md", type: "success"}) %> + <% if @requests.any? { |request| request.status == "pending" || request.status == "started" } %> + <%= print_button_to( + print_unfulfilled_requests_path(format: :pdf), + text: "Print Unfulfilled Picklists", + size: "md") %> + <% end %> <%= download_button_to(requests_path(format: :csv, filters: filter_params.merge(date_range: date_range_params)), {text: "Export Requests", size: "md"}) if @requests.any? %> diff --git a/config/routes.rb b/config/routes.rb index a97548c5cd..25a394fb41 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -241,6 +241,7 @@ def set_up_flipper member do post :start end + get :print_unfulfilled, on: :collection end resources :requests, except: %i(destroy) do resource :cancelation, only: [:new, :create], controller: 'requests/cancelation' From 2721a477c367118f1263c5e3b301804b953aa60e Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sat, 17 Aug 2024 00:01:06 -0700 Subject: [PATCH 02/15] Render PDF displaying table of one request's items --- app/controllers/requests_controller.rb | 11 ++++++++ app/pdfs/picklists_pdf.rb | 39 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 app/pdfs/picklists_pdf.rb diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index 829fcaef48..7871920b88 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -41,6 +41,17 @@ def start end def print_unfulfilled + @requests = Request.where(status: [0, 1]).limit(2) + # respond + respond_to do |format| + format.any do + pdf = PicklistsPdf.new(current_organization, @requests) + send_data pdf.compute_and_render, + filename: format("Picklists_%s.pdf", Time.current.to_fs(:long)), + type: "application/pdf", + disposition: "inline" + end + end end private diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb new file mode 100644 index 0000000000..5dc64aeb6e --- /dev/null +++ b/app/pdfs/picklists_pdf.rb @@ -0,0 +1,39 @@ +# Configures a Prawn PDF template for generating Distribution manifests +class PicklistsPdf + include Prawn::View + include ItemsHelper + + def initialize(organization, requests) + @requests = requests + @organization = organization + end + + def compute_and_render + data = request_data + + table(data) + + render + end + + def request_data + data = [["Items Requested", + "Quantity", + "", + "Differences/Comments"]] + + request = @requests.first + request_items = request.request_items.map do |request_item| + RequestItem.from_json(request_item, request) + end + + data + request_items.map do |request_item| + [request_item.item.name, + request_item.quantity, + "", + ""] + end + end +end + + From 9900e8df4cbae1278f47c3aa280aa717dfc523ef Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sat, 17 Aug 2024 20:38:47 -0700 Subject: [PATCH 03/15] Display complete styled PDF with no units column --- app/pdfs/picklists_pdf.rb | 120 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index 5dc64aeb6e..9a54d43a7a 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -4,14 +4,126 @@ class PicklistsPdf include ItemsHelper def initialize(organization, requests) - @requests = requests + @requests = requests # does this need to be Request.includes(XXX).etc? Investigate. @organization = organization + @request = @requests.first # temporary for single picklist only end def compute_and_render - data = request_data + font_families["OpenSans"] = PrawnRails.config["font_families"][:OpenSans] + font "OpenSans" + font_size 10 - table(data) + logo_image = if @organization.logo.attached? + StringIO.open(@organization.logo.download) + else + Organization::DIAPER_APP_LOGO + end + + footer_height = 35 + + # Bounding box containing non-footer elements + bounding_box [bounds.left, bounds.top], width: bounds.width, height: bounds.height - footer_height do + image logo_image, fit: [250, 85] + + bounding_box [bounds.right - 225, bounds.top], width: 225, height: 85 do + text @organization.name, align: :right + text @organization.address, align: :right + text @organization.email, align: :right + end + + text "Requested by:", style: :bold + font_size 12 + text @request.partner.name + move_up 24 + + text "Partner Primary Contact:", style: :bold, align: :right + font_size 12 + text @request.partner.profile.primary_contact_name, align: :right + font_size 10 + text @request.partner.profile.primary_contact_email, align: :right + text @request.partner.profile.primary_contact_phone, align: :right + move_down 10 + + if @request.partner.profile.pick_up_name.present? + move_up 10 + text "Partner Pickup Person:", style: :bold + font_size 12 + text @request.partner.profile.pick_up_name + font_size 10 + text @request.partner.profile.pick_up_email + text @request.partner.profile.pick_up_phone + move_up 24 + + text "Requested on:", style: :bold, align: :right + font_size 12 + text @request.created_at.to_fs(:date_picker), align: :right + font_size 10 + move_down 30 + else + text "Requested on:", style: :bold + font_size 12 + text @request.created_at.to_fs(:date_picker) + font_size 10 + end + + if @organization.ytd_on_distribution_printout + move_up 22 + text "Items Received Year-to-Date:", style: :bold, align: :right + font_size 12 + text @request.partner.quantity_year_to_date.to_s, align: :right + font_size 10 + end + + move_down 10 + text "Comments:", style: :bold + font_size 12 + text @request.comments + + move_down 20 + + data = request_data + + font_size 11 + + # Line item table + table(data) do + self.header = true + self.cell_style = { padding: [5, 20, 5, 20]} + self.row_colors = %w(dddddd ffffff) + + cells.borders = [] + + # Header row + row(0).borders = [:bottom] + row(0).border_width = 2 + row(0).font_style = :bold + row(0).size = 9 + row(0).column(1..-1).borders = %i(bottom left) + end + end + + number_pages "Page of ", + start_count_at: 1, + at: [bounds.right - 130, 22], + align: :right + + repeat :all do + # Page footer + bounding_box [bounds.left, bounds.bottom + footer_height], width: bounds.width do + stroke_bounds + font "OpenSans" + font_size 9 + stroke_horizontal_rule + move_down 5 + + logo_offset = (bounds.width - 190) / 2 + bounding_box([logo_offset, 0], width: 190, height: 33) do + text "Lovingly created with", valign: :center + image Organization::DIAPER_APP_LOGO, width: 75, vposition: :center, position: :right + end + end + end render end @@ -20,7 +132,7 @@ def request_data data = [["Items Requested", "Quantity", "", - "Differences/Comments"]] + "Differences / Comments"]] request = @requests.first request_items = request.request_items.map do |request_item| From 21cb97d15df18c6ee0643f7047e129c0805ab7b8 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sat, 17 Aug 2024 21:46:49 -0700 Subject: [PATCH 04/15] Add checkboxes --- app/pdfs/picklists_pdf.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index 9a54d43a7a..b2ae5d7a4a 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -98,7 +98,7 @@ def compute_and_render row(0).borders = [:bottom] row(0).border_width = 2 row(0).font_style = :bold - row(0).size = 9 + row(0).size = 10 row(0).column(1..-1).borders = %i(bottom left) end end @@ -131,7 +131,7 @@ def compute_and_render def request_data data = [["Items Requested", "Quantity", - "", + "[X]", "Differences / Comments"]] request = @requests.first @@ -142,7 +142,7 @@ def request_data data + request_items.map do |request_item| [request_item.item.name, request_item.quantity, - "", + "[ ]", ""] end end From a20ae721a21cd7f38848f75b8bf7bebe1bc1b0eb Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sat, 17 Aug 2024 22:51:19 -0700 Subject: [PATCH 05/15] Show units column if using custom units --- app/pdfs/picklists_pdf.rb | 41 ++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index b2ae5d7a4a..38e42826f9 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -82,14 +82,15 @@ def compute_and_render move_down 20 - data = request_data + items = build_items + data = custom_units ? data_with_units(items) : data_no_units(items) font_size 11 # Line item table table(data) do self.header = true - self.cell_style = { padding: [5, 20, 5, 20]} + self.cell_style = { padding: [5, 10, 5, 10]} self.row_colors = %w(dddddd ffffff) cells.borders = [] @@ -128,20 +129,42 @@ def compute_and_render render end - def request_data + def build_items + request = @requests.first + request_items = request.request_items.map do |request_item| + RequestItem.from_json(request_item, request) + end + end + + def custom_units + Flipper.enabled?(:enable_packs) && @request.item_requests.any? { |item| item.request_unit } + end + + def data_with_units(items) data = [["Items Requested", "Quantity", + "Unit (if applicable)", "[X]", "Differences / Comments"]] - request = @requests.first - request_items = request.request_items.map do |request_item| - RequestItem.from_json(request_item, request) + data + items.map do |i| + [i.item.name, + i.quantity, + i.unit&.capitalize&.pluralize(i.quantity), + "[ ]", + ""] end + end + + def data_no_units(items) + data = [["Items Requested", + "Quantity", + "[X]", + "Differences / Comments"]] - data + request_items.map do |request_item| - [request_item.item.name, - request_item.quantity, + data + items.map do |i| + [i.item.name, + i.quantity, "[ ]", ""] end From a193f67cd49124e2cae091f902b06423588e333b Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sun, 18 Aug 2024 00:30:30 -0700 Subject: [PATCH 06/15] Support multiple requests in one PDF --- app/controllers/requests_controller.rb | 6 +- app/pdfs/picklists_pdf.rb | 174 ++++++++++++------------- 2 files changed, 88 insertions(+), 92 deletions(-) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index 7871920b88..d0ecae0922 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -41,11 +41,11 @@ def start end def print_unfulfilled - @requests = Request.where(status: [0, 1]).limit(2) - # respond + requests = Request.includes(partner: [:profile], item_requests: [:item]).where(status: [0, 1]) + respond_to do |format| format.any do - pdf = PicklistsPdf.new(current_organization, @requests) + pdf = PicklistsPdf.new(current_organization, requests) send_data pdf.compute_and_render, filename: format("Picklists_%s.pdf", Time.current.to_fs(:long)), type: "application/pdf", diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index 38e42826f9..b786bca735 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -5,110 +5,108 @@ class PicklistsPdf def initialize(organization, requests) @requests = requests # does this need to be Request.includes(XXX).etc? Investigate. - @organization = organization - @request = @requests.first # temporary for single picklist only + @organization = organization# temporary for single picklist only end def compute_and_render font_families["OpenSans"] = PrawnRails.config["font_families"][:OpenSans] font "OpenSans" font_size 10 - - logo_image = if @organization.logo.attached? - StringIO.open(@organization.logo.download) - else - Organization::DIAPER_APP_LOGO - end - footer_height = 35 - # Bounding box containing non-footer elements - bounding_box [bounds.left, bounds.top], width: bounds.width, height: bounds.height - footer_height do - image logo_image, fit: [250, 85] - - bounding_box [bounds.right - 225, bounds.top], width: 225, height: 85 do - text @organization.name, align: :right - text @organization.address, align: :right - text @organization.email, align: :right - end + @requests.each do |request| + logo_image = if @organization.logo.attached? + StringIO.open(@organization.logo.download) + else + Organization::DIAPER_APP_LOGO + end + + # Bounding box containing non-footer elements + bounding_box [bounds.left, bounds.top], width: bounds.width, height: bounds.height - footer_height do + image logo_image, fit: [250, 85] + + bounding_box [bounds.right - 225, bounds.top], width: 225, height: 85 do + text @organization.name, align: :right + text @organization.address, align: :right + text @organization.email, align: :right + end - text "Requested by:", style: :bold - font_size 12 - text @request.partner.name - move_up 24 - - text "Partner Primary Contact:", style: :bold, align: :right - font_size 12 - text @request.partner.profile.primary_contact_name, align: :right - font_size 10 - text @request.partner.profile.primary_contact_email, align: :right - text @request.partner.profile.primary_contact_phone, align: :right - move_down 10 - - if @request.partner.profile.pick_up_name.present? - move_up 10 - text "Partner Pickup Person:", style: :bold + text "Requested by:", style: :bold font_size 12 - text @request.partner.profile.pick_up_name - font_size 10 - text @request.partner.profile.pick_up_email - text @request.partner.profile.pick_up_phone + text request.partner.name move_up 24 - text "Requested on:", style: :bold, align: :right + text "Partner Primary Contact:", style: :bold, align: :right font_size 12 - text @request.created_at.to_fs(:date_picker), align: :right + text request.partner.profile.primary_contact_name, align: :right font_size 10 - move_down 30 - else - text "Requested on:", style: :bold - font_size 12 - text @request.created_at.to_fs(:date_picker) - font_size 10 - end + text request.partner.profile.primary_contact_email, align: :right + text request.partner.profile.primary_contact_phone, align: :right + move_down 10 + + if request.partner.profile.pick_up_name.present? + move_up 10 + text "Partner Pickup Person:", style: :bold + font_size 12 + text request.partner.profile.pick_up_name + font_size 10 + text request.partner.profile.pick_up_email + text request.partner.profile.pick_up_phone + move_up 24 + + text "Requested on:", style: :bold, align: :right + font_size 12 + text request.created_at.to_fs(:date_picker), align: :right + font_size 10 + move_down 30 + else + text "Requested on:", style: :bold + font_size 12 + text request.created_at.to_fs(:date_picker) + font_size 10 + end - if @organization.ytd_on_distribution_printout - move_up 22 - text "Items Received Year-to-Date:", style: :bold, align: :right - font_size 12 - text @request.partner.quantity_year_to_date.to_s, align: :right - font_size 10 - end + if @organization.ytd_on_distribution_printout + move_up 22 + text "Items Received Year-to-Date:", style: :bold, align: :right + font_size 12 + text request.partner.quantity_year_to_date.to_s, align: :right + font_size 10 + end - move_down 10 - text "Comments:", style: :bold - font_size 12 - text @request.comments + move_down 10 + text "Comments:", style: :bold + font_size 12 + text request.comments - move_down 20 + move_down 20 - items = build_items - data = custom_units ? data_with_units(items) : data_no_units(items) + # items = build_items(request) + items = request.item_requests + data = has_custom_units?(request) ? data_with_units(items) : data_no_units(items) - font_size 11 + font_size 11 - # Line item table - table(data) do - self.header = true - self.cell_style = { padding: [5, 10, 5, 10]} - self.row_colors = %w(dddddd ffffff) + # Line item table + table(data) do + self.header = true + self.cell_style = { padding: [5, 10, 5, 10]} + self.row_colors = %w(dddddd ffffff) - cells.borders = [] + cells.borders = [] - # Header row - row(0).borders = [:bottom] - row(0).border_width = 2 - row(0).font_style = :bold - row(0).size = 10 - row(0).column(1..-1).borders = %i(bottom left) + # Header row + row(0).borders = [:bottom] + row(0).border_width = 2 + row(0).font_style = :bold + row(0).size = 10 + row(0).column(1..-1).borders = %i(bottom left) + end end + + start_new_page unless request == @requests.last end - number_pages "Page of ", - start_count_at: 1, - at: [bounds.right - 130, 22], - align: :right - repeat :all do # Page footer bounding_box [bounds.left, bounds.bottom + footer_height], width: bounds.width do @@ -126,18 +124,16 @@ def compute_and_render end end - render - end + number_pages "Page of ", + start_count_at: 1, + at: [bounds.right - 130, 22], + align: :right - def build_items - request = @requests.first - request_items = request.request_items.map do |request_item| - RequestItem.from_json(request_item, request) - end + render end - def custom_units - Flipper.enabled?(:enable_packs) && @request.item_requests.any? { |item| item.request_unit } + def has_custom_units?(request) + Flipper.enabled?(:enable_packs) && request.item_requests.any? { |item| item.request_unit } end def data_with_units(items) @@ -150,7 +146,7 @@ def data_with_units(items) data + items.map do |i| [i.item.name, i.quantity, - i.unit&.capitalize&.pluralize(i.quantity), + i.request_unit&.capitalize&.pluralize(i.quantity), "[ ]", ""] end From 9cf8a8841616e89031810266d32d6c747ecd2662 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Thu, 29 Aug 2024 12:33:50 -0700 Subject: [PATCH 07/15] Replace Request.item_requests with RequestItem instead --- app/controllers/requests_controller.rb | 2 +- app/pdfs/picklists_pdf.rb | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index d0ecae0922..f4edb65a2e 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -41,7 +41,7 @@ def start end def print_unfulfilled - requests = Request.includes(partner: [:profile], item_requests: [:item]).where(status: [0, 1]) + requests = Request.includes(partner: [:profile]).where(status: [0, 1]) respond_to do |format| format.any do diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index b786bca735..172c570d69 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -81,9 +81,10 @@ def compute_and_render move_down 20 - # items = build_items(request) - items = request.item_requests - data = has_custom_units?(request) ? data_with_units(items) : data_no_units(items) + items = request.request_items.map do |request_item| + RequestItem.from_json(request_item, request) + end + data = has_custom_units?(items) ? data_with_units(items) : data_no_units(items) font_size 11 @@ -132,8 +133,8 @@ def compute_and_render render end - def has_custom_units?(request) - Flipper.enabled?(:enable_packs) && request.item_requests.any? { |item| item.request_unit } + def has_custom_units?(items) + Flipper.enabled?(:enable_packs) && items.any? { |item| item.unit } end def data_with_units(items) @@ -146,7 +147,7 @@ def data_with_units(items) data + items.map do |i| [i.item.name, i.quantity, - i.request_unit&.capitalize&.pluralize(i.quantity), + i.unit&.capitalize&.pluralize(i.quantity), "[ ]", ""] end From 7ddcfec94b05bd4b64b209a849bbf6e063291800 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Thu, 29 Aug 2024 12:55:59 -0700 Subject: [PATCH 08/15] Add fixed width for table and quantity and checkbox columns --- app/pdfs/picklists_pdf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index 172c570d69..b6c2b74b66 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -89,7 +89,7 @@ def compute_and_render font_size 11 # Line item table - table(data) do + table(data, :width => bounds.width, :column_widths => { 1 => 65, -2 => 35 }) do self.header = true self.cell_style = { padding: [5, 10, 5, 10]} self.row_colors = %w(dddddd ffffff) From 409df7e8d345c2db7e0aabe82a33feb68d4c6b29 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sun, 18 Aug 2024 00:39:24 -0700 Subject: [PATCH 09/15] lint --- app/pdfs/picklists_pdf.rb | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index b6c2b74b66..a7bd84e438 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -4,8 +4,8 @@ class PicklistsPdf include ItemsHelper def initialize(organization, requests) - @requests = requests # does this need to be Request.includes(XXX).etc? Investigate. - @organization = organization# temporary for single picklist only + @requests = requests + @organization = organization end def compute_and_render @@ -16,10 +16,10 @@ def compute_and_render @requests.each do |request| logo_image = if @organization.logo.attached? - StringIO.open(@organization.logo.download) - else - Organization::DIAPER_APP_LOGO - end + StringIO.open(@organization.logo.download) + else + Organization::DIAPER_APP_LOGO + end # Bounding box containing non-footer elements bounding_box [bounds.left, bounds.top], width: bounds.width, height: bounds.height - footer_height do @@ -89,10 +89,10 @@ def compute_and_render font_size 11 # Line item table - table(data, :width => bounds.width, :column_widths => { 1 => 65, -2 => 35 }) do + table(data, width: bounds.width, column_widths: {1 => 65, -2 => 35}) do self.header = true - self.cell_style = { padding: [5, 10, 5, 10]} - self.row_colors = %w(dddddd ffffff) + self.cell_style = {padding: [5, 10, 5, 10]} + self.row_colors = %w[dddddd ffffff] cells.borders = [] @@ -101,7 +101,7 @@ def compute_and_render row(0).border_width = 2 row(0).font_style = :bold row(0).size = 10 - row(0).column(1..-1).borders = %i(bottom left) + row(0).column(1..-1).borders = %i[bottom left] end end @@ -126,9 +126,9 @@ def compute_and_render end number_pages "Page of ", - start_count_at: 1, - at: [bounds.right - 130, 22], - align: :right + start_count_at: 1, + at: [bounds.right - 130, 22], + align: :right render end @@ -167,5 +167,3 @@ def data_no_units(items) end end end - - From a12d0c97d88bd0a99cb6e142b85515a50a74749b Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Wed, 11 Sep 2024 23:46:38 -0700 Subject: [PATCH 10/15] Display unfulfilled count in button --- app/controllers/requests_controller.rb | 2 +- app/views/requests/index.html.erb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index f4edb65a2e..565ce1b751 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -8,7 +8,7 @@ def index .undiscarded .during(helpers.selected_range) .class_filter(filter_params) - + @unfulfilled_requests = current_organization.requests.where(status: [:pending, :started]) @paginated_requests = @requests.page(params[:page]) @calculate_product_totals = RequestsTotalItemsService.new(requests: @requests).calculate @items = current_organization.items.alphabetized diff --git a/app/views/requests/index.html.erb b/app/views/requests/index.html.erb index 0f923245f9..b1644cefc5 100644 --- a/app/views/requests/index.html.erb +++ b/app/views/requests/index.html.erb @@ -61,10 +61,10 @@ <%= clear_filter_button %> <%= modal_button_to("#calculateTotals", {text: "Calculate Product Totals", icon: nil, size: "md", type: "success"}) %> - <% if @requests.any? { |request| request.status == "pending" || request.status == "started" } %> + <% if @unfulfilled_requests.exists? %> <%= print_button_to( print_unfulfilled_requests_path(format: :pdf), - text: "Print Unfulfilled Picklists", + text: "Print Unfulfilled Picklists (#{@unfulfilled_requests.size})", size: "md") %> <% end %> <%= download_button_to(requests_path(format: :csv, filters: filter_params.merge(date_range: date_range_params)), {text: "Export Requests", size: "md"}) if @requests.any? %> From 468593829ebd3c74b59729768ab4e71b271c22a7 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Thu, 12 Sep 2024 00:01:29 -0700 Subject: [PATCH 11/15] Scope query to org and use item_requests instead of request_items --- app/controllers/requests_controller.rb | 6 +++++- app/pdfs/picklists_pdf.rb | 16 +++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index 565ce1b751..7b12f4c83c 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -41,7 +41,11 @@ def start end def print_unfulfilled - requests = Request.includes(partner: [:profile]).where(status: [0, 1]) + requests = current_organization + .requests + .includes(:item_requests, partner: [:profile]) + .where(status: [:pending, :started]) + .order(created_at: :desc) respond_to do |format| format.any do diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index a7bd84e438..7bb2d55176 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -81,9 +81,7 @@ def compute_and_render move_down 20 - items = request.request_items.map do |request_item| - RequestItem.from_json(request_item, request) - end + items = request.item_requests data = has_custom_units?(items) ? data_with_units(items) : data_no_units(items) font_size 11 @@ -134,7 +132,7 @@ def compute_and_render end def has_custom_units?(items) - Flipper.enabled?(:enable_packs) && items.any? { |item| item.unit } + Flipper.enabled?(:enable_packs) && items.any? { |item| item.request_unit } end def data_with_units(items) @@ -145,9 +143,11 @@ def data_with_units(items) "Differences / Comments"]] data + items.map do |i| - [i.item.name, + item_name = Item.find(i.item_id).name + + [item_name, i.quantity, - i.unit&.capitalize&.pluralize(i.quantity), + i.request_unit&.capitalize&.pluralize(i.quantity), "[ ]", ""] end @@ -160,7 +160,9 @@ def data_no_units(items) "Differences / Comments"]] data + items.map do |i| - [i.item.name, + item_name = Item.find(i.item_id).name + + [item_name, i.quantity, "[ ]", ""] From a09facb96657f9886eb2f3bb1ad75f63ccd7aa77 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sun, 22 Sep 2024 10:38:19 -0700 Subject: [PATCH 12/15] Clarify using line_items instead of actual items --- app/pdfs/picklists_pdf.rb | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index 7bb2d55176..605f781b39 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -81,8 +81,8 @@ def compute_and_render move_down 20 - items = request.item_requests - data = has_custom_units?(items) ? data_with_units(items) : data_no_units(items) + line_items = request.item_requests + data = has_custom_units?(line_items) ? data_with_units(line_items) : data_no_units(line_items) font_size 11 @@ -131,39 +131,39 @@ def compute_and_render render end - def has_custom_units?(items) - Flipper.enabled?(:enable_packs) && items.any? { |item| item.request_unit } + def has_custom_units?(line_items) + Flipper.enabled?(:enable_packs) && line_items.any? { |line_item| line_item.request_unit } end - def data_with_units(items) + def data_with_units(line_items) data = [["Items Requested", "Quantity", "Unit (if applicable)", "[X]", "Differences / Comments"]] - data + items.map do |i| - item_name = Item.find(i.item_id).name + data + line_items.map do |line_item| + item_name = Item.find(line_item.item_id).name [item_name, - i.quantity, - i.request_unit&.capitalize&.pluralize(i.quantity), + line_item.quantity, + line_item.request_unit&.capitalize&.pluralize(line_item.quantity), "[ ]", ""] end end - def data_no_units(items) + def data_no_units(line_items) data = [["Items Requested", "Quantity", "[X]", "Differences / Comments"]] - data + items.map do |i| - item_name = Item.find(i.item_id).name + data + line_items.map do |line_item| + item_name = Item.find(line_item.item_id).name [item_name, - i.quantity, + line_item.quantity, "[ ]", ""] end From 71b84d7c505130ff7f67eaf4de9aff8f0c5c49d0 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sun, 22 Sep 2024 10:41:02 -0700 Subject: [PATCH 13/15] Remove finding item by id because there are associations --- app/pdfs/picklists_pdf.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/pdfs/picklists_pdf.rb b/app/pdfs/picklists_pdf.rb index 605f781b39..20022c2dc0 100644 --- a/app/pdfs/picklists_pdf.rb +++ b/app/pdfs/picklists_pdf.rb @@ -143,9 +143,7 @@ def data_with_units(line_items) "Differences / Comments"]] data + line_items.map do |line_item| - item_name = Item.find(line_item.item_id).name - - [item_name, + [line_item.name, line_item.quantity, line_item.request_unit&.capitalize&.pluralize(line_item.quantity), "[ ]", @@ -160,9 +158,7 @@ def data_no_units(line_items) "Differences / Comments"]] data + line_items.map do |line_item| - item_name = Item.find(line_item.item_id).name - - [item_name, + [line_item.name, line_item.quantity, "[ ]", ""] From a643e2a56cfbee7f150e97d9bf0e192c50f6968f Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Sun, 22 Sep 2024 12:45:08 -0700 Subject: [PATCH 14/15] Replace exists? with check for count --- app/controllers/requests_controller.rb | 2 +- app/views/requests/index.html.erb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/requests_controller.rb b/app/controllers/requests_controller.rb index 7b12f4c83c..93247275a8 100644 --- a/app/controllers/requests_controller.rb +++ b/app/controllers/requests_controller.rb @@ -8,7 +8,7 @@ def index .undiscarded .during(helpers.selected_range) .class_filter(filter_params) - @unfulfilled_requests = current_organization.requests.where(status: [:pending, :started]) + @unfulfilled_requests_count = current_organization.requests.where(status: [:pending, :started]).count @paginated_requests = @requests.page(params[:page]) @calculate_product_totals = RequestsTotalItemsService.new(requests: @requests).calculate @items = current_organization.items.alphabetized diff --git a/app/views/requests/index.html.erb b/app/views/requests/index.html.erb index b1644cefc5..ef44ea0d3f 100644 --- a/app/views/requests/index.html.erb +++ b/app/views/requests/index.html.erb @@ -61,10 +61,10 @@ <%= clear_filter_button %> <%= modal_button_to("#calculateTotals", {text: "Calculate Product Totals", icon: nil, size: "md", type: "success"}) %> - <% if @unfulfilled_requests.exists? %> + <% if @unfulfilled_requests_count > 0 %> <%= print_button_to( print_unfulfilled_requests_path(format: :pdf), - text: "Print Unfulfilled Picklists (#{@unfulfilled_requests.size})", + text: "Print Unfulfilled Picklists (#{@unfulfilled_requests_count})", size: "md") %> <% end %> <%= download_button_to(requests_path(format: :csv, filters: filter_params.merge(date_range: date_range_params)), {text: "Export Requests", size: "md"}) if @requests.any? %> From a537810306e64ba854b8655fc25c11aed117d958 Mon Sep 17 00:00:00 2001 From: Norris Mei Date: Mon, 23 Sep 2024 23:19:21 -0700 Subject: [PATCH 15/15] Add unit tests for PDF and index page --- spec/factories/partners.rb | 11 +++- spec/factories/partners/profiles.rb | 6 ++ spec/factories/requests.rb | 4 ++ spec/pdfs/picklists_pdf_spec.rb | 84 +++++++++++++++++++++++++ spec/requests/requests_requests_spec.rb | 15 +++++ 5 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 spec/pdfs/picklists_pdf_spec.rb diff --git a/spec/factories/partners.rb b/spec/factories/partners.rb index ba34f27bbe..d73d02be5a 100644 --- a/spec/factories/partners.rb +++ b/spec/factories/partners.rb @@ -40,11 +40,20 @@ status { :awaiting_review } end + transient do + pick_up_person { false } + end + after(:create) do |partner, evaluator| next if evaluator.try(:without_profile) # Create associated records - create(:partner_profile, partner_id: partner.id) + if evaluator.pick_up_person + create(:partner_profile, :with_pickup_person, partner_id: partner.id) + else + create(:partner_profile, partner_id: partner.id) + end + create(:partner_user, email: partner.email, name: partner.name, partner: partner) end end diff --git a/spec/factories/partners/profiles.rb b/spec/factories/partners/profiles.rb index 7b2e3f3500..5d2486a123 100644 --- a/spec/factories/partners/profiles.rb +++ b/spec/factories/partners/profiles.rb @@ -86,5 +86,11 @@ website { "http://some-site.org" } primary_contact_email { Faker::Internet.email } primary_contact_name { Faker::Name.name } + + trait :with_pickup_person do + pick_up_name { "Paul Bunyan" } + pick_up_email { "paul@kenton.com" } + pick_up_phone { "503-123-4567" } + end end end diff --git a/spec/factories/requests.rb b/spec/factories/requests.rb index d8cdc20594..987527a7da 100644 --- a/spec/factories/requests.rb +++ b/spec/factories/requests.rb @@ -61,6 +61,10 @@ def random_request_items status { 'pending' } end + trait :discarded do + status { 'discarded' } + end + trait :with_varied_quantities do request_items { # get 10 unique item ids diff --git a/spec/pdfs/picklists_pdf_spec.rb b/spec/pdfs/picklists_pdf_spec.rb new file mode 100644 index 0000000000..a9f7481343 --- /dev/null +++ b/spec/pdfs/picklists_pdf_spec.rb @@ -0,0 +1,84 @@ +describe PicklistsPdf do + let(:organization) { create(:organization) } + let(:item1) { create(:item, name: "Item 1", organization: organization) } + let(:item2) { create(:item, name: "Item 2", organization: organization) } + + describe "#compute_and_render" do + it "renders multiple requests correctly" do + request1 = create(:request, :pending, organization: organization) + request2 = create(:request, :pending, organization: organization) + create(:item_request, request: request1, item: item1, name: "Item 1") + create(:item_request, request: request2, item: item2, name: "Item 2") + + pdf = described_class.new(organization, [request1, request2]) + pdf_test = PDF::Reader.new(StringIO.new(pdf.compute_and_render)) + + expect(pdf_test.page(1).text).to include(request1.partner.name) + expect(pdf_test.page(1).text).to include(request1.partner.profile.primary_contact_name) + expect(pdf_test.page(1).text).to include(request1.partner.profile.primary_contact_email) + 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("Items Requested") + expect(pdf_test.page(1).text).to include("Item 1") + + expect(pdf_test.page(2).text).to include(request2.partner.name) + expect(pdf_test.page(2).text).to include(request2.partner.profile.primary_contact_name) + expect(pdf_test.page(2).text).to include(request2.partner.profile.primary_contact_email) + 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("Items Requested") + expect(pdf_test.page(2).text).to include("Item 2") + end + + context "When partner pickup person is set" do + it "renders pickup person details" do + partner = create(:partner, pick_up_person: true) + request = create(:request, :pending, organization: organization, partner: partner) + 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(request.partner.profile.pick_up_name) + expect(pdf_test.page(1).text).to include(request.partner.profile.pick_up_email) + expect(pdf_test.page(1).text).to include(request.partner.profile.pick_up_phone) + end + end + end + + context "When packs are not enabled" do + specify "#data_no_units" do + request = create(:request, :pending, organization: organization) + create(:item_request, request: request, item: item1, name: "Item 1") + create(:item_request, request: request, item: item2, name: "Item 2") + pdf = described_class.new(organization, [request]) + data = pdf.data_no_units(request.item_requests) + + expect(data).to eq([ + ["Items Requested", "Quantity", "[X]", "Differences / Comments"], + ["Item 1", "5", "[ ]", ""], + ["Item 2", "5", "[ ]", ""] + ]) + end + end + + context "When packs are enabled" do + before { Flipper.enable(:enable_packs) } + + specify "#data_with_units" do + item_with_units = create(:item, name: "Item with units", organization: organization) + create(:item_unit, item: item_with_units, name: "Pack") + request = create(:request, :pending, organization: organization) + create(:item_request, request: request, item: item_with_units, name: "Item with units", request_unit: "Pack") + create(:item_request, request: request, item: item2, name: "Item 2") + pdf = described_class.new(organization, [request]) + data = pdf.data_with_units(request.item_requests) + + expect(data).to eq([ + ["Items Requested", "Quantity", "Unit (if applicable)", "[X]", "Differences / Comments"], + ["Item with units", "5", "Packs", "[ ]", ""], + ["Item 2", "5", nil, "[ ]", ""] + ]) + end + end +end diff --git a/spec/requests/requests_requests_spec.rb b/spec/requests/requests_requests_spec.rb index cc891607a6..6ff8095bfc 100644 --- a/spec/requests/requests_requests_spec.rb +++ b/spec/requests/requests_requests_spec.rb @@ -26,6 +26,21 @@ it { is_expected.to be_successful } end + + context "when there are pending or started requests" do + it "shows print unfulfilled picklists button with correct quantity" do + Request.delete_all + + create(:request, :pending) + create(:request, :started) + create(:request, :fulfilled) + create(:request, :discarded) + + get requests_path + + expect(response.body).to include('Print Unfulfilled Picklists (2)') + end + end end describe 'GET #show' do