diff --git a/app/assets/javascripts/admin/orders/controllers/bulk_invoice_controller.js.coffee b/app/assets/javascripts/admin/orders/controllers/bulk_invoice_controller.js.coffee deleted file mode 100644 index cd6a02d40b..0000000000 --- a/app/assets/javascripts/admin/orders/controllers/bulk_invoice_controller.js.coffee +++ /dev/null @@ -1,32 +0,0 @@ -angular.module("admin.orders").controller "bulkInvoiceCtrl", ($scope, $http, $timeout) -> - $scope.createBulkInvoice = -> - $scope.invoice_id = null - $scope.poll = 1 - $scope.loading = true - $scope.message = null - $scope.error = null - $scope.poll_wait = 5 # 5 Seconds between each check - $scope.poll_retries = 80 # Maximum checks before stopping - - $http.post('/admin/orders/invoices', {order_ids: $scope.selected_orders}).then (response) -> - $scope.invoice_id = response.data - $scope.pollBulkInvoice() - - $scope.pollBulkInvoice = -> - $timeout($scope.nextPoll, $scope.poll_wait * 1000) - - $scope.nextPoll = -> - $http.get('/admin/orders/invoices/'+$scope.invoice_id+'/poll').then (response) -> - $scope.loading = false - $scope.message = t('js.admin.orders.index.bulk_invoice_created') - - .catch (response) -> - $scope.poll++ - - if $scope.poll > $scope.poll_retries - $scope.loading = false - $scope.error = t('js.admin.orders.index.bulk_invoice_failed') - return - - $scope.pollBulkInvoice() - diff --git a/app/assets/javascripts/admin/orders/directives/invoices_modal.js.coffee b/app/assets/javascripts/admin/orders/directives/invoices_modal.js.coffee deleted file mode 100644 index 0f2eabe778..0000000000 --- a/app/assets/javascripts/admin/orders/directives/invoices_modal.js.coffee +++ /dev/null @@ -1,5 +0,0 @@ -angular.module("admin.orders").directive "invoicesModal", ($modal) -> - restrict: 'C' - link: (scope, elem, attrs, ctrl) -> - elem.on "click", (ev) => - scope.uploadModal = $modal.open(templateUrl: 'admin/modals/bulk_invoice.html', controller: ctrl, scope: scope, windowClass: 'simple-modal') diff --git a/app/channels/session_channel.rb b/app/channels/session_channel.rb new file mode 100644 index 0000000000..ea42d56641 --- /dev/null +++ b/app/channels/session_channel.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class SessionChannel < ApplicationCable::Channel + def self.for_request(request) + "SessionChannel:#{request.session.id}" + end + + def subscribed + return reject if current_user.nil? + + stream_from "SessionChannel:#{session_id}" + end +end + diff --git a/app/jobs/bulk_invoice_job.rb b/app/jobs/bulk_invoice_job.rb index 0957ef393a..324554733d 100644 --- a/app/jobs/bulk_invoice_job.rb +++ b/app/jobs/bulk_invoice_job.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true class BulkInvoiceJob < ApplicationJob - def perform(order_ids, filepath) + include CableReady::Broadcaster + delegate :render, to: ActionController::Base + + def perform(order_ids, filepath, options = {}) pdf = CombinePDF.new sorted_orders(order_ids).each do |order| @@ -11,6 +14,8 @@ class BulkInvoiceJob < ApplicationJob end pdf.save filepath + + broadcast(filepath, options[:channel]) if options[:channel] end private @@ -18,10 +23,22 @@ class BulkInvoiceJob < ApplicationJob # Ensures the records are returned in the same order the ids were originally given in def sorted_orders(order_ids) orders_by_id = Spree::Order.where(id: order_ids).to_a.index_by(&:id) - order_ids.map { |id| orders_by_id[id] } + order_ids.map { |id| orders_by_id[id.to_i] } end def renderer @renderer ||= InvoiceRenderer.new end + + def broadcast(filepath, channel) + file_id = filepath.split("/").last.split(".").first + + cable_ready[channel]. + inner_html( + selector: "#bulk_invoices_modal .modal-content", + html: render(partial: "spree/admin/orders/bulk/invoice_link", + locals: { invoice_url: "/admin/orders/invoices/#{file_id}" }) + ). + broadcast + end end diff --git a/app/reflexes/admin/orders_reflex.rb b/app/reflexes/admin/orders_reflex.rb index 5e03440c72..6f300c82a2 100644 --- a/app/reflexes/admin/orders_reflex.rb +++ b/app/reflexes/admin/orders_reflex.rb @@ -25,6 +25,21 @@ class Admin::OrdersReflex < ApplicationReflex end end + def bulk_invoice(params) + cable_ready.append( + selector: "#orders-index", + html: render(partial: "spree/admin/orders/bulk/invoice_modal") + ).broadcast + + BulkInvoiceJob.perform_later( + params[:order_ids], + "tmp/invoices/#{Time.zone.now.to_i}-#{SecureRandom.hex(2)}.pdf", + channel: SessionChannel.for_request(request) + ) + + morph :nothing + end + private def authorize_order diff --git a/app/views/spree/admin/orders/_bulk_actions.html.haml b/app/views/spree/admin/orders/_bulk_actions.html.haml index bdbfdd466a..cea049867c 100644 --- a/app/views/spree/admin/orders/_bulk_actions.html.haml +++ b/app/views/spree/admin/orders/_bulk_actions.html.haml @@ -13,7 +13,7 @@ %span.name{ "data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "send_invoice" } = t('spree.admin.orders.index.send_invoice') %div.menu_item - %span.name.invoices-modal{'ng-controller' => 'bulkInvoiceCtrl', 'ng-click' => 'createBulkInvoice()' } + %span.name{ "data-controller": "bulk-invoice", "data-action": "click->bulk-invoice#generate" } = t('spree.admin.orders.index.print_invoices') %div.menu_item %span.name{ "data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "cancel_orders" } diff --git a/app/views/spree/admin/orders/bulk/_invoice_link.html.haml b/app/views/spree/admin/orders/bulk/_invoice_link.html.haml new file mode 100644 index 0000000000..dbc5c455d5 --- /dev/null +++ b/app/views/spree/admin/orders/bulk/_invoice_link.html.haml @@ -0,0 +1,7 @@ +%p.message + = t('js.admin.orders.index.bulk_invoice_created') + +%br + +%a.button.primary{ target: '_blank', href: invoice_url } + = t('js.admin.orders.index.view_file') diff --git a/app/views/spree/admin/orders/bulk/_invoice_modal.html.haml b/app/views/spree/admin/orders/bulk/_invoice_modal.html.haml new file mode 100644 index 0000000000..07c2f30121 --- /dev/null +++ b/app/views/spree/admin/orders/bulk/_invoice_modal.html.haml @@ -0,0 +1,15 @@ +%div{ id: "bulk_invoices_modal", "data-controller": "modal", "data-modal-instant-value": true, "data-action": "keyup@document->modal#closeIfEscapeKey" } + .reveal-modal-bg.fade{ "data-modal-target": "background", "data-action": "click->modal#remove" } + .reveal-modal.fade.tiny.help-modal{ "data-modal-target": "modal" } + %div.fullwidth.align-center + %h4.modal-title + = t('js.admin.orders.index.compiling_invoices') + %br + %br + .modal-content + .modal-loading + %img.spinner{ src: image_path("/spinning-circles.svg") } + %br + %br + %p= t('js.admin.orders.index.please_wait') + %br diff --git a/app/webpacker/channels/session_channel.js b/app/webpacker/channels/session_channel.js new file mode 100644 index 0000000000..d43acef462 --- /dev/null +++ b/app/webpacker/channels/session_channel.js @@ -0,0 +1,8 @@ +import consumer from './consumer' +import CableReady from 'cable_ready' + +consumer.subscriptions.create("SessionChannel", { + received(data) { + if (data.cableReady) CableReady.perform(data.operations) + } +}); diff --git a/app/webpacker/controllers/bulk_invoice_controller.js b/app/webpacker/controllers/bulk_invoice_controller.js new file mode 100644 index 0000000000..aebe57565c --- /dev/null +++ b/app/webpacker/controllers/bulk_invoice_controller.js @@ -0,0 +1,11 @@ +import BulkActionsController from "./bulk_actions_controller"; + +export default class extends BulkActionsController { + connect() { + super.connect(); + } + + generate() { + this.stimulate("Admin::OrdersReflex#bulk_invoice", { order_ids: super.getOrdersIds() }); + } +}