Add first iteration
This commit is contained in:
parent
f97b01dd43
commit
57e976ef96
2
Gemfile
2
Gemfile
@ -11,9 +11,11 @@ gem "puma", "~> 5.0"
|
|||||||
gem "rails", "~> 7.0.3"
|
gem "rails", "~> 7.0.3"
|
||||||
gem "dotenv-rails"
|
gem "dotenv-rails"
|
||||||
gem "pundit"
|
gem "pundit"
|
||||||
|
gem "ransack"
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem "debug", platforms: %i[ mri mingw x64_mingw ]
|
gem "debug", platforms: %i[ mri mingw x64_mingw ]
|
||||||
|
gem "timecop"
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
|
@ -159,10 +159,15 @@ GEM
|
|||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
zeitwerk (~> 2.5)
|
zeitwerk (~> 2.5)
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
|
ransack (3.2.1)
|
||||||
|
activerecord (>= 6.1.5)
|
||||||
|
activesupport (>= 6.1.5)
|
||||||
|
i18n
|
||||||
reline (0.3.1)
|
reline (0.3.1)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
strscan (3.0.3)
|
strscan (3.0.3)
|
||||||
thor (1.2.1)
|
thor (1.2.1)
|
||||||
|
timecop (0.9.5)
|
||||||
timeout (0.3.0)
|
timeout (0.3.0)
|
||||||
tzinfo (2.0.4)
|
tzinfo (2.0.4)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
@ -189,6 +194,8 @@ DEPENDENCIES
|
|||||||
puma (~> 5.0)
|
puma (~> 5.0)
|
||||||
pundit
|
pundit
|
||||||
rails (~> 7.0.3)
|
rails (~> 7.0.3)
|
||||||
|
ransack
|
||||||
|
timecop
|
||||||
web-console
|
web-console
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
|
@ -1 +1,7 @@
|
|||||||
/* Application styles */
|
/* Application styles */
|
||||||
|
|
||||||
|
table { border: 1px solid black; }
|
||||||
|
|
||||||
|
td, th { padding: 10px; }
|
||||||
|
|
||||||
|
.new_contribution_form { max-width: 600px; }
|
||||||
|
54
app/controllers/contributions_controller.rb
Normal file
54
app/controllers/contributions_controller.rb
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
class ContributionsController < ApplicationController
|
||||||
|
before_action :set_member, only: %i[ new create ]
|
||||||
|
before_action :set_contribution, only: %i[ edit ]
|
||||||
|
|
||||||
|
# GET /members/new
|
||||||
|
def new
|
||||||
|
@contribution = Contribution.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /members/1/edit
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /members
|
||||||
|
def create
|
||||||
|
@contribution = @member.contributions.build(contribution_params)
|
||||||
|
|
||||||
|
Contribution.transaction do
|
||||||
|
if @contribution.save
|
||||||
|
@member.handle_new_contribution(@contribution, params.dig(:contribution, :overriden_expires_on))
|
||||||
|
@member.reset_status!
|
||||||
|
|
||||||
|
redirect_to @member, notice: "Contribution was successfully created."
|
||||||
|
else
|
||||||
|
render :new, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
## PATCH/PUT /members/1
|
||||||
|
#def update
|
||||||
|
# if @member.update(member_params)
|
||||||
|
# redirect_to @member, notice: "Member was successfully updated."
|
||||||
|
# else
|
||||||
|
# render :edit, status: :unprocessable_entity
|
||||||
|
# end
|
||||||
|
#end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
def set_member
|
||||||
|
@member = Member.find(params[:member_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_contribution
|
||||||
|
@contribution = Contribution.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Only allow a list of trusted parameters through.
|
||||||
|
def contribution_params
|
||||||
|
params.fetch(:contribution, {}).permit(:eurocents, :payment_method, :payment_on, :payment_reference)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
72
app/controllers/members_controller.rb
Normal file
72
app/controllers/members_controller.rb
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
class MembersController < ApplicationController
|
||||||
|
before_action :set_member, only: %i[ show edit update destroy ]
|
||||||
|
helper_method :sort_params
|
||||||
|
|
||||||
|
# GET /members
|
||||||
|
def index
|
||||||
|
params.delete(:status) if params[:status] == 'any'
|
||||||
|
params.delete(:category) if params[:category] == 'any'
|
||||||
|
|
||||||
|
@members = Member.all.order(sort_params.merge(number: :asc))
|
||||||
|
@members = @members.ransack(display_name_or_email_or_identification_number_i_cont: params[:q], status_cont: params[:status], category_cont: params[:category]).result
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /members/1
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /members/new
|
||||||
|
def new
|
||||||
|
@member = Member.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /members/1/edit
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /members
|
||||||
|
def create
|
||||||
|
@member = Member.new(member_params)
|
||||||
|
|
||||||
|
if @member.save
|
||||||
|
@member.reset_status!
|
||||||
|
redirect_to @member, notice: "Member was successfully created."
|
||||||
|
else
|
||||||
|
render :new, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# PATCH/PUT /members/1
|
||||||
|
def update
|
||||||
|
if @member.update(member_params)
|
||||||
|
@member.reload.reset_status!
|
||||||
|
redirect_to @member, notice: "Member was successfully updated."
|
||||||
|
else
|
||||||
|
render :edit, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# Use callbacks to share common setup or constraints between actions.
|
||||||
|
def set_member
|
||||||
|
@member = Member.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# Only allow a list of trusted parameters through.
|
||||||
|
def member_params
|
||||||
|
params.fetch(:member, {}).permit(:display_name, :email, :identification_number, :category, :address, :joined_on, :expires_on)
|
||||||
|
end
|
||||||
|
|
||||||
|
def sort_params
|
||||||
|
field, direction = params.fetch(:sort, "").split(".")
|
||||||
|
|
||||||
|
directions = %w[ asc desc ]
|
||||||
|
fields = %w[ number expires_on joined_on email status display_name ]
|
||||||
|
|
||||||
|
if directions.include?(direction) && fields.include?(field)
|
||||||
|
{ field => direction }
|
||||||
|
else
|
||||||
|
{ number: :asc }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,2 +1,5 @@
|
|||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
|
def member_status(status)
|
||||||
|
t("members.status.#{status}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
24
app/helpers/members_helper.rb
Normal file
24
app/helpers/members_helper.rb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
module MembersHelper
|
||||||
|
def link_to_current_with_sort text, default_sort
|
||||||
|
current_sort = stringify(sort_params)
|
||||||
|
|
||||||
|
pp [default_sort, current_sort]
|
||||||
|
|
||||||
|
if default_sort == current_sort
|
||||||
|
link_to text, members_path(sort: invert_sort_order(current_sort))
|
||||||
|
else
|
||||||
|
link_to text, members_path(sort: default_sort)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def stringify(sort)
|
||||||
|
"#{sort.keys.first.to_s}.#{sort.values.first.to_s}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def invert_sort_order(sort)
|
||||||
|
sort.sub(/\.(asc|desc)$/) { |x| x == '.asc' ? '.desc' : '.asc' }
|
||||||
|
end
|
||||||
|
end
|
19
app/lib/if_then_pay.rb
Normal file
19
app/lib/if_then_pay.rb
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
require 'net/http'
|
||||||
|
|
||||||
|
module IfThenPay
|
||||||
|
def self.generate_gateway_link(id:, amount:, description:)
|
||||||
|
response = Net::HTTP.post(
|
||||||
|
URI("https://ifthenpay.com/api/gateway/paybylink/#{ENV['IFTHENPAY_KEY']}"),
|
||||||
|
JSON.generate({
|
||||||
|
id: id,
|
||||||
|
amount: amount.to_s,
|
||||||
|
description: description.to_s,
|
||||||
|
"lang": "pt",
|
||||||
|
"expiredate": "",
|
||||||
|
"accounts": ENV['IFTHENPAY_ACCOUNTS'],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
JSON.parse(response.body)
|
||||||
|
end
|
||||||
|
end
|
@ -1,4 +1,4 @@
|
|||||||
class ApplicationMailer < ActionMailer::Base
|
class ApplicationMailer < ActionMailer::Base
|
||||||
default from: "from@example.com"
|
default from: email_address_with_name(ENV['SMTP_FROM_ADDRESS'], ENV['SMTP_FROM_NAME'])
|
||||||
layout "mailer"
|
layout "mailer"
|
||||||
end
|
end
|
||||||
|
68
app/mailers/notification_mailer.rb
Normal file
68
app/mailers/notification_mailer.rb
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
class NotificationMailer < ApplicationMailer
|
||||||
|
|
||||||
|
# Subject can be set in your I18n file at config/locales/en.yml
|
||||||
|
# with the following lookup:
|
||||||
|
#
|
||||||
|
# en.notification_mailer.expiration_in_60d.subject
|
||||||
|
#
|
||||||
|
def expiration_in_60d
|
||||||
|
@notification = params[:notification]
|
||||||
|
|
||||||
|
mail to: params[:notification].member.email
|
||||||
|
end
|
||||||
|
|
||||||
|
# Subject can be set in your I18n file at config/locales/en.yml
|
||||||
|
# with the following lookup:
|
||||||
|
#
|
||||||
|
# en.notification_mailer.expiration_in_30d.subject
|
||||||
|
#
|
||||||
|
def expiration_in_30d
|
||||||
|
@notification = params[:notification]
|
||||||
|
|
||||||
|
mail to: params[:notification].member.email
|
||||||
|
end
|
||||||
|
|
||||||
|
# Subject can be set in your I18n file at config/locales/en.yml
|
||||||
|
# with the following lookup:
|
||||||
|
#
|
||||||
|
# en.notification_mailer.expired.subject
|
||||||
|
#
|
||||||
|
def expired
|
||||||
|
@notification = params[:notification]
|
||||||
|
|
||||||
|
mail to: params[:notification].member.email
|
||||||
|
end
|
||||||
|
|
||||||
|
# Subject can be set in your I18n file at config/locales/en.yml
|
||||||
|
# with the following lookup:
|
||||||
|
#
|
||||||
|
# en.notification_mailer.expired_30d_ago.subject
|
||||||
|
#
|
||||||
|
def expired_30d_ago
|
||||||
|
@notification = params[:notification]
|
||||||
|
|
||||||
|
mail to: params[:notification].member.email
|
||||||
|
end
|
||||||
|
|
||||||
|
# Subject can be set in your I18n file at config/locales/en.yml
|
||||||
|
# with the following lookup:
|
||||||
|
#
|
||||||
|
# en.notification_mailer.expired_60d_ago.subject
|
||||||
|
#
|
||||||
|
def expired_60d_ago
|
||||||
|
@notification = params[:notification]
|
||||||
|
|
||||||
|
mail to: params[:notification].member.email
|
||||||
|
end
|
||||||
|
|
||||||
|
# Subject can be set in your I18n file at config/locales/en.yml
|
||||||
|
# with the following lookup:
|
||||||
|
#
|
||||||
|
# en.notification_mailer.cancelled.subject
|
||||||
|
#
|
||||||
|
def cancelled
|
||||||
|
@notification = params[:notification]
|
||||||
|
|
||||||
|
mail to: params[:notification].member.email
|
||||||
|
end
|
||||||
|
end
|
3
app/models/contribution.rb
Normal file
3
app/models/contribution.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
class Contribution < ApplicationRecord
|
||||||
|
belongs_to :member
|
||||||
|
end
|
88
app/models/member.rb
Normal file
88
app/models/member.rb
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
class Member < ApplicationRecord
|
||||||
|
has_many :contributions
|
||||||
|
has_many :notifications
|
||||||
|
|
||||||
|
def cancelled_on
|
||||||
|
expires_on + 90.days
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_status!
|
||||||
|
update(status: expected_status)
|
||||||
|
end
|
||||||
|
|
||||||
|
def expected_status
|
||||||
|
if joined_on.nil?
|
||||||
|
:pending
|
||||||
|
elsif (joined_on + 6.months).future?
|
||||||
|
:passive
|
||||||
|
elsif expires_on.future?
|
||||||
|
:active
|
||||||
|
elsif cancelled_on.future?
|
||||||
|
:expired
|
||||||
|
else
|
||||||
|
:cancelled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_new_contribution(contribution, overriden_expires_on)
|
||||||
|
if joined_on.nil?
|
||||||
|
self.joined_on = contribution.payment_on
|
||||||
|
self.expires_on = overriden_expires_on.presence || (joined_on + 1.year)
|
||||||
|
else
|
||||||
|
self.expires_on = overriden_expires_on.presence || expires_on + 1.year
|
||||||
|
end
|
||||||
|
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
|
||||||
|
def regenerate_notifications
|
||||||
|
notifications.where(status: 'scheduled').delete_all
|
||||||
|
|
||||||
|
return if expires_on.nil?
|
||||||
|
|
||||||
|
[
|
||||||
|
{ to_be_sent_on: expires_on - 90.days, template: "expiration_in_60d" },
|
||||||
|
{ to_be_sent_on: expires_on - 30.days, template: "expiration_in_30d" },
|
||||||
|
{ to_be_sent_on: expires_on + 0.days, template: "expired" },
|
||||||
|
{ to_be_sent_on: expires_on + 30.days, template: "expired_30d_ago" },
|
||||||
|
{ to_be_sent_on: expires_on + 60.days, template: "expired_60d_ago" },
|
||||||
|
{ to_be_sent_on: expires_on + 90.days, template: "cancelled" },
|
||||||
|
].reject { |n| n[:to_be_sent_on].past? }.each do |n|
|
||||||
|
notifications.create(n.merge(status: "scheduled"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_missing_ifthenpay_links!
|
||||||
|
self.regular_ifthenpay_link = IfThenPay.generate_gateway_link(
|
||||||
|
id: number,
|
||||||
|
amount: "30.00",
|
||||||
|
description: "Quotas ANSOL",
|
||||||
|
) unless self.regular_ifthenpay_link.present?
|
||||||
|
|
||||||
|
self.reduced_ifthenpay_link = IfThenPay.generate_gateway_link(
|
||||||
|
id: number,
|
||||||
|
amount: "6.00",
|
||||||
|
description: "Quotas ANSOL",
|
||||||
|
) unless self.reduced_ifthenpay_link.present?
|
||||||
|
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.reset_all_status!
|
||||||
|
Member.all.each do |member|
|
||||||
|
member.reset_status!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.generate_all_missing_ifthenpay_links!
|
||||||
|
Member.all.each do |member|
|
||||||
|
member.generate_missing_ifthenpay_links!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.regenerate_all_notifications
|
||||||
|
Member.all.each do |member|
|
||||||
|
member.regenerate_notifications
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
20
app/models/notification.rb
Normal file
20
app/models/notification.rb
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
class Notification < ApplicationRecord
|
||||||
|
belongs_to :member
|
||||||
|
|
||||||
|
scope :scheduled_for_today, ->() { where(status: 'scheduled', to_be_sent_on: Date.today) }
|
||||||
|
|
||||||
|
def self.send_scheduled_for_today
|
||||||
|
scheduled_for_today.each do |n|
|
||||||
|
n.deliver!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deliver!
|
||||||
|
# actually send the email.
|
||||||
|
NotificationMailer.with(notification: self).send(template).deliver_now!
|
||||||
|
|
||||||
|
update(status: 'sent', sent_at: Time.current)
|
||||||
|
rescue
|
||||||
|
# TODO: do something about failures
|
||||||
|
end
|
||||||
|
end
|
22
app/views/contributions/edit.html.erb
Normal file
22
app/views/contributions/edit.html.erb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
editando contriboot
|
||||||
|
|
||||||
|
<%= form_with(model: @contribution) do |form| %>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Amount</td>
|
||||||
|
<td>€<%= @contribution.eurocents %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Payment date</td>
|
||||||
|
<td>€<%= @contribution.payment_on %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Payment method</td>
|
||||||
|
<td><%= @contribution.payment_method %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Payment reference</td>
|
||||||
|
<td><%= @contribution.payment_reference %></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<% end %>
|
48
app/views/contributions/new.html.erb
Normal file
48
app/views/contributions/new.html.erb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<h1>Registering contribution for <%= @member.display_name %></h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><td>Member number</td><td><%= @member.number %></td></tr>
|
||||||
|
<tr><td>Joined on</td><td><%= @member.joined_on %></td></tr>
|
||||||
|
<tr><td>Expires on</td><td><%= @member.expires_on %></td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<%= form_with(model: [@member, @contribution]) do |form| %>
|
||||||
|
<table class="new_contribution_form">
|
||||||
|
<tr>
|
||||||
|
<td><label for="contribution_eurocents">Amount</label></td>
|
||||||
|
<td><%= form.number_field :eurocents %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="contribution_payment_on">Payment date</label></td>
|
||||||
|
<td><%= form.date_field :payment_on %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="contribution_payment_method">Payment method</label></td>
|
||||||
|
<td><%= form.select :payment_method, %w[iban mbway multibanco] %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="contribution_payment_reference">Referência</label></td>
|
||||||
|
<td><%= form.text_field :payment_reference %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan=2>
|
||||||
|
Adding a contribution will automatically bump the membership expiration
|
||||||
|
date by one year. If it's the first contribution for this member, the
|
||||||
|
join date will be set to the payment date and the expiration date one
|
||||||
|
year after that. You can override the expiration date by setting a date
|
||||||
|
below:
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="member_expires_on">Nova data de expiração</label></td>
|
||||||
|
<td>
|
||||||
|
<%= form.date_field :overriden_expires_on %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= form.submit %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
@ -11,6 +11,10 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<nav>
|
||||||
|
<%= link_to t('navigation.members'), members_path %>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -8,6 +8,12 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<%= yield %>
|
<div style="max-width: 600px;">
|
||||||
|
<div style="background-color: #041952; padding: 20px">
|
||||||
|
<img src="https://hugopeixoto.net/images/ansol-logo-white.png?xxx" style="margin: 0px auto; max-width: 400px; display: block; color: white" alt="ANSOL" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= yield %>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
0
app/views/members/_form.html.erb
Normal file
0
app/views/members/_form.html.erb
Normal file
2
app/views/members/_member.html.erb
Normal file
2
app/views/members/_member.html.erb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<div id="<%= dom_id member %>">
|
||||||
|
</div>
|
59
app/views/members/edit.html.erb
Normal file
59
app/views/members/edit.html.erb
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<h1><%= t('members.edit.title') %></h1>
|
||||||
|
|
||||||
|
<%= form_with(model: @member) do |form| %>
|
||||||
|
<% if @member.errors.any? %>
|
||||||
|
<div style="color: red">
|
||||||
|
<h2><%= pluralize(@member.errors.count, "error") %> prohibited this member from being saved:</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<% @member.errors.each do |error| %>
|
||||||
|
<li><%= error.full_message %></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><label><%= t('members.attributes.display_name') %></label></td>
|
||||||
|
<td><%= form.text_field :display_name, required: true %></label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label><%= t('members.attributes.email') %></label></td>
|
||||||
|
<td><%= form.email_field :email, required: true %></label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label><%= t('members.attributes.category') %></label></td>
|
||||||
|
<td><%= form.select :category, %w{student retired unemployed employed} %></label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label><%= t('members.attributes.identification_number') %></label></td>
|
||||||
|
<td><%= form.text_field :identification_number %></label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label><%= t('members.attributes.address') %></label></td>
|
||||||
|
<td><%= form.text_area :address %></label></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><%= t('members.edit.edit_dates_warning') %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="member_joined_on"><%= t('members.attributes.joined_on') %></label></td>
|
||||||
|
<td><%= form.date_field :joined_on %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="member_expires_on"><%= t('members.attributes.expires_on') %></label></td>
|
||||||
|
<td><%= form.date_field :expires_on %></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= form.submit %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= link_to t('members.edit.actions.back_to_show'), @member %>
|
||||||
|
</div>
|
44
app/views/members/index.html.erb
Normal file
44
app/views/members/index.html.erb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<p style="color: green"><%= notice %></p>
|
||||||
|
|
||||||
|
<h1><%= t 'members.index.title' %></h1>
|
||||||
|
|
||||||
|
<%= link_to t('members.index.actions.new'), new_member_path %>
|
||||||
|
|
||||||
|
<%= form_with url: members_path, method: :get do |form| %>
|
||||||
|
<%= form.text_field :q %>
|
||||||
|
<%= form.select :status, %w[ any active passive pending expired cancelled ], selected: params[:status] %>
|
||||||
|
<%= form.select :category, %w[ any student employed unemployed retired ], selected: params[:category], multiple: true %>
|
||||||
|
<%= form.submit 'Search', name: '' %>
|
||||||
|
<% if params[:q].present? || params[:status].present? || params[:category].present? %>
|
||||||
|
<%= link_to t('members.index.actions.clear_search'), members_path %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<table id="members">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= link_to_current_with_sort t('members.attributes.number'), 'number.asc' %></th>
|
||||||
|
<th><%= link_to_current_with_sort t('members.attributes.status'), 'status.asc' %></th>
|
||||||
|
<th><%= link_to_current_with_sort t('members.attributes.email'), 'email.asc' %></th>
|
||||||
|
<th><%= link_to_current_with_sort t('members.attributes.display_name'), 'display_name.asc' %></th>
|
||||||
|
<th><%= link_to_current_with_sort t('members.attributes.joined_on'), 'joined_on.asc' %></th>
|
||||||
|
<th><%= link_to_current_with_sort t('members.attributes.expires_on'), 'expires_on.asc' %></th>
|
||||||
|
<th><%= t('members.index.actions.title') %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<% @members.each do |member| %>
|
||||||
|
<tr id="<%= dom_id member %>">
|
||||||
|
<td><%= member.number %></td>
|
||||||
|
<td><%= member_status(member.status) %></td>
|
||||||
|
<td><%= member.email %></td>
|
||||||
|
<td><%= member.display_name %></td>
|
||||||
|
<td><%= member.joined_on %></td>
|
||||||
|
<td><%= member.expires_on %></td>
|
||||||
|
<td>
|
||||||
|
<%= link_to t('members.index.actions.show'), member %> |
|
||||||
|
<%= link_to t('members.index.actions.edit'), edit_member_path(member) %> |
|
||||||
|
<%= link_to t('members.index.actions.new_contribution'), new_member_contribution_path(member) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
27
app/views/members/new.html.erb
Normal file
27
app/views/members/new.html.erb
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<h1><%= t('members.new.title') %></h1>
|
||||||
|
|
||||||
|
<%= form_with(model: @member) do |form| %>
|
||||||
|
<% if @member.errors.any? %>
|
||||||
|
<div style="color: red">
|
||||||
|
<h2><%= pluralize(@member.errors.count, "error") %> prohibited this member from being saved:</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<% @member.errors.each do |error| %>
|
||||||
|
<li><%= error.full_message %></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><td><label><%= t('members.attributes.display_name') %></label></td><td><%= form.text_field :display_name, required: true %></label></td></tr>
|
||||||
|
<tr><td><label><%= t('members.attributes.email') %></label></td><td><%= form.email_field :email, required: true %></label></td></tr>
|
||||||
|
<tr><td><label><%= t('members.attributes.category') %></label></td><td><%= form.select :category, %w{student retired unemployed employed} %></label></td></tr>
|
||||||
|
<tr><td><label><%= t('members.attributes.identification_number') %></label></td><td><%= form.text_field :identification_number %></label></td></tr>
|
||||||
|
<tr><td><label><%= t('members.attributes.address') %></label></td><td><%= form.text_area :address %></label></td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= form.submit %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
40
app/views/members/show.html.erb
Normal file
40
app/views/members/show.html.erb
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<p style="color: green"><%= notice %></p>
|
||||||
|
|
||||||
|
<h1><%= t('members.show.title') %></h1>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr><td><%= t('members.attributes.display_name') %></td><td><%= @member.display_name %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.email') %></td><td><%= @member.email %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.category') %></td><td><%= @member.category %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.identification_number') %></td><td><%= @member.identification_number %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.address') %></td><td><%= simple_format @member.address %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.joined_on') %></td><td><%= @member.joined_on %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.expires_on') %></td><td><%= @member.expires_on %></td></tr>
|
||||||
|
<tr><td><%= t('members.attributes.status') %></td><td><%= @member.status %></td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= link_to t('members.show.actions.edit'), edit_member_path(@member) %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2><%= t('members.show.contribution_history') %></h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Payment date</th>
|
||||||
|
<th>Payment method</th>
|
||||||
|
<th>Payment reference</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
</tr>
|
||||||
|
<% @member.contributions.each do |contribution| %>
|
||||||
|
<tr>
|
||||||
|
<td><%= contribution.payment_on %></td>
|
||||||
|
<td><%= contribution.payment_method %></td>
|
||||||
|
<td><%= contribution.payment_reference %></td>
|
||||||
|
<td>€<%= contribution.eurocents %></td>
|
||||||
|
<td>
|
||||||
|
<%= link_to t('members.show.actions.edit_contribution'), edit_contribution_path(contribution) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</table>
|
22
app/views/notification_mailer/_payment.html.erb
Normal file
22
app/views/notification_mailer/_payment.html.erb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<p>
|
||||||
|
Aceitamos pagamento via transferência bancária, referência multibanco ou
|
||||||
|
MBWAY:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Valor: 30.00€</li>
|
||||||
|
<li>Transferência bancária: <strong>PT50 0035 2178 00027478430 14</strong></li>
|
||||||
|
<li>Multibanco ou MBWAY: <a href="<%= ifthenpay %>"><%= ifthenpay %></a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Caso queiras usufruir da quota reduzida de 6.00€ para estudantes,
|
||||||
|
desempregados e reformados, pedimos que nos envies um comprovativo desse
|
||||||
|
estatuto e faças o pagamento por transferência bancária.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Se optares pelo método de transferência bancária, pedimos que envies o
|
||||||
|
comprovativo de transferência em resposta a este email ou para o endereço
|
||||||
|
direccao@ansol.org.
|
||||||
|
</p>
|
14
app/views/notification_mailer/_payment.text.erb
Normal file
14
app/views/notification_mailer/_payment.text.erb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Aceitamos pagamento via transferência bancária, referência multibanco ou
|
||||||
|
MBWAY:
|
||||||
|
|
||||||
|
* Valor: 30.00€
|
||||||
|
* Transferência bancária: <strong>PT50 0035 2178 00027478430 14</strong>
|
||||||
|
* Multibanco ou MBWAY: <a href="<%= @link %>"><%= @link %></a>
|
||||||
|
|
||||||
|
Caso queiras usufruir da quota reduzida de 6.00€ para estudantes,
|
||||||
|
desempregados e reformados, pedimos que nos envies um comprovativo desse
|
||||||
|
estatuto e faças o pagamento por transferência bancária.
|
||||||
|
|
||||||
|
Se optares pelo método de transferência bancária, pedimos que envies o
|
||||||
|
comprovativo de transferência em resposta a este email ou para o endereço
|
||||||
|
direccao@ansol.org.
|
30
app/views/notification_mailer/cancelled.html.erb
Normal file
30
app/views/notification_mailer/cancelled.html.erb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<p>
|
||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Como não recebemos o pagamento anual das quotas da ANSOL, a tua inscrição foi
|
||||||
|
cancelada.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Vamos revogar em breve os teus acessos à infraestrutura da associação
|
||||||
|
exclusiva para membros (nextcloud, mailing list, sala de Matrix, etc).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Esperamos poder voltar a merecer o teu apoio no futuro. Podes reinscrever-te
|
||||||
|
a qualquer altura através do formulário disponível em
|
||||||
|
<a href="https://ansol.org/inscricao">https://ansol.org/inscricao</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Caso consideres que estás a receber esta mensagem indevidamente, contacta-nos
|
||||||
|
através do endereço direccao@ansol.org para resolvermos a situação o mais
|
||||||
|
rápido possível.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Saudações livres,<br>
|
||||||
|
Direcção da ANSOL
|
||||||
|
</p>
|
17
app/views/notification_mailer/cancelled.text.erb
Normal file
17
app/views/notification_mailer/cancelled.text.erb
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
|
||||||
|
Como não recebemos o pagamento anual das quotas da ANSOL, a tua inscrição foi
|
||||||
|
cancelada.
|
||||||
|
|
||||||
|
Vamos revogar em breve os teus acessos à infraestrutura da associação exclusiva
|
||||||
|
para membros (nextcloud, mailing list, sala de Matrix, etc).
|
||||||
|
|
||||||
|
Esperamos poder voltar a merecer o teu apoio no futuro. Podes reinscrever-te a
|
||||||
|
qualquer altura através do formulário disponível em https://ansol.org/inscricao
|
||||||
|
|
||||||
|
Caso consideres que estás a receber esta mensagem indevidamente, contacta-nos
|
||||||
|
através do endereço direccao@ansol.org para resolvermos a situação o mais
|
||||||
|
rápido possível.
|
||||||
|
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
24
app/views/notification_mailer/expiration_in_30d.html.erb
Normal file
24
app/views/notification_mailer/expiration_in_30d.html.erb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<p><%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A tua inscrição como membro da ANSOL expira em 30 dias.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Em primeiro lugar, queremos agradecer o teu contributo para a ANSOL.
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades, e gostaríamos de continuar a contar com a tua
|
||||||
|
participação.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Para estender a tua inscrição por mais um ano, pedimos que faças o pagamento
|
||||||
|
das quotas até <strong><%= @notification.member.expires_on %></strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Saudações livres,<br>
|
||||||
|
Direcção da ANSOL
|
||||||
|
</p>
|
16
app/views/notification_mailer/expiration_in_30d.text.erb
Normal file
16
app/views/notification_mailer/expiration_in_30d.text.erb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
|
||||||
|
A tua inscrição como membro da ANSOL expira em 30 dias.
|
||||||
|
|
||||||
|
Em primeiro lugar, queremos agradecer o teu contributo para a ANSOL.
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades, e gostaríamos de continuar a contar com a tua
|
||||||
|
participação.
|
||||||
|
|
||||||
|
Para estender a tua inscrição por mais um ano, pedimos que faças o pagamento
|
||||||
|
das quotas até <%= @notification.member.expires_on %>.
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
24
app/views/notification_mailer/expiration_in_60d.html.erb
Normal file
24
app/views/notification_mailer/expiration_in_60d.html.erb
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<p><%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %></p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A tua inscrição como membro da ANSOL expira em 60 dias.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Em primeiro lugar, queremos agradecer o teu contributo para a ANSOL.
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades, e gostaríamos de continuar a contar com a tua
|
||||||
|
participação.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Para estender a tua inscrição por mais um ano, pedimos que faças o pagamento
|
||||||
|
das quotas até <strong><%= @notification.member.expires_on %></strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Saudações livres,<br>
|
||||||
|
Direcção da ANSOL
|
||||||
|
</p>
|
16
app/views/notification_mailer/expiration_in_60d.text.erb
Normal file
16
app/views/notification_mailer/expiration_in_60d.text.erb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
|
||||||
|
A tua inscrição como membro da ANSOL expira em 60 dias.
|
||||||
|
|
||||||
|
Em primeiro lugar, queremos agradecer o teu contributo para a ANSOL.
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades, e gostaríamos de continuar a contar com a tua
|
||||||
|
participação.
|
||||||
|
|
||||||
|
Para estender a tua inscrição por mais um ano, pedimos que faças o pagamento
|
||||||
|
das quotas até <%= @notification.member.expires_on %>.
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
26
app/views/notification_mailer/expired.html.erb
Normal file
26
app/views/notification_mailer/expired.html.erb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<p>
|
||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A tua inscrição como membro da ANSOL vai ser cancelada dentro de 30 dias por
|
||||||
|
falta de pagamento da contribuição anual.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades. Gostaríamos de continuar a contar com a tua participação.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Caso não recebamos o pagamento até dia <%= @notification.member.cancelled_on
|
||||||
|
%>, cancelaremos permanentemente a tua inscrição. Estamos disponíveis para
|
||||||
|
esclarecer qualquer dúvida através do endereço direccao@ansol.org.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Saudações livres,<br>
|
||||||
|
Direcção da ANSOL
|
||||||
|
</p>
|
16
app/views/notification_mailer/expired.text.erb
Normal file
16
app/views/notification_mailer/expired.text.erb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
|
||||||
|
A tua inscrição como membro da ANSOL expirou hoje e não recebemos a tua
|
||||||
|
contribuição anual.
|
||||||
|
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades. Gostaríamos de continuar a contar com a tua participação.
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
Caso não recebamos o pagamento até dia <%= @notification.member.cancelled_on
|
||||||
|
%>, cancelaremos permanentemente a tua inscrição. Estamos disponíveis para
|
||||||
|
esclarecer qualquer dúvida através do endereço direccao@ansol.org.
|
||||||
|
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
26
app/views/notification_mailer/expired_30d_ago.html.erb
Normal file
26
app/views/notification_mailer/expired_30d_ago.html.erb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<p>
|
||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A tua inscrição como membro da ANSOL expirou há um mês e ainda não recebemos
|
||||||
|
a tua contribuição anual.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades. Gostaríamos de continuar a contar com a tua participação.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Caso não recebamos o pagamento até dia <%= @notification.member.cancelled_on
|
||||||
|
%>, cancelaremos permanentemente a tua inscrição. Estamos disponíveis para
|
||||||
|
esclarecer qualquer dúvida através do endereço direccao@ansol.org.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
||||||
|
</p>
|
16
app/views/notification_mailer/expired_30d_ago.text.erb
Normal file
16
app/views/notification_mailer/expired_30d_ago.text.erb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
|
||||||
|
A tua inscrição como membro da ANSOL expirou há um mês e ainda não recebemos
|
||||||
|
a tua contribuição anual.
|
||||||
|
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades. Gostaríamos de continuar a contar com a tua participação.
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
Caso não recebamos o pagamento até dia <%= @notification.member.cancelled_on
|
||||||
|
%>, cancelaremos permanentemente a tua inscrição. Estamos disponíveis para
|
||||||
|
esclarecer qualquer dúvida através do endereço direccao@ansol.org.
|
||||||
|
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
26
app/views/notification_mailer/expired_60d_ago.html.erb
Normal file
26
app/views/notification_mailer/expired_60d_ago.html.erb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<p>
|
||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A tua inscrição como membro da ANSOL vai ser cancelada dentro de 30 dias por
|
||||||
|
falta de pagamento da contribuição anual.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades. Gostaríamos de continuar a contar com a tua participação.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Caso não recebamos o pagamento até dia <%= @notification.member.cancelled_on
|
||||||
|
%>, cancelaremos permanentemente a tua inscrição. Estamos disponíveis para
|
||||||
|
esclarecer qualquer dúvida através do endereço direccao@ansol.org.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Saudações livres,<br>
|
||||||
|
Direcção da ANSOL
|
||||||
|
</p>
|
16
app/views/notification_mailer/expired_60d_ago.text.erb
Normal file
16
app/views/notification_mailer/expired_60d_ago.text.erb
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<%= t('notification_mailer.greetings', display_name: @notification.member.display_name) %>
|
||||||
|
|
||||||
|
A tua inscrição como membro da ANSOL expirou há 60 dias e ainda não recebemos
|
||||||
|
a tua contribuição anual.
|
||||||
|
|
||||||
|
Dependemos exclusivamente da contribuição dos nossos membros para suportar as
|
||||||
|
nossas actividades. Gostaríamos de continuar a contar com a tua participação.
|
||||||
|
|
||||||
|
<%= render partial: "payment", locals: { ifthenpay: @link } %>
|
||||||
|
|
||||||
|
Caso não recebamos o pagamento até dia <%= @notification.member.cancelled_on
|
||||||
|
%>, cancelaremos permanentemente a tua inscrição. Estamos disponíveis para
|
||||||
|
esclarecer qualquer dúvida através do endereço direccao@ansol.org.
|
||||||
|
|
||||||
|
Saudações livres,
|
||||||
|
Direcção da ANSOL
|
@ -33,5 +33,6 @@ module Saucy
|
|||||||
|
|
||||||
# Don't generate system test files.
|
# Don't generate system test files.
|
||||||
config.generators.system_tests = nil
|
config.generators.system_tests = nil
|
||||||
|
config.i18n.default_locale = :pt
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -41,6 +41,18 @@ Rails.application.configure do
|
|||||||
|
|
||||||
config.action_mailer.perform_caching = false
|
config.action_mailer.perform_caching = false
|
||||||
|
|
||||||
|
config.action_mailer.delivery_method :smtp
|
||||||
|
|
||||||
|
config.action_mailer.smtp_settings = {
|
||||||
|
address: ENV['SMTP_ADDRESS'],
|
||||||
|
port: 587,
|
||||||
|
domain: ENV['SMTP_DOMAIN'],
|
||||||
|
user_name: ENV['SMTP_USERNAME'],
|
||||||
|
password: ENV['SMTP_PASSWORD'],
|
||||||
|
authentication: 'plain',
|
||||||
|
enable_starttls_auto: true,
|
||||||
|
}
|
||||||
|
|
||||||
# Print deprecation notices to the Rails logger.
|
# Print deprecation notices to the Rails logger.
|
||||||
config.active_support.deprecation = :log
|
config.active_support.deprecation = :log
|
||||||
|
|
||||||
|
0
config/initializers/rules.rb
Normal file
0
config/initializers/rules.rb
Normal file
@ -1,33 +1,60 @@
|
|||||||
# Files in the config/locales directory are used for internationalization
|
|
||||||
# and are automatically loaded by Rails. If you want to use locales other
|
|
||||||
# than English, add the necessary files in this directory.
|
|
||||||
#
|
|
||||||
# To use the locales, use `I18n.t`:
|
|
||||||
#
|
|
||||||
# I18n.t "hello"
|
|
||||||
#
|
|
||||||
# In views, this is aliased to just `t`:
|
|
||||||
#
|
|
||||||
# <%= t("hello") %>
|
|
||||||
#
|
|
||||||
# To use a different locale, set it with `I18n.locale`:
|
|
||||||
#
|
|
||||||
# I18n.locale = :es
|
|
||||||
#
|
|
||||||
# This would use the information in config/locales/es.yml.
|
|
||||||
#
|
|
||||||
# The following keys must be escaped otherwise they will not be retrieved by
|
|
||||||
# the default I18n backend:
|
|
||||||
#
|
|
||||||
# true, false, on, off, yes, no
|
|
||||||
#
|
|
||||||
# Instead, surround them with single quotes.
|
|
||||||
#
|
|
||||||
# en:
|
|
||||||
# "true": "foo"
|
|
||||||
#
|
|
||||||
# To learn more, please read the Rails Internationalization guide
|
|
||||||
# available at https://guides.rubyonrails.org/i18n.html.
|
|
||||||
|
|
||||||
en:
|
en:
|
||||||
hello: "Hello world"
|
navigation:
|
||||||
|
members: "Member list"
|
||||||
|
members:
|
||||||
|
index:
|
||||||
|
title: "Members"
|
||||||
|
actions:
|
||||||
|
new: "New member"
|
||||||
|
clear_search: "Clear search"
|
||||||
|
show: "Show"
|
||||||
|
edit: "Edit"
|
||||||
|
new_contribution: "Register contribution"
|
||||||
|
show:
|
||||||
|
title: "Member details"
|
||||||
|
actions:
|
||||||
|
edit: "Edit"
|
||||||
|
edit:
|
||||||
|
title: "Edit member details"
|
||||||
|
actions:
|
||||||
|
back_to_show: "Show this member"
|
||||||
|
edit_dates_warning: "Warning: changing the join/expiration date may trigger the delivery of email notifications regarding pending payments."
|
||||||
|
new:
|
||||||
|
title: "Register new member"
|
||||||
|
attributes:
|
||||||
|
number: "#"
|
||||||
|
status: "Status"
|
||||||
|
email: "Email address"
|
||||||
|
display_name: "Display name"
|
||||||
|
joined_on: "Joined on"
|
||||||
|
expires_on: "Expires on"
|
||||||
|
category: "Category"
|
||||||
|
identification_number: "ID number"
|
||||||
|
address: "Postal address"
|
||||||
|
status:
|
||||||
|
any: "Any"
|
||||||
|
active: "Active"
|
||||||
|
passive: "Passive"
|
||||||
|
pending: "Pending"
|
||||||
|
expired: "Expired"
|
||||||
|
cancelled: "Cancelled"
|
||||||
|
category:
|
||||||
|
any: "Any"
|
||||||
|
employed: "Employed"
|
||||||
|
unemployed: "Unemployed"
|
||||||
|
student: "Student"
|
||||||
|
retired: "Retired"
|
||||||
|
notification_mailer:
|
||||||
|
expiration_in_60d:
|
||||||
|
subject: "ANSOL - Pagamento anual de quotas"
|
||||||
|
title: "Pagamento anual de quotas"
|
||||||
|
expiration_in_30d:
|
||||||
|
subject: "ANSOL - Prazo para pagamento de quotas vence em 30 dias"
|
||||||
|
expired:
|
||||||
|
subject: "ANSOL - Pagamento de quotas pendente"
|
||||||
|
expired_30d_ago:
|
||||||
|
subject: "ANSOL - Pagamento de quotas em atraso"
|
||||||
|
expired_60d_ago:
|
||||||
|
subject: "ANSOL - Suspensão de inscrição iminente"
|
||||||
|
cancelled:
|
||||||
|
subject: "ANSOL - Inscrição cancelada"
|
||||||
|
62
config/locales/pt.yml
Normal file
62
config/locales/pt.yml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
pt:
|
||||||
|
navigation:
|
||||||
|
members: "Lista de membros"
|
||||||
|
members:
|
||||||
|
index:
|
||||||
|
title: "Membros"
|
||||||
|
actions:
|
||||||
|
new: "Registar novo membro"
|
||||||
|
clear_search: ""
|
||||||
|
show: "Mostrar"
|
||||||
|
edit: "Editar"
|
||||||
|
new_contribution: "Registar contribuição"
|
||||||
|
title: "Acções"
|
||||||
|
show:
|
||||||
|
title: "Detalhes de membro"
|
||||||
|
actions:
|
||||||
|
edit: "Editar detalhes"
|
||||||
|
edit_contribution: "Editar"
|
||||||
|
edit:
|
||||||
|
title: "Editar detalhes de membro"
|
||||||
|
actions:
|
||||||
|
back_to_show: "Show this member"
|
||||||
|
edit_dates_warning: "Atenção: a alteração das datas de inscrição/expiração podem causar o envio de emails com notificações de atraso de pagamento."
|
||||||
|
new:
|
||||||
|
title: "Registar novo membro"
|
||||||
|
attributes:
|
||||||
|
number: "#"
|
||||||
|
status: "Estado"
|
||||||
|
email: "Endereço de correio electrónico"
|
||||||
|
display_name: "Nome"
|
||||||
|
joined_on: "Data de inscrição"
|
||||||
|
expires_on: "Data de expiração"
|
||||||
|
category: "Categoria"
|
||||||
|
identification_number: "N.º de identificação"
|
||||||
|
address: "Endereço postal"
|
||||||
|
status:
|
||||||
|
any: "Qualquer"
|
||||||
|
active: "Activo"
|
||||||
|
passive: "Passivo"
|
||||||
|
pending: "Pendente"
|
||||||
|
expired: "Expirado"
|
||||||
|
cancelled: "Cancelado"
|
||||||
|
category:
|
||||||
|
any: "Qualquer"
|
||||||
|
employed: "Empregado"
|
||||||
|
unemployed: "Desempregado"
|
||||||
|
student: "Estudante"
|
||||||
|
retired: "Reformado"
|
||||||
|
notification_mailer:
|
||||||
|
expiration_in_60d:
|
||||||
|
subject: "ANSOL - Pagamento anual de quotas"
|
||||||
|
expiration_in_30d:
|
||||||
|
subject: "ANSOL - Inscrição expira em 30 dias"
|
||||||
|
expired:
|
||||||
|
subject: "ANSOL - Pagamento de quotas pendente"
|
||||||
|
expired_30d_ago:
|
||||||
|
subject: "ANSOL - Pagamento de quotas em atraso"
|
||||||
|
expired_60d_ago:
|
||||||
|
subject: "ANSOL - Suspensão de inscrição iminente"
|
||||||
|
cancelled:
|
||||||
|
subject: "ANSOL - Inscrição cancelada"
|
||||||
|
greetings: "Caro(a) %{display_name}"
|
@ -3,4 +3,10 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
# Defines the root path route ("/")
|
# Defines the root path route ("/")
|
||||||
# root "articles#index"
|
# root "articles#index"
|
||||||
|
|
||||||
|
resources :members do
|
||||||
|
resources :contributions, only: [:new, :create]
|
||||||
|
end
|
||||||
|
|
||||||
|
resources :contributions, only: [:edit, :update]
|
||||||
end
|
end
|
||||||
|
15
db/migrate/20220620195513_create_member.rb
Normal file
15
db/migrate/20220620195513_create_member.rb
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class CreateMember < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
create_table :members, id: :uuid do |t|
|
||||||
|
t.serial :number, null: false, index: { unique: true }
|
||||||
|
t.string :email, null: false, index: { unique: true }
|
||||||
|
t.string :display_name, null: false
|
||||||
|
t.string :identification_number
|
||||||
|
t.string :status
|
||||||
|
t.string :category
|
||||||
|
t.text :address
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
8
db/migrate/20220620233944_add_dates_to_members.rb
Normal file
8
db/migrate/20220620233944_add_dates_to_members.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class AddDatesToMembers < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
change_table :members do |t|
|
||||||
|
t.date :joined_on
|
||||||
|
t.date :expires_on
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
db/migrate/20220621101236_create_contributions.rb
Normal file
14
db/migrate/20220621101236_create_contributions.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class CreateContributions < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
create_table :contributions, id: :uuid do |t|
|
||||||
|
t.references :member, type: :uuid, foreign_key: true, null: false
|
||||||
|
|
||||||
|
t.integer :eurocents, null: false
|
||||||
|
t.date :payment_on, null: false
|
||||||
|
t.string :payment_method
|
||||||
|
t.string :payment_reference
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
db/migrate/20220623135702_create_notifications.rb
Normal file
14
db/migrate/20220623135702_create_notifications.rb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class CreateNotifications < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
create_table :notifications, id: :uuid do |t|
|
||||||
|
t.references :member, type: :uuid, foreign_key: true
|
||||||
|
t.date :to_be_sent_on, null: false
|
||||||
|
t.string :template, null: false
|
||||||
|
|
||||||
|
t.string :status, null: false
|
||||||
|
t.timestamp :sent_at
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,8 @@
|
|||||||
|
class AddIfthenpayLinksToMember < ActiveRecord::Migration[7.0]
|
||||||
|
def change
|
||||||
|
change_table :members do |t|
|
||||||
|
t.string :regular_ifthenpay_link
|
||||||
|
t.string :reduced_ifthenpay_link
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
44
db/schema.rb
generated
44
db/schema.rb
generated
@ -10,9 +10,51 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.0].define(version: 2022_06_20_195143) do
|
ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pgcrypto"
|
enable_extension "pgcrypto"
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
|
||||||
|
create_table "contributions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
|
t.uuid "member_id", null: false
|
||||||
|
t.integer "eurocents", null: false
|
||||||
|
t.date "payment_on", null: false
|
||||||
|
t.string "payment_method"
|
||||||
|
t.string "payment_reference"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["member_id"], name: "index_contributions_on_member_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "members", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
|
t.serial "number", null: false
|
||||||
|
t.string "email", null: false
|
||||||
|
t.string "display_name", null: false
|
||||||
|
t.string "identification_number"
|
||||||
|
t.string "status"
|
||||||
|
t.string "category"
|
||||||
|
t.text "address"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.date "joined_on"
|
||||||
|
t.date "expires_on"
|
||||||
|
t.string "regular_ifthenpay_link"
|
||||||
|
t.string "reduced_ifthenpay_link"
|
||||||
|
t.index ["email"], name: "index_members_on_email", unique: true
|
||||||
|
t.index ["number"], name: "index_members_on_number", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "notifications", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||||
|
t.uuid "member_id"
|
||||||
|
t.date "to_be_sent_on", null: false
|
||||||
|
t.string "template", null: false
|
||||||
|
t.string "status", null: false
|
||||||
|
t.datetime "sent_at", precision: nil
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["member_id"], name: "index_notifications_on_member_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
add_foreign_key "contributions", "members"
|
||||||
|
add_foreign_key "notifications", "members"
|
||||||
end
|
end
|
||||||
|
14
lib/tasks/saucy.rake
Normal file
14
lib/tasks/saucy.rake
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
desc "Application specific tasks"
|
||||||
|
namespace :saucy do
|
||||||
|
desc "Background sync operations"
|
||||||
|
task sync: :environment do
|
||||||
|
Member.generate_all_missing_ifthenpay_links!
|
||||||
|
Member.reset_all_status!
|
||||||
|
Member.regenerate_all_notifications
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Send daily email notifications"
|
||||||
|
task notify: :environment do
|
||||||
|
Notification.send_scheduled_for_today
|
||||||
|
end
|
||||||
|
end
|
48
test/controllers/members_controller_test.rb
Normal file
48
test/controllers/members_controller_test.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class MembersControllerTest < ActionDispatch::IntegrationTest
|
||||||
|
#setup do
|
||||||
|
# @member = members(:one)
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should get index" do
|
||||||
|
# get members_url
|
||||||
|
# assert_response :success
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should get new" do
|
||||||
|
# get new_member_url
|
||||||
|
# assert_response :success
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should create member" do
|
||||||
|
# assert_difference("Member.count") do
|
||||||
|
# post members_url, params: { member: { } }
|
||||||
|
# end
|
||||||
|
|
||||||
|
# assert_redirected_to member_url(Member.last)
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should show member" do
|
||||||
|
# get member_url(@member)
|
||||||
|
# assert_response :success
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should get edit" do
|
||||||
|
# get edit_member_url(@member)
|
||||||
|
# assert_response :success
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should update member" do
|
||||||
|
# patch member_url(@member), params: { member: { } }
|
||||||
|
# assert_redirected_to member_url(@member)
|
||||||
|
#end
|
||||||
|
|
||||||
|
#test "should destroy member" do
|
||||||
|
# assert_difference("Member.count", -1) do
|
||||||
|
# delete member_url(@member)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# assert_redirected_to members_url
|
||||||
|
#end
|
||||||
|
end
|
11
test/fixtures/notifications.yml
vendored
Normal file
11
test/fixtures/notifications.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||||
|
|
||||||
|
# This model initially had no columns defined. If you add columns to the
|
||||||
|
# model remove the "{}" from the fixture names and add the columns immediately
|
||||||
|
# below each fixture, per the syntax in the comments below
|
||||||
|
#
|
||||||
|
one: {}
|
||||||
|
# column: value
|
||||||
|
#
|
||||||
|
two: {}
|
||||||
|
# column: value
|
52
test/mailers/notification_mailer_test.rb
Normal file
52
test/mailers/notification_mailer_test.rb
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class NotificationMailerTest < ActionMailer::TestCase
|
||||||
|
test "expiration_in_60d" do
|
||||||
|
mail = NotificationMailer.expiration_in_60d
|
||||||
|
assert_equal "Expiration in 60d", mail.subject
|
||||||
|
assert_equal ["to@example.org"], mail.to
|
||||||
|
assert_equal ["from@example.com"], mail.from
|
||||||
|
assert_match "Hi", mail.body.encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
test "expiration_in_30d" do
|
||||||
|
mail = NotificationMailer.expiration_in_30d
|
||||||
|
assert_equal "Expiration in 30d", mail.subject
|
||||||
|
assert_equal ["to@example.org"], mail.to
|
||||||
|
assert_equal ["from@example.com"], mail.from
|
||||||
|
assert_match "Hi", mail.body.encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
test "expired" do
|
||||||
|
mail = NotificationMailer.expired
|
||||||
|
assert_equal "Expired", mail.subject
|
||||||
|
assert_equal ["to@example.org"], mail.to
|
||||||
|
assert_equal ["from@example.com"], mail.from
|
||||||
|
assert_match "Hi", mail.body.encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
test "expired_30d_ago" do
|
||||||
|
mail = NotificationMailer.expired_30d_ago
|
||||||
|
assert_equal "Expired 30d ago", mail.subject
|
||||||
|
assert_equal ["to@example.org"], mail.to
|
||||||
|
assert_equal ["from@example.com"], mail.from
|
||||||
|
assert_match "Hi", mail.body.encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
test "expired_60d_ago" do
|
||||||
|
mail = NotificationMailer.expired_60d_ago
|
||||||
|
assert_equal "Expired 60d ago", mail.subject
|
||||||
|
assert_equal ["to@example.org"], mail.to
|
||||||
|
assert_equal ["from@example.com"], mail.from
|
||||||
|
assert_match "Hi", mail.body.encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
test "cancelled" do
|
||||||
|
mail = NotificationMailer.cancelled
|
||||||
|
assert_equal "Cancelled", mail.subject
|
||||||
|
assert_equal ["to@example.org"], mail.to
|
||||||
|
assert_equal ["from@example.com"], mail.from
|
||||||
|
assert_match "Hi", mail.body.encoded
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
34
test/mailers/previews/notification_mailer_preview.rb
Normal file
34
test/mailers/previews/notification_mailer_preview.rb
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Preview all emails at http://localhost:3000/rails/mailers/notification_mailer
|
||||||
|
class NotificationMailerPreview < ActionMailer::Preview
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/expiration_in_60d
|
||||||
|
def expiration_in_60d
|
||||||
|
NotificationMailer.expiration_in_60d
|
||||||
|
end
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/expiration_in_30d
|
||||||
|
def expiration_in_30d
|
||||||
|
NotificationMailer.expiration_in_30d
|
||||||
|
end
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/expired
|
||||||
|
def expired
|
||||||
|
NotificationMailer.expired
|
||||||
|
end
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/expired_30d_ago
|
||||||
|
def expired_30d_ago
|
||||||
|
NotificationMailer.expired_30d_ago
|
||||||
|
end
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/expired_60d_ago
|
||||||
|
def expired_60d_ago
|
||||||
|
NotificationMailer.expired_60d_ago
|
||||||
|
end
|
||||||
|
|
||||||
|
# Preview this email at http://localhost:3000/rails/mailers/notification_mailer/cancelled
|
||||||
|
def cancelled
|
||||||
|
NotificationMailer.cancelled
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
26
test/models/member_test.rb
Normal file
26
test/models/member_test.rb
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class MemberTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@member = Member.create!(
|
||||||
|
email: 'dsfargeg@example.com',
|
||||||
|
display_name: 'dsfargeg',
|
||||||
|
joined_on: Date.today,
|
||||||
|
expires_on: Date.today + 1.year
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "no expired in the first year and 90 days" do
|
||||||
|
(1.year + 90.days).in_days.to_i.times do |n|
|
||||||
|
Timecop.freeze(Date.today + n.days) do
|
||||||
|
assert_not_equal @member.expected_status, :cancelled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "expired after 1 year and 90 days" do
|
||||||
|
Timecop.freeze(Date.today + 1.year + 90.days) do
|
||||||
|
assert_equal @member.expected_status, :cancelled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
test/models/notification_test.rb
Normal file
7
test/models/notification_test.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class NotificationTest < ActiveSupport::TestCase
|
||||||
|
# test "the truth" do
|
||||||
|
# assert true
|
||||||
|
# end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user