diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index b735090..1e9e983 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -1,7 +1,25 @@ /* Application styles */ -table { border: 1px solid black; } +body { + max-width: 800px; + margin: 0 auto; +} -td, th { padding: 10px; } +table { + border: 1px solid black; + border-collapse: collapse; + margin: 20px 0; + width: calc(100% - 42px); +} -.new_contribution_form { max-width: 600px; } +td, th { padding: 10px; text-align: left; } + +table.zebra tr:nth-child(2n) { background-color: #eee; } +table.lined tr:nth-child(n + 2) td { border-top: 1px solid #eee; } + +ul { + padding-left: 5px; + margin: 0; +} + +li { padding: 5px 0px; } diff --git a/app/controllers/contributions_controller.rb b/app/controllers/contributions_controller.rb index 08820f5..15d812c 100644 --- a/app/controllers/contributions_controller.rb +++ b/app/controllers/contributions_controller.rb @@ -1,6 +1,6 @@ class ContributionsController < ApplicationController before_action :set_member, only: %i[ new create ] - before_action :set_contribution, only: %i[ edit ] + before_action :set_contribution, only: %i[ edit update delete destroy ] # GET /members/new def new @@ -27,14 +27,26 @@ class ContributionsController < ApplicationController 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 + # PATCH/PUT /members/1 + def update + if @contribution.update(contribution_params) + redirect_to @contribution.member, notice: "Contribution was successfully updated." + else + render :edit, status: :unprocessable_entity + end + end + # + # GET /members/1/delete + def delete + end + + # DELETE /members/1 + def destroy + @member = @contribution.member + @contribution.destroy + + redirect_to @member, notice: "Member personal data permanently removed." + end private # Use callbacks to share common setup or constraints between actions. diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 11bccae..a69ad47 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -1,5 +1,5 @@ class MembersController < ApplicationController - before_action :set_member, only: %i[ show edit update destroy ] + before_action :set_member, only: %i[ show edit update delete destroy ] helper_method :sort_params # GET /members @@ -46,6 +46,17 @@ class MembersController < ApplicationController end end + # GET /members/1/delete + def delete + end + + # DELETE /members/1 + def destroy + @member.remove_personal_information! + + redirect_to members_path, notice: "Member personal data permanently removed." + end + private # Use callbacks to share common setup or constraints between actions. def set_member diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5da3d9b..c4c7516 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,4 +2,8 @@ module ApplicationHelper def member_status(status) t("members.status.#{status}") end + + def notification_status(status) + t("notifications.status.#{status}") + end end diff --git a/app/models/member.rb b/app/models/member.rb index a036845..7f7024a 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -1,4 +1,5 @@ class Member < ApplicationRecord + default_scope { where(excluded: false) } has_many :contributions has_many :notifications @@ -10,6 +11,17 @@ class Member < ApplicationRecord update(status: expected_status) end + def remove_personal_information! + update( + excluded: true, + display_name: "", + email: nil, + identification_number: "", + category: "", + address: "", + ) + end + def expected_status if joined_on.nil? :pending diff --git a/app/views/contributions/delete.html.erb b/app/views/contributions/delete.html.erb new file mode 100644 index 0000000..f21488f --- /dev/null +++ b/app/views/contributions/delete.html.erb @@ -0,0 +1,28 @@ +

<%= notice %>

+ +

<%= t('contributions.delete.title') %>

+ +

<%= t('contributions.delete.confirmation_message') %>

+ + + + + + + + + + +
<%= t('members.attributes.display_name') %><%= @contribution.member.display_name %>
<%= t('members.attributes.email') %><%= @contribution.member.email %>
<%= t('members.attributes.category') %><%= @contribution.member.category %>
<%= t('members.attributes.identification_number') %><%= @contribution.member.identification_number %>
<%= t('members.attributes.address') %><%= simple_format @contribution.member.address %>
<%= t('members.attributes.joined_on') %><%= @contribution.member.joined_on %>
<%= t('members.attributes.expires_on') %><%= @contribution.member.expires_on %>
<%= t('members.attributes.status') %><%= @contribution.member.status %>
+ + +<%= form_with model: @contribution, method: :delete do |form| %> +
+ <%= form.submit t('contributions.delete.actions.submit') %> +
+ +
+ <%= link_to t('contributions.delete.actions.go_back'), members_path %> +
+<% end %> + diff --git a/app/views/contributions/edit.html.erb b/app/views/contributions/edit.html.erb index 91b1ebf..dec8906 100644 --- a/app/views/contributions/edit.html.erb +++ b/app/views/contributions/edit.html.erb @@ -1,22 +1,36 @@ -editando contriboot +

<%= t('contributions.edit.title') %>

<%= form_with(model: @contribution) do |form| %> - - - - - - - - - - - - - - - - - -
Amount€<%= @contribution.eurocents %>
Payment date€<%= @contribution.payment_on %>
Payment method<%= @contribution.payment_method %>
Payment reference<%= @contribution.payment_reference %>
+ + + + + + + + + + + + + + + + + + + + + +
<%= t('contributions.edit.member') %> + <%= link_to @contribution.member do %> + <%= @contribution.member.number %>. + <%= @contribution.member.display_name %> + <<%= @contribution.member.email %>> + <% end %> +
<%= form.number_field :eurocents, required: true %>
<%= form.date_field :payment_on %>
<%= form.select :payment_method, %w[iban mbway multibanco] %>
<%= form.text_field :payment_reference %>
+ +
+ <%= form.submit t('contributions.edit.actions.submit') %> +
<% end %> diff --git a/app/views/contributions/new.html.erb b/app/views/contributions/new.html.erb index 4eb3f92..40272bf 100644 --- a/app/views/contributions/new.html.erb +++ b/app/views/contributions/new.html.erb @@ -1,39 +1,46 @@ -

Registering contribution for <%= @member.display_name %>

- - - - - -
Member number<%= @member.number %>
Joined on<%= @member.joined_on %>
Expires on<%= @member.expires_on %>
- +

<%= t('contributions.new.title') %>

<%= form_with(model: [@member, @contribution]) do |form| %> - + + + + + - + - + - + + + + + + + + +
<%= t('contributions.new.member') %> + <%= link_to @member do %> + <%= @member.number %>. + <%= @member.display_name %> + <<%= @member.email %>> + <% end %> +
<%= form.number_field :eurocents %>
<%= form.date_field :payment_on %>
<%= form.select :payment_method, %w[iban mbway multibanco] %>
<%= form.text_field :payment_reference %>
- 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: + <%= t('contributions.new.expires_on_warning') %>
<%= t('members.attributes.joined_on') %><%= @member.joined_on %>
<%= t('members.attributes.expires_on') %><%= @member.expires_on %>
diff --git a/app/views/members/delete.html.erb b/app/views/members/delete.html.erb new file mode 100644 index 0000000..dea23a6 --- /dev/null +++ b/app/views/members/delete.html.erb @@ -0,0 +1,27 @@ +

<%= notice %>

+ +

<%= t('members.delete.title') %>

+ +

<%= t('members.delete.confirmation_message') %>

+ + + + + + + + + + +
<%= t('members.attributes.display_name') %><%= @member.display_name %>
<%= t('members.attributes.email') %><%= @member.email %>
<%= t('members.attributes.category') %><%= @member.category %>
<%= t('members.attributes.identification_number') %><%= @member.identification_number %>
<%= t('members.attributes.address') %><%= simple_format @member.address %>
<%= t('members.attributes.joined_on') %><%= @member.joined_on %>
<%= t('members.attributes.expires_on') %><%= @member.expires_on %>
<%= t('members.attributes.status') %><%= @member.status %>
+ + +<%= form_with model: @member, method: :delete do |form| %> +
+ <%= form.submit t('members.delete.actions.submit') %> +
+ +
+ <%= link_to t('members.delete.actions.go_back'), members_path %> +
+<% end %> diff --git a/app/views/members/index.html.erb b/app/views/members/index.html.erb index 71dc6c5..e8556b7 100644 --- a/app/views/members/index.html.erb +++ b/app/views/members/index.html.erb @@ -14,18 +14,16 @@ <% end %> <% end %> - - - - - - - - - - - - +
<%= link_to_current_with_sort t('members.attributes.number'), 'number.asc' %><%= link_to_current_with_sort t('members.attributes.status'), 'status.asc' %><%= link_to_current_with_sort t('members.attributes.email'), 'email.asc' %><%= link_to_current_with_sort t('members.attributes.display_name'), 'display_name.asc' %><%= link_to_current_with_sort t('members.attributes.joined_on'), 'joined_on.asc' %><%= link_to_current_with_sort t('members.attributes.expires_on'), 'expires_on.asc' %><%= t('members.index.actions.title') %>
+ + + + + + + + + <% @members.each do |member| %> @@ -35,9 +33,12 @@ <% end %> diff --git a/app/views/members/show.html.erb b/app/views/members/show.html.erb index 7d45f55..5b09eda 100644 --- a/app/views/members/show.html.erb +++ b/app/views/members/show.html.erb @@ -2,7 +2,7 @@

<%= t('members.show.title') %>

-
<%= link_to_current_with_sort t('members.attributes.number'), 'number.asc' %><%= link_to_current_with_sort t('members.attributes.status'), 'status.asc' %><%= link_to_current_with_sort t('members.attributes.email'), 'email.asc' %><%= link_to_current_with_sort t('members.attributes.display_name'), 'display_name.asc' %><%= link_to_current_with_sort t('members.attributes.joined_on'), 'joined_on.asc' %><%= link_to_current_with_sort t('members.attributes.expires_on'), 'expires_on.asc' %><%= t('members.index.actions.title') %>
<%= member.number %><%= member.joined_on %> <%= member.expires_on %> - <%= 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) %> +
    +
  • <%= 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) %>
  • +
  • <%= link_to t('members.index.actions.delete'), delete_member_path(member) %>
  • +
