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

[ FEAT ] Cobrança mensal da assinatura Premium #238

Merged
merged 8 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 0 additions & 1 deletion app/controllers/projects_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
class ProjectsController < ApplicationController
before_action :authenticate_user!
before_action :authenticate_subscriber, only: :create_invitation_request

def index
@invitation_request = current_user.invitation_requests.build
@invitation_requests = current_user.invitation_requests.pluck(:project_id).to_json
Expand Down
15 changes: 15 additions & 0 deletions app/jobs/notify_billing_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class NotifyBillingJob < ApplicationJob
queue_as :default

before_perform do |job|
current_billing = job.arguments.first
next_billing = current_billing.subscription.billings.create!(
billing_date: current_billing.billing_date + 1.month, amount: 19.90
)
self.class.set(wait_until: next_billing.billing_date.to_datetime).perform_later(next_billing)
end

def perform(billing)
BillingsMailer.with(billing:).notify_billing.deliver
end
end
10 changes: 10 additions & 0 deletions app/mailers/billings_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class BillingsMailer < ApplicationMailer
default from: '[email protected]'

def notify_billing
@billing = params[:billing]
@user = @billing.subscription.user

mail(subject: default_i18n_subject, to: @user.email)
end
end
3 changes: 3 additions & 0 deletions app/models/billing.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Billing < ApplicationRecord
belongs_to :subscription
end
20 changes: 20 additions & 0 deletions app/models/subscription.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
class Subscription < ApplicationRecord
SUBSCRIPTION_AMOUNT = 19.90

belongs_to :user
has_many :billings, dependent: :destroy

enum status: { inactive: 0, active: 10 }

after_update :create_billing, if: :active? && :saved_change_to_status?

def active!
self.start_date = Time.zone.now.to_date
super
Expand All @@ -11,4 +17,18 @@ def inactive!
self.start_date = nil
super
end

private

def create_billing
return if start_date.nil?

billing_date = if start_date.day < 29
start_date + 1.month
else
start_date.next_month.beginning_of_month + 1.month
end

billings.create(billing_date:, amount: SUBSCRIPTION_AMOUNT)
end
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class User < ApplicationRecord
has_many :professional_infos, through: :profile
has_many :education_infos, through: :profile
has_many :invitation_requests, through: :profile
has_one :subscription, dependent: :destroy

enum role: { user: 0, admin: 10 }

Expand Down
9 changes: 9 additions & 0 deletions app/views/billings_mailer/notify_billing.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<h3><%= t('.greeting', recipient: @user.full_name)%></h3>

<p><%= t('.reminder')%></p>

<p><%= t('.call_to_action')%></p>

<p><%= t('.due_date', due_date: I18n.l(@billing.billing_date)) %></p>

<p><%= t('.amount', amount: number_to_currency(@billing.amount)) %></p>
18 changes: 18 additions & 0 deletions config/locales/models/billings.pt-BR.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pt-BR:
activerecord:
models:
billings:
one: Cobrança
other: Cobranças
attributes:
billings:
billing_date: Data de Cobrança
amount: Valor
billings_mailer:
notify_billing:
subject: Porfoliorrr - Assinatura mensal
greeting: Olá, %{recipient}!
reminder: Sua assinatura mensal do Porfoliorrr Premium vence hoje
call_to_action: Efetue o pagamento para continuar usando os benefícios da sua assinatura
due_date: "Vencimento: %{due_date}"
amount: "Valor: %{amount}"
11 changes: 11 additions & 0 deletions db/migrate/20240215115912_create_billings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CreateBillings < ActiveRecord::Migration[7.1]
def change
create_table :billings do |t|
t.references :subscription, null: false, foreign_key: true
t.date :billing_date, null: false
t.decimal :amount, precision: 8, scale: 2, null: false

t.timestamps
end
end
end
10 changes: 10 additions & 0 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions spec/factories/billings.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FactoryBot.define do
factory :billing do
subscription { nil }
billing_date { '2024-02-15' }
amount { '19.90' }
end
end
2 changes: 1 addition & 1 deletion spec/factories/subscriptions.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FactoryBot.define do
factory :subscription do
user
start_date { nil }
start_date { '2024-02-15' }
status { 0 }
end
end
4 changes: 0 additions & 4 deletions spec/factories/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
email { Faker::Internet.email }
password { '123456' }

