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

Sends invoice to email #262

Merged
merged 2 commits into from
Apr 18, 2022
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
12 changes: 12 additions & 0 deletions app/controllers/internal_api/v1/invoices_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ def update
}
end

def send_invoice
authorize invoice

invoice.send_to_email(subject: invoice_email_params[:subject], recipients: invoice_email_params[:recipients])

render json: { message: "Invoice will be sent!" }, status: :accepted
end

private

def load_client
Expand All @@ -58,4 +66,8 @@ def invoice_params
policy(Invoice).permitted_attributes
)
end

def invoice_email_params
params.require(:invoice_email).permit(:subject, :body, recipients: [])
end
end
13 changes: 13 additions & 0 deletions app/mailers/invoice_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class InvoiceMailer < ApplicationMailer
after_action -> { @invoice.sent! }

def invoice
@invoice = params[:invoice]
recipients = params[:recipients]
subject = params[:subject]

mail(to: recipients, subject:)
end
end
9 changes: 9 additions & 0 deletions app/models/concerns/invoice_sendable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module InvoiceSendable
extend ActiveSupport::Concern

def send_to_email(subject:, recipients:)
InvoiceMailer.with(invoice: self, subject:, recipients:).invoice.deliver_later
end
end
2 changes: 2 additions & 0 deletions app/models/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
# frozen_string_literal: true

class Invoice < ApplicationRecord
include InvoiceSendable

attr_accessor :sub_total

enum status: [
Expand Down
4 changes: 4 additions & 0 deletions app/policies/invoice_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ def show?
user_owner_or_admin?
end

def send_invoice?
user_owner_or_admin?
end

def permitted_attributes
[
:issue_date, :due_date,
Expand Down
19 changes: 19 additions & 0 deletions app/views/invoice_mailer/invoice.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
</head>
<body>
<h1>Invoice: <%= @invoice.invoice_number %></h1>

<p>
Hi <%= @invoice.client_name %>, You have an invoice with amount <%= @invoice.amount %>.
</p>

<p>
The due date is <%= @invoice.due_date %>.
</p>

<p>Thanks!</p>
</body>
</html>
8 changes: 8 additions & 0 deletions app/views/invoice_mailer/invoice.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Hi, <%= @invoice.client_name %>
===============================================

You have an invoice - <%= @invoice.invoice_number %> with amount <%= @invoice.amount %>
due date is: <%= @invoice.due_date %>.

Thanks!
Miru
2 changes: 2 additions & 0 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test

config.active_job.queue_adapter = :test

# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr

Expand Down
4 changes: 3 additions & 1 deletion config/routes/internal_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
resources :timesheet_entry, only: [:index, :create, :update, :destroy]
resources :reports, only: [:index]
resources :workspaces, only: [:update]
resources :invoices, only: [:index, :create, :update]
resources :invoices, only: [:index, :create, :update] do
post :send_invoice, on: :member
end
resources :generate_invoice, only: [:index, :show]
end
end
22 changes: 22 additions & 0 deletions spec/mailers/invoice_mailer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe InvoiceMailer, type: :mailer do
describe "invoice" do
let(:invoice) { create :invoice }
let(:recipients) { [invoice.client.email, "miru@example.com"] }
let(:subject) { "Invoice (#{invoice.invoice_number}) due on #{invoice.due_date}" }
let(:mail) { InvoiceMailer.with(invoice:, subject:, recipients:).invoice }

it "renders the headers" do
expect(mail.subject).to eq(subject)
expect(mail.to).to eq(recipients)
expect(mail.from).to eq(["from@example.com"])
end

it "renders the body" do
expect(mail.body.encoded).to match("You have an invoice")
end
end
end
13 changes: 13 additions & 0 deletions spec/mailers/previews/invoice_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

# Preview all emails at http://localhost:3000/rails/mailers/invoice

class InvoicePreview < ActionMailer::Preview
def invoice
invoice = Invoice.first
recipients = [invoice.client.email, "miru@example.com"]
subject = "Invoice (#{invoice.invoice_number}) due on #{invoice.due_date}"

InvoiceMailer.with(invoice:, recipients:, subject:).invoice
end
end
10 changes: 10 additions & 0 deletions spec/models/invoice_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,14 @@
describe ".delegate" do
it { is_expected.to delegate_method(:name).to(:client).with_prefix(:client) }
end

describe ".send_to_email" do
let(:invoice) { create :invoice }
let(:recipients) { [invoice.client.email, "miru@example.com"] }
let(:subject) { "Invoice (#{invoice.invoice_number}) due on #{invoice.due_date}" }

it "sends the invoice on email" do
expect { invoice.send_to_email(subject:, recipients:) }.to have_enqueued_mail(InvoiceMailer, :invoice)
end
end
end
71 changes: 71 additions & 0 deletions spec/requests/internal_api/v1/invoices/send_invoice_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe "InternalApi::V1::Invoices#send_invoice", type: :request do
let(:client) { create :client_with_invoices }
let(:company) { client.company }
let(:invoice) { client.invoices.first }
let(:user) { create :user, current_workspace_id: company.id }

context "when user is signed in" do
before do
create(:company_user, company:, user:)
end

let(:invoice_email) do
{ subject: "Some Subject", recipients: [client.email, "miru@example.com"], body: "You have an invoice!" }
end

context "when user is an admin" do
before do
user.add_role :admin, company
sign_in user
end

it "returns a 202 response" do
post send_invoice_internal_api_v1_invoice_path(id: invoice.id), params: { invoice_email: }

expect(response).to have_http_status :accepted
expect(json_response["message"]).to eq("Invoice will be sent!")
end

it "enqueues an email for delivery" do
expect do
post send_invoice_internal_api_v1_invoice_path(id: invoice.id), params: { invoice_email: }
end.to have_enqueued_mail(InvoiceMailer, :invoice)
end

context "when invoice doesn't exist" do
it "returns 404 response" do
post send_invoice_internal_api_v1_invoice_path(id: "random")

expect(response).to have_http_status :not_found
expect(json_response["errors"]).to eq "Couldn't find Invoice with 'id'=random"
end
end
end

context "when user is an employee" do
before do
user.add_role :employee, company
sign_in user
end

it "returns a 403 response" do
post send_invoice_internal_api_v1_invoice_path(id: invoice.id)

expect(response).to have_http_status(:forbidden)
end
end
end

context "when user is logged out" do
it "returns a 401 response" do
post send_invoice_internal_api_v1_invoice_path(id: invoice.id)

expect(response).to have_http_status(:unauthorized)
expect(json_response["error"]).to eq("You need to sign in or sign up before continuing.")
end
end
end
22 changes: 22 additions & 0 deletions spec/support/patch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

# This patches rspec-rails to support rails 7.0 https://github.com/rspec/rspec-rails/issues/2531
module RSpec
module Rails
module Matchers
class HaveEnqueuedMail
def legacy_mail?(job)
defined?(ActionMailer::DeliveryJob) && job[:job] <= ActionMailer::DeliveryJob
end

def parameterized_mail?(job)
RSpec::Rails::FeatureCheck.has_action_mailer_parameterized? && job[:job] <= ActionMailer::MailDeliveryJob
end

def unified_mail?(job)
RSpec::Rails::FeatureCheck.has_action_mailer_unified_delivery? && job[:job] <= ActionMailer::MailDeliveryJob
end
end
end
end
end