+
@@ -19,12 +19,12 @@

<%= t('members.show.contribution_history') %>

-
<%= t('members.attributes.display_name') %><%= @member.display_name %>
<%= t('members.attributes.email') %><%= @member.email %>
<%= t('members.attributes.category') %><%= @member.category %>
+
- - - - + + + + <% @member.contributions.each do |contribution| %> @@ -33,8 +33,31 @@ <% end %>
Payment datePayment methodPayment referenceAmount<%= t('contributions.attributes.payment_on') %><%= t('contributions.attributes.payment_method') %><%= t('contributions.attributes.payment_reference') %><%= t('contributions.attributes.amount') %>
<%= contribution.payment_reference %> €<%= contribution.eurocents %> - <%= link_to t('members.show.actions.edit_contribution'), edit_contribution_path(contribution) %> +
    +
  • <%= link_to t('members.show.actions.edit_contribution'), edit_contribution_path(contribution) %> +
  • <%= link_to t('members.show.actions.delete_contribution'), delete_contribution_path(contribution) %>
  • +
+ +

+ +

<%= t('members.show.notifications') %>

+ + + + + + + + <% @member.notifications.order(to_be_sent_on: :desc).each do |notification| %> + + + + + + <% end %> +
<%= t('notifications.attributes.to_be_sent_on') %><%= t('notifications.attributes.template') %><%= t('notifications.attributes.status') %>
<%= notification.to_be_sent_on %><%= notification.template %><%= notification_status(notification.status) %>
+ diff --git a/config/locales/en.yml b/config/locales/en.yml index 3adf8af..3d357e1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -44,6 +44,14 @@ en: unemployed: "Unemployed" student: "Student" retired: "Retired" + contributions: + new: + expires_on_warning: | + 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. notification_mailer: expiration_in_60d: subject: "ANSOL - Pagamento anual de quotas" diff --git a/config/locales/pt.yml b/config/locales/pt.yml index aa915a4..b6fa5e6 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -2,6 +2,16 @@ pt: navigation: members: "Lista de membros" members: + delete: + confirmation_message: | + Tens a certeza que queres apagar o registo deste membro + permanentemente? Esta acção vai apagar todos os dados pessoais da + pessoa em questão, mas não irá apagar o registo de contribuições, caso + estas sejam necessárias por motivos legais/fiscais. + title: "Remover membro permanentemente" + actions: + submit: "Confirmar remoção" + go_back: "Cancelar" index: title: "Membros" actions: @@ -16,6 +26,9 @@ pt: actions: edit: "Editar detalhes" edit_contribution: "Editar" + delete_contribution: "Apagar" + contribution_history: "Histórico de contribuições" + notifications: "Notificações por correio electrónico" edit: title: "Editar detalhes de membro" actions: @@ -46,6 +59,34 @@ pt: unemployed: "Desempregado" student: "Estudante" retired: "Reformado" + notifications: + attributes: + to_be_sent_on: Data de envio + template: Modelo + status: Estado + status: + sent: Enviada + scheduled: Agendada + contributions: + attributes: + amount: Montante + payment_on: Data de pagamento + payment_method: Método de pagamento + payment_reference: Referência + edit: + member: "Membro" + title: "Editar dados de contribuição" + actions: + submit: "Gravar" + new: + member: "Membro" + title: "Registar contribuição" + expires_on_warning: | + Ao registar uma contribuição, o sistema estende a data de expiração por + um ano automaticamente. Se for a primeira contribuição deste membro, a + data de inscrição é automaticamente definida como a data de pagamento, + e a data de expiração passa a ser um ano após essa data. Podes definir + uma data de expiração manualmente usando o próximo campo. notification_mailer: expiration_in_60d: subject: "ANSOL - Pagamento anual de quotas" diff --git a/config/routes.rb b/config/routes.rb index 29828f3..f21fa29 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,8 +5,15 @@ Rails.application.routes.draw do # root "articles#index" resources :members do + member do + get :delete + end resources :contributions, only: [:new, :create] end - resources :contributions, only: [:edit, :update] + resources :contributions, only: [:edit, :update, :destroy] do + member do + get :delete + end + end end diff --git a/db/migrate/20220625174250_add_excluded_to_members.rb b/db/migrate/20220625174250_add_excluded_to_members.rb new file mode 100644 index 0000000..4c4c607 --- /dev/null +++ b/db/migrate/20220625174250_add_excluded_to_members.rb @@ -0,0 +1,7 @@ +class AddExcludedToMembers < ActiveRecord::Migration[7.0] + def change + change_table :members do |t| + t.boolean :excluded, default: false + end + end +end diff --git a/db/migrate/20220625181824_remove_null_constraints_from_member.rb b/db/migrate/20220625181824_remove_null_constraints_from_member.rb new file mode 100644 index 0000000..e4963f7 --- /dev/null +++ b/db/migrate/20220625181824_remove_null_constraints_from_member.rb @@ -0,0 +1,6 @@ +class RemoveNullConstraintsFromMember < ActiveRecord::Migration[7.0] + def change + change_column_null :members, :email, true + change_column_null :members, :display_name, true + end +end diff --git a/db/schema.rb b/db/schema.rb index fead68e..acaad17 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do +ActiveRecord::Schema[7.0].define(version: 2022_06_25_181824) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -28,8 +28,8 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do 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 "email" + t.string "display_name" t.string "identification_number" t.string "status" t.string "category" @@ -40,6 +40,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_24_134509) do t.date "expires_on" t.string "regular_ifthenpay_link" t.string "reduced_ifthenpay_link" + t.boolean "excluded", default: false t.index ["email"], name: "index_members_on_email", unique: true t.index ["number"], name: "index_members_on_number", unique: true end