after(:create) do |user|
user.subscription.active!
end

trait :seed do
after(:build) do |user|
user.class.skip_callback(:create, :after, :create_profile!, raise: false)
Expand Down
27 changes: 27 additions & 0 deletions spec/jobs/notify_billing_job_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
require 'rails_helper'

RSpec.describe NotifyBillingJob, type: :job do
context 'envia email de cobrança ' do
it 'para usuário com assinatura premium' do
user = create(:user, :paid, full_name: 'Marcos Madeira', email: '[email protected]')
billing = user.subscription.billings.first

mail = double('mail', deliver: true)
mailer = double('BillingsMailer', notifify_billing: mail)

allow(BillingsMailer).to receive(:with).and_return(mailer)
allow(mailer).to receive(:notify_billing).and_return(mail)

NotifyBillingJob.perform_now(billing)

expect(mail).to have_received(:deliver).once
end

it 'A cobrança é recriada para ser enviada via email no próximo mês' do
user = create(:user, :paid, full_name: 'Marcos Madeira', email: '[email protected]')
billing = user.subscription.billings.first

expect { NotifyBillingJob.perform_now(billing) }.to have_enqueued_job(NotifyBillingJob).on_queue('default')
end
end
end
22 changes: 22 additions & 0 deletions spec/mailer/billings_mailer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'rails_helper'

RSpec.describe BillingsMailer, type: :mailer do
context '#notify_billing' do
it 'envia e-mail de acordo com data de cobrança da assinatura' do
user = create(:user, :paid, full_name: 'Marcos Madeira', email: '[email protected]')

billing = user.subscription.billings.first

mail = BillingsMailer.with(billing:).notify_billing

expect(mail.subject).to eq 'Porfoliorrr - Assinatura mensal'
expect(mail.to).to eq ['[email protected]']
expect(mail.from).to eq ['[email protected]']
expect(mail.body).to include 'Olá, Marcos Madeira!'
expect(mail.body).to include 'Sua assinatura mensal do Porfoliorrr Premium vence hoje'
expect(mail.body).to include 'Efetue o pagamento para continuar usando os benefícios da sua assinatura'
expect(mail.body).to include "Vencimento: #{I18n.l(billing.billing_date)}"
expect(mail.body).to include 'Valor: R$ 19,90'
end
end
end
6 changes: 3 additions & 3 deletions spec/models/profile_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@
it 'retorna perfis premium primeiro e depois os perfis free' do
create(:user, :free, full_name: 'André Porteira')
create(:user, :free, full_name: 'Eliseu Ramos')
create(:user, full_name: 'Moisés Campus')
create(:user, :paid, full_name: 'Moisés Campus')
user_premium_inactive = create(:user, full_name: 'Joao Almeida')
user_premium_inactive.subscription.inactive!

Expand All @@ -268,8 +268,8 @@
it 'ordena por nome em caso de mesmo status de assinatura' do
create(:user, :free, full_name: 'André Almeida')
create(:user, :free, full_name: 'André Barbosa')
create(:user, full_name: 'André Campus')
create(:user, full_name: 'André Dias')
create(:user, :paid, full_name: 'André Campus')
create(:user, :paid, full_name: 'André Dias')

result = Profile.order_by_premium

Expand Down
75 changes: 62 additions & 13 deletions spec/models/subscription_spec.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,74 @@
require 'rails_helper'

RSpec.describe Subscription, type: :model do
describe '#active!' do
it 'atualiza data de início automaticamente' do
subscription = create(:subscription, status: :inactive, start_date: nil)
context 'assinatura de usuário premium' do
it 'cria cobrança antes do dia 29' do
user = create(:user, :free)

subscription.active!
travel_to Date.parse('2024-02-10') do
user.subscription.active!
end

expect(subscription.start_date).to eq Time.zone.now.to_date
expect(subscription).to be_active
billing = Billing.first
expect(Billing.count).to eq 1
expect(billing.billing_date).to eq Date.parse '2024-03-10'
expect(billing.amount).to eq 19.90
end

context 'recebe cobrança no primeiro dia do mês seguinte' do
it 'quando assinatura for no dia 29' do
user = create(:user, :free)

travel_to Date.parse('2024-03-29') do
user.subscription.active!
end

expect(Billing.count).to eq 1
expect(Billing.first.billing_date).to eq Date.parse '2024-05-01'
end

it 'quando assinatura for no dia 30' do
user = create(:user, :free)

travel_to Date.parse('2024-06-30') do
user.subscription.active!
end

expect(Billing.count).to eq 1
expect(Billing.first.billing_date).to eq Date.parse '2024-08-01'
end

it 'quando assinatura for no dia 31' do
user = create(:user, :free)

travel_to Date.parse('2024-10-31') do
user.subscription.active!
end

expect(Billing.count).to eq 1
expect(Billing.first.billing_date).to eq Date.parse '2024-12-01'
end
end
describe '#active!' do
it 'atualiza data de início automaticamente' do
subscription = create(:subscription, status: :inactive, start_date: nil)

subscription.active!

expect(subscription.start_date).to eq Time.zone.now.to_date
expect(subscription).to be_active
end
end
end

describe '#active!' do
it 'atualiza data de início automaticamente' do
subscription = create(:subscription, status: :active, start_date: Time.zone.now)
describe '#active!' do
it 'atualiza data de início automaticamente' do
subscription = create(:subscription, status: :active, start_date: Time.zone.now)

subscription.inactive!
subscription.inactive!

expect(subscription.start_date).to be_nil
expect(subscription).to be_inactive
expect(subscription.start_date).to be_nil
expect(subscription).to be_inactive
end
end
end
end
6 changes: 3 additions & 3 deletions spec/requests/apis/v1/search_user_by_job_categories_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@
it 'retorna perfis premium primeiro e depois os perfis comuns' do
create(:user, :free, full_name: 'Eliseu Ramos')
create(:user, :free, full_name: 'André Porteira')
create(:user, full_name: 'Moisés Campus')
create(:user, full_name: 'Joao Almeida')
create(:user, :paid, full_name: 'Moisés Campus')
create(:user, :paid, full_name: 'Joao Almeida')

get '/api/v1/profiles'

Expand All @@ -107,7 +107,7 @@
it 'retorna perfis premium primeiro e depois os perfis free na busca com parâmetro' do
ruby = create(:job_category, name: 'Ruby on Rails')

user_premium = create(:user, full_name: 'Moisés Campus')
user_premium = create(:user, :paid, full_name: 'Moisés Campus')
user_premium.profile.profile_job_categories.create(job_category: ruby, description: 'Sou um especialista em Ruby')
user_free = create(:user, :free, full_name: 'André Almeida')
user_free.profile.profile_job_categories.create(job_category: ruby, description: 'Fiz um e-commerce em Ruby')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@

describe 'Usuário solicita convite para um projeto' do
it 'com sucesso' do
user = create(:user)

user = create(:user, :paid)
login_as user
post invitation_request_path, params: { invitation_request: { message: 'Me convida', project_id: 1 } }

post invitation_request_path, params: {
'project_id' => 1,
'invitation_request' => {
'message' => 'Me convida'
}
}
user_requests = user.profile.invitation_requests

expect(user_requests.count).to eq 1
expect(user_requests.reload.count).to eq 1
expect(user_requests.last.message).to eq 'Me convida'
end

it 'e falha se já solicitou convite para o mesmo projeto' do
user = create(:user)
user = create(:user, :paid)
create(:invitation_request, profile: user.profile)
login_as user

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

describe 'Solicitação de convite tem status atualizado para "aceita"' do
it 'quando recebe convite para o mesmo projeto' do
user = create(:user)
user = create(:user, :paid)

invitation_request_one = create(:invitation_request, profile: user.profile,
project_id: 1, status: :pending)
Expand Down
Loading
Loading