diff --git a/Gemfile b/Gemfile index b6a5c6d8..5b7828e0 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,7 @@ gem 'faraday' gem 'image_processing', '>= 1.2' gem 'jbuilder' gem 'jsbundling-rails' +gem 'money-rails', '~> 1.12' gem 'puma', '~> 6.0' gem 'simple_calendar' gem 'sprockets-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 25e3e9ee..83cf7978 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -167,6 +167,15 @@ GEM mini_magick (4.13.2) mini_mime (1.1.5) minitest (5.24.1) + monetize (1.13.0) + money (~> 6.12) + money (6.19.0) + i18n (>= 0.6.4, <= 2) + money-rails (1.15.0) + activesupport (>= 3.0) + monetize (~> 1.9) + money (~> 6.13) + railties (>= 3.0) msgpack (1.7.2) mutex_m (0.2.0) net-http (0.4.1) @@ -342,6 +351,7 @@ DEPENDENCIES image_processing (>= 1.2) jbuilder jsbundling-rails + money-rails (~> 1.12) puma (~> 6.0) rails (~> 7.1.3.1) rspec-rails diff --git a/README.md b/README.md index 9d1372e7..9bb61c46 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@
- + [![Contributors][contributors-shield]][contributors-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![MIT License][license-shield]][license-url] [![Status][status-shield]][status-url] + +
@@ -27,9 +29,9 @@ Sumário
  1. - Sobre o projeto + Sobre o Projeto @@ -39,10 +41,10 @@
  2. @@ -73,19 +75,30 @@ ## Funcionalidades -

    Usuários administrativos podem ser cadastrados no sistema e usuários proprietários e moradores podem ser convidados por e-mail a se registrar.

    +

    :trophy:Usuários administrativos podem ser cadastrados no sistema e usuários proprietários e moradores podem ser convidados por e-mail a se registrar;

    + +

    :trophy:Apenas usuários administrativos categorizados como super no momento da criação podem cadastrar outros usuários administrativos, cadastrar um condomínio com endereço e associar um usuário ou mais usuários administrativos àquele condomínio;

    + +

    :trophy:Usuários administrativos regulares podem cadastrar torres, tipos de unidade, unidade de um condomínio, andares, áreas comuns e moradores;

    + +

    :trophy:A fração ideal de cada unidade é gerada automaticamente com base no tamanho de cada uma e a quantidade de unidades em um condomínio;

    + +

    :trophy:Tanto administradores quanto moradores podem ver a página de listatrophy e detalhes de condomínio. Tendo sua exibição alterada para cada tipo de usuário;

    + +

    :trophy:Moradores podem fazer uma reserva de área comum a partir de um calendário de reservas, bem como cancelar essa reserva. Gerando ou cancelando cobrança de taxa de uso dessa reserva na aplicação PagueAluguel;

    + +

    :trophy:Moradores podem consultar suas faturas e enviar comprovantes de pagamento que serão comunicados através da aplicação PagueAluguel;

    -

    Apenas usuários administrativos categorizados como super no momento da criação podem cadastrar outros usuários administrativos, cadastrar um condomínio com endereço e associar um usuário ou mais usuários administrativos àquele condomínio.

    +

    :trophy:Administradores podem registrar entrada de visitantes no condomínio e visualizar uma lista com o histórico de visitas;

    + +

    :trophy:Administradores podem criar avisos para serem mostrados em um mural na tela de detalhes de um condomínio.

    -

    Usuários administrativos regulares podem cadastrar torres, tipos de unidade, unidade de um condomínio, andares, áreas comuns e moradores.

    -

    Tanto administradores quanto moradores podem ver a página de listagem e detalhes de condomínio. Tendo sua exibição alterada para cada tipo de usuário.

    -

    Moradores podem fazer uma reserva de área comum, bem como cancelar essa reserva.

    (voltar ao topo)

    -
    +
    ## Endpoints da API @@ -124,7 +137,7 @@ Retorna erro 404 caso não exista um condomínio cadastrado com esse id.

    Exemplo de resposta: ```json { - "name": "Condominio Residencial Paineiras", + "name": "Condomínio Residencial Paineiras", "registration_number": "62.810.952/2718-22", "address": { "public_place": "Travessa João Edimar", @@ -290,7 +303,7 @@ Possíveis respostas ``` Retorna 404 se não existe um proprietário com o CPF informado na aplicação CondoMínios, ou se existe, mas não possui nenhuma unidade como propriedade; Retorna 412 se o CPF não for válido para consulta. -Retorna 200 se o CPF é de um proprietário de alguma unidade e o seguinte JSON +Retorna 200 se o CPF é de um proprietário de alguma unidade e o seguinte JSON. ``` ```json @@ -371,7 +384,7 @@ Exemplo de Resposta: ``` -

    caso não existam áreas comuns cadastradas para o condomínio informado retorna o `id` do condomínio e um array vazio.

    +

    Caso não existam áreas comuns cadastradas para o condomínio informado retorna o `id` do condomínio e um array vazio.

    Retorna erro `404` caso o condomínio informado não esteja cadastrado.

    @@ -384,17 +397,20 @@ Exemplo de Resposta: Exemplo de Resposta: ```json { - "name": "Piscina", - "description": "Para adultos e crianças", - "max_occupancy": 20, - "rules": "Só pode ser usada até 22h", - "condo_id": 1 + "name": "Piscina", + "description": "Para adultos e crianças", + "max_occupancy": 20, + "rules": "Só pode ser usada até 22h", + "condo_id": 1 } ```

    Retorna erro `404` caso a área comum informada não esteja cadastrada para o condomínio informado.

    + +
    + ## Instalação e Execução
    @@ -403,10 +419,14 @@ Exemplo de Resposta:

    Você vai precisar da versão 3.2.2 do Ruby, libvips e uma versão atual de NodeJS com Yarn instalado. Recomendamos sempre a instalação das versões LTS (Long Term Support).

    -#### Instalação do [libvips](https://github.com/libvips/libvips/wiki/Build-for-Ubuntu) no ubuntu: +Instalação do [libvips](https://github.com/libvips/libvips/wiki/Build-for-Ubuntu) com o apt-get: ```sh sudo apt install libvips ``` +Instalação do rails +``` +gem install rails +```
    @@ -420,6 +440,10 @@ Entre na pasta do projeto: ```sh cd condominions ``` +Instale Bundle: +```sh +bundle install +``` Instale as dependências: ```sh bin/setup @@ -429,14 +453,27 @@ Para popular o banco de dados: rails db:seed ``` -
    - +
    + ### Execução de Testes + Para rodar os testes, execute: ```sh rake spec ``` +### Testando E-mails + +Caso queria testar emails, você pode fazê-lo instalando a gem [MailCatcher](https://mailcatcher.me/): +```sh +gem install mailcatcher +``` +Para executar o MailCatcher: +```sh +mailcatcher +``` +Agora você pode acessá-lo através da rota http://localhost:1080/ +
    ### Execução da Aplicação @@ -446,40 +483,39 @@ bin/dev ``` Agora é possível acessar a aplicação a partir da rota http://localhost:3000/ +**Integração com o PagueAluguel**: Essa aplicação foi construída para ser integrada com o [PagueAluguel](https://github.com/TreinaDev/pague-aluguel). Com ambas as aplicações rodando, você poderá utilizá-la com todas as suas funcionalidades! +

    (voltar ao topo)

    ## Estrutura do Banco de Dados -![Estrutura do banco de dados](https://i.imgur.com/emiKwf5.png) +![Estrutura do banco de dados](https://github.com/user-attachments/assets/ee40045d-5e22-4404-96c8-be0c573b4fd6)

    (voltar ao topo)

    -
    +
    -## Banco de Dados Iniciais +## Seeds de Usuários -Dados inseridos no seeds +Esses usuários são gerados nas seeds e você pode utilizá-los para testar a aplicação. >Administradores ->>|Nome Completo|CPF|E-mail|Senha| ->>| :--------: | :--------: |:--------: | :--------: | ->>|Murilo Pereira Rocha|745.808.535-55|adm@teste.com|teste123| - ->Endereços ->>|Rua|Número|Bairro|Cidade|Estado|CEP|ID| ->>| :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | :--------: | ->>|Travessa João Edimar|29|João Eduardo II|Rio Branco|AC|69911-520| 1 | +>>|Nome Completo|E-mail|Senha| +>>| :--------: | :--------: |:--------: | +>>|Ednaldo Pereira|adm@teste.com|teste123| +>>|Adroaldo Silva Santos|adm@teste.com|teste123| ->Condominions ->>|Nome do condomínio|CNPJ|ID do endereço| ->>| :--------: | :--------: | :--------: | ->>|Condominio Residencial Paineiras|62.810.952/2718-22| 1 | +>Residentes +>>|Nome Completo|E-mail|Senha| +>>| :--------: | :--------: |:--------: | +>>|Marina Santos Oliveira|marina@email.com|teste123| +>>|Rafael Souza Lima|rafael@email.com|teste123|

    (voltar ao topo)

    -
    +
    ## Desenvolvedores @@ -508,4 +544,4 @@ Dados inseridos no seeds [Ruby-url]: https://www.ruby-lang.org/en/news/2023/03/30/ruby-3-2-2-released/ [RubyOnRails.com]: https://img.shields.io/static/v1?label=Ruby%20On%20Rails&message=7.1.3.1&color=red&style=for-the-badge&logo=rubyonrails [RubyOnRails-url]: https://rubyonrails.org/2023/11/10/Rails-7-1-2-has-been-released -[EstruturaDoBancoDeDados-URL]: https://i.imgur.com/emiKwf5.png \ No newline at end of file +[EstruturaDoBancoDeDados-URL]: https://i.imgur.com/emiKwf5.png diff --git a/app/assets/stylesheets/style.scss b/app/assets/stylesheets/style.scss index 80417b02..d984cfd7 100644 --- a/app/assets/stylesheets/style.scss +++ b/app/assets/stylesheets/style.scss @@ -1,7 +1,3 @@ -body { - margin-bottom: 4rem; -} - // Colors .bg-light-gray { @@ -12,6 +8,10 @@ body { background-color: #FDE879; } +.bg-blue-cyan { + background-color: #1985A1 +} + .bg-medium-blue-lighter { background-color: #577998; } @@ -20,6 +20,10 @@ body { background-color: #4c677f; } +.bg-medium-blue-dark { + background-color: #3f556f; +} + // Images .user-image-200 { width: 200px; diff --git a/app/controllers/announcements_controller.rb b/app/controllers/announcements_controller.rb index 2176cf64..9b31cf50 100644 --- a/app/controllers/announcements_controller.rb +++ b/app/controllers/announcements_controller.rb @@ -54,7 +54,7 @@ def set_breadcrumbs_for_action def set_breadcrumbs_for_details add_breadcrumb @announcement.condo.name, condo_path(@announcement.condo) - add_breadcrumb @announcement.title, common_area_path(@announcement) + add_breadcrumb @announcement.title, @announcement end def set_announcement diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e1b08c50..f7a0e0bf 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -25,6 +25,12 @@ def authorize_super_manager not_authorized_redirect unless current_manager.is_super end + def authorize_condo_manager_superintendent(condo) + return if authorize_manager(condo) || (authorize_resident(condo) && current_resident&.superintendent) + + not_authorized_redirect + end + def authorize_condo_manager(condo) not_authorized_redirect unless authorize_manager(condo) end @@ -44,7 +50,7 @@ def authorize_manager(condo) end def authorize_resident(condo) - resident_signed_in? && condo.residents.include?(current_resident) + resident_signed_in? && condo && condo.residents.include?(current_resident) end def not_authorized_redirect diff --git a/app/controllers/fines_controller.rb b/app/controllers/fines_controller.rb new file mode 100644 index 00000000..939fb9ce --- /dev/null +++ b/app/controllers/fines_controller.rb @@ -0,0 +1,85 @@ +class FinesController < ApplicationController + before_action :set_condo, only: %i[new create] + before_action :authorize_superintendent, only: %i[new create] + before_action :set_breadcrumbs_for_register, only: %i[new create] + + def new + @fine = SingleCharge.new(condo: @condo) + end + + def create + @fine = SingleCharge.new(fine_params) + + if @fine.valid? + return redirect_to @condo if post_response + + flash.now.alert = t('alerts.single_charge.server_error') + else + flash.now.alert = t('alerts.single_charge.fine_not_created') + end + render 'new', status: :unprocessable_entity + end + + private + + def set_breadcrumbs_for_register + add_breadcrumb @condo.name.to_s, @condo + add_breadcrumb I18n.t('breadcrumb.fine.new') + end + + def authorize_superintendent + return if resident_signed_in? && @condo.superintendent && @condo.superintendent.tenant == current_resident + + redirect_to root_path + end + + def set_condo + @condo = Condo.find params[:condo_id] + end + + def find_tower_and_floor + return unless params['single_charge'] + + tower = Tower.find_by(id: params['single_charge']['tower_id']) + return tower.floors[params['single_charge']['floor'].to_i - 1] if tower + + nil + end + + def find_unit_id + floor = find_tower_and_floor + + return floor.units[params['single_charge']['unit'].to_i - 1].id if floor + + nil + end + + def fine_params + params.require(:single_charge) + .permit(:value, :description) + .merge({ charge_type: :fine, condo: @condo, unit_id: find_unit_id }) + end + + def single_charge_params + { single_charge: { + description: @fine.description, + value_cents: @fine.value_cents, + charge_type: @fine.charge_type, + issue_date: Time.zone.today, + condo_id: @fine.condo.id, + common_area_id: nil, + unit_id: @fine.unit.id + } } + end + + def post_response + request = Faraday.new(url: Rails.configuration.api['base_url'].to_s) + .post('/api/v1/single_charges/', single_charge_params.to_json, + 'Content-Type' => 'application/json') + return flash.notice = "Multa lançada com sucesso para a #{@fine.unit.print_identifier}" if request.success? + + nil + rescue Faraday::ConnectionFailed + nil + end +end diff --git a/app/controllers/residents/passwords_controller.rb b/app/controllers/residents/passwords_controller.rb new file mode 100644 index 00000000..7e480021 --- /dev/null +++ b/app/controllers/residents/passwords_controller.rb @@ -0,0 +1,23 @@ +module Residents + class PasswordsController < Devise::PasswordsController + def edit + add_breadcrumb I18n.t('breadcrumb.resident.edit_password') + self.resource = find_resource_by_token + + return redirect_to root_path, alert: t('alerts.resident.invalid_token') unless valid_token? + + sign_out(current_manager || current_resident) if anyone_signed_in? + super + end + + private + + def find_resource_by_token + resource_class.with_reset_password_token(params[:reset_password_token]) + end + + def valid_token? + resource.present? && resource.reset_password_period_valid? + end + end +end diff --git a/app/controllers/residents_controller.rb b/app/controllers/residents_controller.rb index 089013ff..eac75cc1 100644 --- a/app/controllers/residents_controller.rb +++ b/app/controllers/residents_controller.rb @@ -1,7 +1,9 @@ class ResidentsController < ApplicationController - before_action :authenticate_manager!, only: %i[new create find_towers show] + before_action :authenticate_manager!, only: %i[new create show] before_action :set_resident, only: %i[update edit_photo update_photo show] before_action :authenticate_resident!, only: %i[update edit_photo update_photo] + before_action :set_condo, only: %i[find_towers] + before_action -> { authorize_condo_manager_superintendent(@condo) }, only: %i[find_towers] def show add_breadcrumb I18n.t('breadcrumb.resident.show') @@ -46,13 +48,12 @@ def update end def find_towers - condo = Condo.find_by(id: params[:id]) - return render status: :not_found, json: [] unless condo + return render status: :not_found, json: [] unless @condo - towers = condo.towers + towers = @condo.towers return render status: :not_found, json: [] if towers.empty? - render json: condo.towers.to_json(only: %i[id name units_per_floor floor_quantity]) + render json: @condo.towers.to_json(only: %i[id name units_per_floor floor_quantity]) end def confirm @@ -93,6 +94,10 @@ def find_unit_id private + def set_condo + @condo = Condo.find_by(id: params[:id]) + end + def authenticate_resident! return redirect_to root_path if manager_signed_in? diff --git a/app/controllers/tenants_controller.rb b/app/controllers/tenants_controller.rb index 77f72b91..af8c6921 100644 --- a/app/controllers/tenants_controller.rb +++ b/app/controllers/tenants_controller.rb @@ -8,7 +8,7 @@ def new; end def create return unless update_resident_for_valid_unit - @resident.mail_not_confirmed! && send_email if @resident.residence_registration_pending? + return @resident.mail_not_confirmed! && send_email if @resident.residence_registration_pending? redirect_to @resident, notice: t('notices.tenant.updated') end @@ -29,6 +29,7 @@ def send_email random_password = SecureRandom.alphanumeric 8 @resident.update password: random_password @resident.send_invitation random_password + redirect_to @resident, notice: t('notices.resident.send_email') end def update_resident_for_valid_unit diff --git a/app/controllers/visitor_entries_controller.rb b/app/controllers/visitor_entries_controller.rb index bf18624f..93620c0a 100644 --- a/app/controllers/visitor_entries_controller.rb +++ b/app/controllers/visitor_entries_controller.rb @@ -10,7 +10,7 @@ def index @result = [] params.permit(:full_name, :visit_date, :identity_number).each do |key, value| - key = 'created_at' if key == 'visit_date' + key = 'database_datetime' if key == 'visit_date' @result << find_visitor_entries(key, value) if value.present? end diff --git a/app/javascript/controllers/fines_controller.js b/app/javascript/controllers/fines_controller.js new file mode 100644 index 00000000..d07c9f34 --- /dev/null +++ b/app/javascript/controllers/fines_controller.js @@ -0,0 +1,40 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ['condo', 'tower', 'floor', 'unit'] + + searchTowers(condoId) { + fetch(`${window.origin}/residents/find_towers?id=${condoId}`) + .then((response) => { + return response.json() + }) + .then((towers) => { + this.towerTarget.innerHTML = "" + towers.forEach(tower => { + this.towerTarget.options.add(new Option(tower.name, tower.id)) + }); + this.towers = towers + this.changeTower() + }) + .catch(() => { console.log('Towers not found') }) + } + + connect() { + this.searchTowers(this.element.getAttribute('condo-id')) + } + + changeTower() { + let tower = this.towers[this.towerTarget.selectedIndex] + console.log(tower) + this.unitTarget.innerHTML = "" + this.floorTarget.innerHTML = "" + + for (let floor = 1; floor <= tower.floor_quantity; floor++) { + this.floorTarget.options.add(new Option(`${floor}`, `${floor}`)) + } + + for (let unit = 1; unit <= tower.units_per_floor; unit++) { + this.unitTarget.options.add(new Option(`${unit}`, `${unit}`)) + } + } +} \ No newline at end of file diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 486e14af..8c6c7bb1 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -20,3 +20,6 @@ application.register("resident", ResidentController) import UnitsController from "./units_controller" application.register("units", UnitsController) + +import FinesController from "./fines_controller" +application.register("fines", FinesController) diff --git a/app/models/single_charge.rb b/app/models/single_charge.rb new file mode 100644 index 00000000..b6d768f4 --- /dev/null +++ b/app/models/single_charge.rb @@ -0,0 +1,22 @@ +class SingleCharge < ApplicationRecord + belongs_to :condo + belongs_to :unit + belongs_to :common_area, optional: true + + validates :value_cents, :charge_type, presence: true + validates :description, presence: true, if: -> { charge_type == 'fine' } + + validate :unit_valid? + + enum charge_type: { fine: 0, common_area_fee: 1 } + + monetize :value_cents, as: :value, with_model_currency: :currency + + private + + def unit_valid? + return true if unit&.owner + + errors.add(:unit, 'não possui um proprietário.') + end +end diff --git a/app/models/tower.rb b/app/models/tower.rb index 04a0d2dc..c487473c 100644 --- a/app/models/tower.rb +++ b/app/models/tower.rb @@ -8,7 +8,7 @@ class Tower < ApplicationRecord validates :name, :floor_quantity, :units_per_floor, presence: true validates :floor_quantity, :units_per_floor, numericality: { - greater_than: 0, only_integer: true + greater_than: 0, only_integer: true, less_than: 200 } after_create :generate_floors diff --git a/app/models/unit.rb b/app/models/unit.rb index 5cae10e7..14edfee7 100644 --- a/app/models/unit.rb +++ b/app/models/unit.rb @@ -15,6 +15,10 @@ def short_identifier "#{floor.identifier}#{floor.units.index(self) + 1}" end + def identifier + floor.units.index(self) + 1 + end + def tower_identifier "#{floor.tower.name} - #{short_identifier}" end diff --git a/app/models/visitor_entry.rb b/app/models/visitor_entry.rb index cd2562da..69eef811 100644 --- a/app/models/visitor_entry.rb +++ b/app/models/visitor_entry.rb @@ -8,4 +8,12 @@ class VisitorEntry < ApplicationRecord validates :identity_number, length: { in: 5..10 } validates :identity_number, format: { with: ID_REGEX, message: I18n.t('alerts.visitor_entry.only_numbers_and_letters') } + + before_save :set_database_datetime + + private + + def set_database_datetime + self.database_datetime ||= (DateTime.now + Time.zone.utc_offset.seconds) + end end diff --git a/app/views/announcements/show.html.erb b/app/views/announcements/show.html.erb index 59b26eee..f2471e2e 100644 --- a/app/views/announcements/show.html.erb +++ b/app/views/announcements/show.html.erb @@ -13,8 +13,10 @@

    Atualizado em: <%= I18n.l(@announcement.updated_at, format: :custom) %>

    -
    - <%= link_to "Editar", edit_announcement_path(@announcement), class: "btn btn-dark rounded-pill px-4 me-2" %> - <%= link_to "Excluir", announcement_path(@announcement), data: { turbo_method: :delete, turbo_confirm: "Tem certeza que deseja excluir?" }, class: "btn btn-danger rounded-pill px-4" %> -
    + <% if manager_signed_in? %> +
    + <%= link_to "Editar", edit_announcement_path(@announcement), class: "btn btn-dark rounded-pill px-4 me-2" %> + <%= link_to "Excluir", announcement_path(@announcement), data: { turbo_method: :delete, turbo_confirm: "Tem certeza que deseja excluir?" }, class: "btn btn-danger rounded-pill px-4" %> +
    + <% end %> diff --git a/app/views/condos/show.html.erb b/app/views/condos/show.html.erb index 2459724c..a714e3eb 100644 --- a/app/views/condos/show.html.erb +++ b/app/views/condos/show.html.erb @@ -79,6 +79,19 @@ <% end %> <%= render 'condos/dashboard/common_area_list' %> + + <% if resident_signed_in? && current_resident&.superintendent %> + <%= link_to new_condo_fine_path(@condo), class:"btn py-2 rounded-pill d-flex justify-content-center align-items-center mb-2 shadow-sm mt-2", style: "width: 100%; background-color: #FDE879;" do %> + Lançar Multa + + + + + + + <% end %> + <% end %> +
    diff --git a/app/views/fines/new.html.erb b/app/views/fines/new.html.erb new file mode 100644 index 00000000..8817785d --- /dev/null +++ b/app/views/fines/new.html.erb @@ -0,0 +1,42 @@ +
    +

    Lançar Multa

    + <%= form_with model: [@condo, @fine], url: condo_fines_path(@condo, @fine) do |f| %> +
    +
    +
    + <%= f.label :tower_id %> + <%= f.collection_select :tower_id, {}, {}, {}, {}, :'data-fines-target' => "tower", :'data-action' => "change->fines#changeTower", class: "form-control form-select #{'is-invalid' if @fine.errors[:tower_id].any?}" %> + <%= render("shared/errors", model: @fine, attribute: :tower_id) if @fine.errors[:tower_id].any? %> +
    + +
    + <%= f.label :floor %> + <%= f.collection_select :floor, {}, {}, {}, {}, :'data-fines-target' => "floor", class: "form-control form-select #{'is-invalid' if @fine.errors[:floor].any?}" %> + <%= render("shared/errors", model: @fine, attribute: :floor) if @fine.errors[:floor].any? %> +
    + +
    + <%= f.label :unit %> + <%= f.collection_select :unit, {}, {}, {}, {}, :'data-fines-target' => "unit", class: "form-control form-select #{'is-invalid' if @fine.errors[:unit].any?}" %> + <%= render("shared/errors", model: @fine, attribute: :unit) if @fine.errors[:unit].any? %> +
    +
    +
    +
    + <%= f.label :description, class: "form-label" %> + <%= f.text_field :description, placeholder: 'Descreva o motivo da multa...', class: "form-control #{'is-invalid' if @fine.errors[:description].any?}" %> + <%= render("shared/errors", model: @fine, attribute: :description) if @fine.errors[:description].any? %> +
    + +
    + <%= f.label :value, class: "form-label" %> + <%= f.text_field :value, placeholder: '0,00', step: '0.01', pattern: '\d+(\,\d{2})?', class: "form-control #{'is-invalid' if @fine.errors[:value].any?}" %> + <%= render("shared/errors", model: @fine, attribute: :value) if @fine.errors[:value].any? %> +
    +
    +
    + <%= f.submit 'Lançar Multa', class: "btn btn-dark rounded-pill px-4 mt-3" %> +
    +
    + <% end %> +
    \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 16f23c2d..b108df2a 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -14,9 +14,11 @@ <%= render 'shared/navbar' %> -
    +
    <%= flash_messages %> - <%= yield %> + <%= yield %>
    + + <%= render 'shared/footer' %> diff --git a/app/views/owners/new.html.erb b/app/views/owners/new.html.erb index aa9ec179..96e29584 100644 --- a/app/views/owners/new.html.erb +++ b/app/views/owners/new.html.erb @@ -39,36 +39,36 @@

    Adicionar nova propriedade

    <%= form_with model: @resident, url: resident_owners_path(@resident), method: :post do |f| %> -
    -
    -
    - <%= f.label :condo_id %> - <%= f.collection_select :condo_id, @condos, :id, :name, {}, :'data-resident-target' => "condo", :'data-action' => "change->resident#changeCondo", class: 'form-control form-select' %> +
    +
    +
    + <%= f.label :condo_id %> + <%= f.collection_select :condo_id, @condos, :id, :name, {}, :'data-resident-target' => "condo", :'data-action' => "change->resident#changeCondo", class: 'form-control form-select' %> +
    -
    -
    -
    - <%= f.label :tower_id %> - <%= f.collection_select :tower_id, {}, {}, {}, {}, :'data-resident-target' => "tower", :'data-action' => "change->resident#changeTower", class: 'form-control form-select' %> -
    +
    +
    + <%= f.label :tower_id %> + <%= f.collection_select :tower_id, {}, {}, {}, {}, :'data-resident-target' => "tower", :'data-action' => "change->resident#changeTower", class: 'form-control form-select' %> +
    -
    - <%= f.label :floor %> - <%= f.collection_select :floor, {}, {}, {}, {}, :'data-resident-target' => "floor", class: 'form-control form-select' %> -
    +
    + <%= f.label :floor %> + <%= f.collection_select :floor, {}, {}, {}, {}, :'data-resident-target' => "floor", class: 'form-control form-select' %> +
    -
    - <%= f.label :unit %> - <%= f.collection_select :unit, {}, {}, {}, {}, :'data-resident-target' => "unit", class: 'form-control form-select' %> +
    + <%= f.label :unit %> + <%= f.collection_select :unit, {}, {}, {}, {}, :'data-resident-target' => "unit", class: 'form-control form-select' %> +
    -
    -
    - <%= f.submit 'Adicionar Propriedade', class:'btn btn-dark rounded-pill px-4 mt-3' %> - <%= f.submit 'Finalizar Cadastro de Propriedades', class: 'btn btn-dark rounded-pill px-4 mt-3 ms-3' %> +
    + <%= f.submit 'Adicionar Propriedade', class:'btn btn-dark rounded-pill px-4 mt-3' %> + <%= f.submit 'Finalizar Cadastro de Propriedades', class: 'btn btn-dark rounded-pill px-4 mt-3 ms-3' %> +
    -
    <% end %>
    \ No newline at end of file diff --git a/app/views/residents/confirm.html.erb b/app/views/residents/confirm.html.erb index b5fdf412..bb74e9b8 100644 --- a/app/views/residents/confirm.html.erb +++ b/app/views/residents/confirm.html.erb @@ -58,8 +58,8 @@ <%= form_with model: @resident do |f| %>
    - <%= f.label :user_image %> <%= f.file_field :user_image, class: 'form-control' %> + <%= f.label :user_image %>
    diff --git a/app/views/residents/passwords/edit.html.erb b/app/views/residents/passwords/edit.html.erb index 5c158d83..b86be82f 100644 --- a/app/views/residents/passwords/edit.html.erb +++ b/app/views/residents/passwords/edit.html.erb @@ -2,27 +2,25 @@

    Altere sua senha

    <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> - <%= render "residents/shared/error_messages", resource: resource %> <%= f.hidden_field :reset_password_token %> -
    -
    +
    +
    <%= f.label :password, "Nova senha" %> - <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> + <%= f.password_field :password, autofocus: true, autocomplete: "new-password", class: "form-control #{'is-invalid' if @resident.errors[:password].any?}" %> + <%= render("shared/errors", model: @resident, attribute: :password) if @resident.errors[:password].any? %> + <%= render("shared/errors2", model: @resident, attribute: :reset_password_token) if @resident.errors[:reset_password_token].any? %>
    -
    +
    <%= f.label :password_confirmation, "Confirme sua nova senha" %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> + <%= f.password_field :password_confirmation, autocomplete: "new-password", class: "form-control #{'is-invalid' if @resident.errors[:password_confirmation].any?}" %> + <%= render("shared/errors", model: @resident, attribute: :password_confirmation) if @resident.errors[:password_confirmation].any? %>
    -
    +
    <%= f.submit "Alterar minha senha", class: 'btn btn-dark rounded-pill px-4 mt-1' %>
    <% end %> - -
    - <%= render "residents/shared/links" %> -
    diff --git a/app/views/shared/_footer.html.erb b/app/views/shared/_footer.html.erb new file mode 100644 index 00000000..46b1ee5f --- /dev/null +++ b/app/views/shared/_footer.html.erb @@ -0,0 +1,9 @@ +
    +
    +
    +
    +

    © <%= Time.now.year %> Feito com amor pela turma do TreinaDev 12.

    +
    +
    +
    +
    \ No newline at end of file diff --git a/app/views/shared/_navbar.html.erb b/app/views/shared/_navbar.html.erb index 30a0167b..54c40ca8 100644 --- a/app/views/shared/_navbar.html.erb +++ b/app/views/shared/_navbar.html.erb @@ -11,7 +11,7 @@ <% end %> <% end %> -

    <%= current_resident.description %>

    +

    <%= current_resident.description %> - Morador

    <%= button_to destroy_manager_session_path, method: :delete, class: 'btn btn-outline-dark d-inline-flex align-items-center justify-content-center rounded-5' do %> Sair @@ -51,7 +51,7 @@ -
    -
    - <%= f.submit class:"btn btn-dark rounded-pill px-4 mt-3" %> - <%= f.submit 'Não reside neste condomínio', class:'btn btn-dark rounded-pill px-4 mt-3 ms-3' %> +
    + <%= f.submit class:"btn btn-dark rounded-pill px-4 mt-3" %> + <%= f.submit 'Não reside neste condomínio', class:'btn btn-dark rounded-pill px-4 mt-3 ms-3' %> +
    <% end %>
    diff --git a/config/initializers/money.rb b/config/initializers/money.rb new file mode 100644 index 00000000..e088f7d5 --- /dev/null +++ b/config/initializers/money.rb @@ -0,0 +1,116 @@ +# encoding : utf-8 + +MoneyRails.configure do |config| + + # To set the default currency + # + config.default_currency = :brl + Money.locale_backend = :i18n + Money.rounding_mode = BigDecimal::ROUND_HALF_UP + # Set default bank object + # + # Example: + # config.default_bank = EuCentralBank.new + + # Add exchange rates to current money bank object. + # (The conversion rate refers to one direction only) + # + # Example: + # config.add_rate "USD", "CAD", 1.24515 + # config.add_rate "CAD", "USD", 0.803115 + + # To handle the inclusion of validations for monetized fields + # The default value is true + # + # config.include_validations = true + + # Default ActiveRecord migration configuration values for columns: + # + # config.amount_column = { prefix: '', # column name prefix + # postfix: '_cents', # column name postfix + # column_name: nil, # full column name (overrides prefix, postfix and accessor name) + # type: :integer, # column type + # present: true, # column will be created + # null: false, # other options will be treated as column options + # default: 0 + # } + # + # config.currency_column = { prefix: '', + # postfix: '_currency', + # column_name: nil, + # type: :string, + # present: true, + # null: false, + # default: 'USD' + # } + + # Register a custom currency + # + # Example: + # config.register_currency = { + # priority: 1, + # iso_code: "EU4", + # name: "Euro with subunit of 4 digits", + # symbol: "€", + # symbol_first: true, + # subunit: "Subcent", + # subunit_to_unit: 10000, + # thousands_separator: ".", + # decimal_mark: "," + # } + + # Specify a rounding mode + # Any one of: + # + # BigDecimal::ROUND_UP, + # BigDecimal::ROUND_DOWN, + # BigDecimal::ROUND_HALF_UP, + # BigDecimal::ROUND_HALF_DOWN, + # BigDecimal::ROUND_HALF_EVEN, + # BigDecimal::ROUND_CEILING, + # BigDecimal::ROUND_FLOOR + # + # set to BigDecimal::ROUND_HALF_EVEN by default + # + # config.rounding_mode = BigDecimal::ROUND_HALF_UP + + # Set default money format globally. + # Default value is nil meaning "ignore this option". + # Example: + # + # config.default_format = { + # no_cents_if_whole: nil, + # symbol: nil, + # sign_before_symbol: nil + # } + + # If you would like to use I18n localization (formatting depends on the + # locale): + # config.locale_backend = :i18n + # + # Example (using default localization from rails-i18n): + # + # I18n.locale = :en + # Money.new(10_000_00, 'USD').format # => $10,000.00 + # I18n.locale = :es + # Money.new(10_000_00, 'USD').format # => $10.000,00 + # + # For the legacy behaviour of "per currency" localization (formatting depends + # only on currency): + # config.locale_backend = :currency + # + # Example: + # Money.new(10_000_00, 'USD').format # => $10,000.00 + # Money.new(10_000_00, 'EUR').format # => €10.000,00 + # + # In case you don't need localization and would like to use default values + # (can be redefined using config.default_format): + # config.locale_backend = nil + + # Set default raise_error_on_money_parsing option + # It will be raise error if assigned different currency + # The default value is false + # + # Example: + # config.raise_error_on_money_parsing = false +end diff --git a/config/locales/breadcrumb.pt-BR.yml b/config/locales/breadcrumb.pt-BR.yml index b4f55d20..4d64f3db 100644 --- a/config/locales/breadcrumb.pt-BR.yml +++ b/config/locales/breadcrumb.pt-BR.yml @@ -22,6 +22,7 @@ pt-BR: new: 'Cadastrar Morador' edit_photo: 'Editar Foto' show: 'Visualizar Morador' + edit_password: 'Redefinir Senha' owner: new: 'Adicionar Propriedade' tenant: @@ -49,3 +50,5 @@ pt-BR: show: 'Detalhes de fatura' receipt: new: 'Comprovante' + fine: + new: 'Lançar Multa' diff --git a/config/locales/models/resident.pt-BR.yml b/config/locales/models/resident.pt-BR.yml index 9c5f972f..fbcbc3bf 100644 --- a/config/locales/models/resident.pt-BR.yml +++ b/config/locales/models/resident.pt-BR.yml @@ -5,6 +5,10 @@ pt-BR: updated_photo: 'Foto atualizada com sucesso.' created: 'Residente cadastrado com sucesso' not_created: 'Falha ao cadastrar residente' + send_email: 'Convite para cadastro de morador enviado com sucesso!' + alerts: + resident: + invalid_token: 'Token inválido ou já utilizado' owner: 'Proprietário' tenant: 'Inquilino' not_confirmed: 'Não Confirmado' diff --git a/config/locales/models/single_charge.pt-BR.yml b/config/locales/models/single_charge.pt-BR.yml new file mode 100644 index 00000000..f2db9398 --- /dev/null +++ b/config/locales/models/single_charge.pt-BR.yml @@ -0,0 +1,25 @@ +pt-BR: + alerts: + single_charge: + fine_not_created: 'Não foi possível lançar a multa.' + server_error: 'Falha de comunicação com o servidor' + activerecord: + models: + single_charge: + one: 'Cobrança Avulsa' + other: 'Cobranças Avulsa' + attributes: + single_charge: + tower: 'Torre' + tower_id: 'Torre' + floor: 'Andar' + floor_id: 'Andar' + unit: 'Unidade' + unit_id: 'Unidade' + condo: 'Condomínio' + condo_id: 'Condomínio' + description: 'Descrição' + value_cents: 'Valor' + value: 'Valor' + common_area: 'Área Comum' + charge_type: 'Tipo' \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 1d43671e..b738a878 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,9 @@ get '/signup_choice', to: 'home#signup' devise_for :managers - devise_for :residents + devise_for :residents, controllers: { + passwords: 'residents/passwords' + } resources :managers, only: [:new, :create] do get 'edit_photo', on: :member @@ -53,6 +55,7 @@ get 'find', on: :collection get 'all', on: :collection end + resources :fines, only: [:new, :create] resources :towers, only: [:new, :create] do member do diff --git a/db/migrate/20240718203804_create_single_charges.rb b/db/migrate/20240718203804_create_single_charges.rb new file mode 100644 index 00000000..06a2dfc2 --- /dev/null +++ b/db/migrate/20240718203804_create_single_charges.rb @@ -0,0 +1,14 @@ +class CreateSingleCharges < ActiveRecord::Migration[7.1] + def change + create_table :single_charges do |t| + t.text :description + t.integer :value_cents, null: false + t.integer :charge_type, null: false + t.references :condo, null: false, foreign_key: true + t.references :unit, null: false, foreign_key: true + t.references :common_area, null: true, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20240722105115_add_database_datetime_to_visitor_entry.rb b/db/migrate/20240722105115_add_database_datetime_to_visitor_entry.rb new file mode 100644 index 00000000..70d58b98 --- /dev/null +++ b/db/migrate/20240722105115_add_database_datetime_to_visitor_entry.rb @@ -0,0 +1,5 @@ +class AddDatabaseDatetimeToVisitorEntry < ActiveRecord::Migration[7.1] + def change + add_column :visitor_entries, :database_datetime, :datetime, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 6c8b4022..ffc4fa0e 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.1].define(version: 2024_07_22_025316) do +ActiveRecord::Schema[7.1].define(version: 2024_07_22_105115) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false t.text "body" @@ -152,6 +152,20 @@ t.index ["reset_password_token"], name: "index_residents_on_reset_password_token", unique: true end + create_table "single_charges", force: :cascade do |t| + t.text "description" + t.integer "value_cents", null: false + t.integer "charge_type", null: false + t.integer "condo_id", null: false + t.integer "unit_id", null: false + t.integer "common_area_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["common_area_id"], name: "index_single_charges_on_common_area_id" + t.index ["condo_id"], name: "index_single_charges_on_condo_id" + t.index ["unit_id"], name: "index_single_charges_on_unit_id" + end + create_table "superintendents", force: :cascade do |t| t.date "start_date", null: false t.date "end_date", null: false @@ -204,6 +218,7 @@ t.integer "unit_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.datetime "database_datetime", null: false t.index ["condo_id"], name: "index_visitor_entries_on_condo_id" t.index ["unit_id"], name: "index_visitor_entries_on_unit_id" end @@ -234,6 +249,9 @@ add_foreign_key "floors", "towers" add_foreign_key "reservations", "common_areas" add_foreign_key "reservations", "residents" + add_foreign_key "single_charges", "common_areas" + add_foreign_key "single_charges", "condos" + add_foreign_key "single_charges", "units" add_foreign_key "superintendents", "condos" add_foreign_key "superintendents", "residents", column: "tenant_id" add_foreign_key "towers", "condos" diff --git a/db/seeds.rb b/db/seeds.rb index 527e9132..18be09d7 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -16,9 +16,9 @@ ) admin2 = Manager.create!( - full_name: "Adroaldo Silva Santos", - registration_number: '025.727.205-40', - email: "adm2@teste.com", + full_name: "Adroaldo Silva Santos", + registration_number: '025.727.205-40', + email: "adm2@teste.com", password: "teste123", is_super: false, ) @@ -365,6 +365,7 @@ status: :property_registration_pending, full_name: 'Cláudia Rodrigues Gomes', registration_number: '458.456.480-92', + properties: [tower1.floors[0].units[0]], residence: tower1.floors[0].units[0] ) @@ -374,6 +375,7 @@ status: :property_registration_pending, full_name: 'João da Silva', registration_number: '478.040.830-09', + properties: [tower1.floors[1].units[0]], residence: tower1.floors[1].units[0] ) @@ -383,6 +385,7 @@ status: :property_registration_pending, full_name: 'Maria Oliveira', registration_number: '231.887.610-07', + properties: [tower1.floors[2].units[0]], residence: tower1.floors[2].units[0] ) @@ -392,6 +395,7 @@ status: :residence_registration_pending, full_name: 'Pedro Alves', registration_number: '185.894.110-52', + properties: [tower1.floors[3].units[0]], residence: tower1.floors[3].units[0] ) @@ -724,7 +728,7 @@ rules: 'Acompanhamento de adulto obrigatório' ) -visitor_1 = Visitor.create!( +Visitor.create!( condo: resident1.residence.condo, resident: resident1, visit_date: Time.zone.today, @@ -732,7 +736,7 @@ identity_number: '1456987', category: :visitor ) -visitor_2 = Visitor.create!( +Visitor.create!( condo: resident1.residence.condo, resident: resident1, visit_date: Time.zone.today, @@ -741,7 +745,7 @@ category: :employee, recurrence: :working_days ) -visitor_3 = Visitor.create!( +Visitor.create!( condo: resident2.residence.condo, resident: resident2, visit_date: Time.zone.today, @@ -749,7 +753,7 @@ identity_number: '3214567', category: :visitor ) -visitor_4 = Visitor.create!( +Visitor.create!( condo: resident2.residence.condo, resident: resident2, visit_date: 1.day.from_now.to_date, @@ -758,7 +762,7 @@ category: :employee, recurrence: :monthly ) -visitor_5 = Visitor.create!( +Visitor.create!( condo: resident3.residence.condo, resident: resident3, visit_date: 1.day.from_now.to_date, @@ -767,7 +771,7 @@ category: :employee, recurrence: :biweekly ) -visitor_6 = Visitor.create!( +Visitor.create!( condo: resident3.residence.condo, resident: resident3, visit_date: Time.zone.today, @@ -775,7 +779,7 @@ identity_number: '6901234', category: :visitor ) -visitor_7 = Visitor.create!( +Visitor.create!( condo: resident3.residence.condo, resident: resident3, visit_date: 2.days.from_now.to_date, @@ -783,7 +787,7 @@ identity_number: '7890123', category: :visitor ) -visitor_8 = Visitor.create!( +Visitor.create!( condo: resident4.residence.condo, resident: resident4, visit_date: Time.zone.today, @@ -792,7 +796,7 @@ category: :employee, recurrence: :bimonthly ) -visitor_9 = Visitor.create!( +Visitor.create!( condo: resident4.residence.condo, resident: resident4, visit_date: 1.day.from_now, @@ -800,7 +804,7 @@ identity_number: '9654321', category: :visitor ) -visitor_10 = Visitor.create!( +Visitor.create!( condo: resident5.residence.condo, resident: resident5, visit_date: Time.zone.today, @@ -810,62 +814,73 @@ recurrence: :semiannual ) -visitor_entry1 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Maria Fernandes', identity_number: '1234567', - unit: tower1.floors[0].units[0] + unit: tower1.floors[0].units[0], + database_datetime: 1.day.ago ) -visitor_entry2 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'João Pereira', identity_number: '2345678', - unit: tower1.floors[0].units[1] + unit: tower1.floors[0].units[1], + database_datetime: 3.days.ago.to_datetime + ) -visitor_entry3 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Ana Souza', identity_number: '3456789', - unit: tower1.floors[1].units[3] + unit: tower1.floors[1].units[3], + database_datetime: 14.days.ago.to_datetime ) -visitor_entry4 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Carlos Lima', - identity_number: '4567890' + identity_number: '4567890', + database_datetime: 30.days.ago.to_datetime ) -visitor_entry5 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Patricia Mendes', - identity_number: '5678901' + identity_number: '5678901', + database_datetime: 1.day.ago.to_datetime ) -visitor_entry6 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Lucas Alves', identity_number: '6789012', - unit: tower1.floors[2].units[0] + unit: tower1.floors[2].units[0], + database_datetime: 2.days.ago.to_datetime ) -visitor_entry7 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Mariana Costa', identity_number: '7890123', - unit: tower2.floors[2].units[0] + unit: tower2.floors[2].units[0], + database_datetime: 3.days.ago.to_datetime ) -visitor_entry8 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo1, full_name: 'Fernando Gomes', identity_number: '8901234', - unit: tower2.floors[0].units[0] + unit: tower2.floors[0].units[0], + database_datetime: 4.days.ago.to_datetime ) -visitor_entry9 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo2, full_name: 'Juliana Oliveira', identity_number: '9012345', - unit: tower3.floors[0].units[0] + unit: tower3.floors[0].units[0], + database_datetime: 1.days.ago.to_datetime ) -visitor_entry10 = VisitorEntry.create!( +VisitorEntry.create!( condo: condo2, full_name: 'Gustavo Ferreira', - identity_number: '0123456' + identity_number: '0123456', + database_datetime: 1.days.ago.to_datetime ) Announcement.create!( title: 'Reunião de condomínio', @@ -894,3 +909,5 @@ manager: admin2, condo: condo1 ) + +puts 'Seed data created successfully!' diff --git a/spec/factories/managers.rb b/spec/factories/managers.rb index 50096bf6..3d75801e 100644 --- a/spec/factories/managers.rb +++ b/spec/factories/managers.rb @@ -2,7 +2,7 @@ factory :manager do full_name { 'João Almeida' } registration_number { CPF.generate format: true } - email { 'joao@email.com' } + sequence(:email) { |n| "João#{n}@example.com" } password { 'password' } is_super { true } end diff --git a/spec/factories/single_charges.rb b/spec/factories/single_charges.rb new file mode 100644 index 00000000..e6ee5bf7 --- /dev/null +++ b/spec/factories/single_charges.rb @@ -0,0 +1,10 @@ +FactoryBot.define do + factory :single_charge do + description { 'MyText' } + value_cents { 1 } + charge_type { 1 } + condo { nil } + unit { nil } + common_area { nil } + end +end diff --git a/spec/models/condo_spec.rb b/spec/models/condo_spec.rb index 3f41e3dd..4155d8ab 100644 --- a/spec/models/condo_spec.rb +++ b/spec/models/condo_spec.rb @@ -96,14 +96,12 @@ describe '#residents' do it 'show list of residents' do - condo = create :condo, name: 'Condominio Certo' + condo = create :condo, name: 'Condomínio Certo' tower = create :tower, 'condo' => condo, name: 'Torre correta', floor_quantity: 2, units_per_floor: 2 unit11 = tower.floors[0].units[0] - first_resident = create :resident, :mail_confirmed, full_name: 'Adroaldo Silva', - properties: [unit11], email: 'Adroaldo@email.com' - second_resident = create :resident, :property_registration_pending, full_name: 'Sandra Soares', - residence: unit11, email: 'sandra@email' - not_resident = create :resident, :property_registration_pending, full_name: 'João Soares', email: 'joao@email' + first_resident = create :resident, :mail_confirmed, properties: [unit11] + second_resident = create :resident, :property_registration_pending, residence: unit11 + not_resident = create :resident, :property_registration_pending expect(condo.residents).to include first_resident expect(condo.residents).to include second_resident diff --git a/spec/models/reservation_spec.rb b/spec/models/reservation_spec.rb index 8ca43b29..d0d01135 100644 --- a/spec/models/reservation_spec.rb +++ b/spec/models/reservation_spec.rb @@ -34,7 +34,7 @@ it 'date cannot have multiple reservations' do common_area = create :common_area, rules: 'Não pode subir no escorregador.' first_resident = build :resident - second_resident = build :resident, email: 'morador@mail.com' + second_resident = build :resident first_reservation = build :reservation, common_area:, date: Date.current + 1.week, resident: first_resident common_area.reservations << first_reservation diff --git a/spec/models/single_charge_spec.rb b/spec/models/single_charge_spec.rb new file mode 100644 index 00000000..bcf349f6 --- /dev/null +++ b/spec/models/single_charge_spec.rb @@ -0,0 +1,32 @@ +require 'rails_helper' + +RSpec.describe SingleCharge, type: :model do + describe '#valid' do + it 'missing params' do + single_charge = SingleCharge.new charge_type: nil, condo: nil, + unit: nil, description: nil, value_cents: nil + + expect(single_charge).not_to be_valid + expect(single_charge.errors).to include :charge_type + expect(single_charge.errors).to include :condo + expect(single_charge.errors).to include :unit + expect(single_charge.errors).not_to include :description + expect(single_charge.errors).to include :value_cents + end + + it 'description required, case charge_type is fine' do + single_charge = SingleCharge.new charge_type: :fine, description: nil + + expect(single_charge).not_to be_valid + expect(single_charge.errors).to include :description + end + + it 'unit needs an owner' do + unit = create :unit + single_charge = SingleCharge.new(unit:) + + expect(single_charge).not_to be_valid + expect(single_charge.errors.full_messages).to include 'Unidade não possui um proprietário.' + end + end +end diff --git a/spec/models/tower_spec.rb b/spec/models/tower_spec.rb index 88614a7f..c3c9e2c0 100644 --- a/spec/models/tower_spec.rb +++ b/spec/models/tower_spec.rb @@ -35,6 +35,22 @@ .to include 'Apartamentos por Andar não é um número' end + it 'Floor Quantity and Units per Floor must be lesser than 200' do + over_floor_tower = build :tower, floor_quantity: 200, units_per_floor: 199 + over_unit_tower = build :tower, floor_quantity: 199, units_per_floor: 200 + valid_tower = build :tower, floor_quantity: 199, units_per_floor: 199 + + expect(over_floor_tower).not_to be_valid + expect(over_unit_tower).not_to be_valid + expect(valid_tower).to be_valid + + expect(over_floor_tower.errors.include?(:floor_quantity)).to be true + expect(over_unit_tower.errors.include?(:units_per_floor)).to be true + + expect(over_floor_tower.errors.full_messages).to include 'Quantidade de Andares deve ser menor que 200' + expect(over_unit_tower.errors.full_messages).to include 'Apartamentos por Andar deve ser menor que 200' + end + it 'Floor quantity must be greater than 0' do no_floor_tower = build :tower, floor_quantity: 0, units_per_floor: 0 one_floor_tower = build :tower, floor_quantity: 1, units_per_floor: 1 diff --git a/spec/requests/announcement_spec.rb b/spec/requests/announcement_spec.rb index 03cf863e..e1541ac4 100644 --- a/spec/requests/announcement_spec.rb +++ b/spec/requests/announcement_spec.rb @@ -13,10 +13,10 @@ end it 'must be authenticated as Super Manager or Condo Manager to create an announcement' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo - login_as condo_manager, scope: :manager + login_as manager, scope: :manager post condo_announcements_path condo, params: { announcement: { title: 'Novo Aviso' } } expect(response).to redirect_to root_path @@ -51,7 +51,7 @@ end it 'must be authenticated as Super Manager or Condo Manager to edit and announcement' do - manager = create :manager, email: 'joaquina@email.com', is_super: false + manager = create :manager, is_super: false condo = create :condo announcement = create(:announcement, condo:) @@ -82,7 +82,7 @@ context 'GET /announcements' do context 'Manager' do it 'must be authenticated as Super Manager or Condo Manager to see announcements list' do - condo_manager = create :manager, email: 'joaquina@email.com', is_super: false + condo_manager = create :manager, is_super: false condo = create :condo create(:announcement, condo:) @@ -94,7 +94,7 @@ end it 'must be authenticated as Super Manager or Condo Manager to see announcement details' do - manager = create :manager, email: 'joaquina@email.com', is_super: false + manager = create :manager, is_super: false condo = create :condo announcement = create :announcement, condo:, title: 'Reunião de condomínio' @@ -135,7 +135,7 @@ context 'DESTROY /announcements' do it 'must be authenticated as Super Manager or Condo Manager to destroy an announcement' do - condo_manager = create :manager, email: 'joaquina@email.com', is_super: false + condo_manager = create :manager, is_super: false condo = create :condo announcement = create :announcement, condo:, title: 'Reunião de condomínio' diff --git a/spec/requests/apis/resident_spec.rb b/spec/requests/apis/resident_spec.rb index e9634f9a..0bb475d3 100644 --- a/spec/requests/apis/resident_spec.rb +++ b/spec/requests/apis/resident_spec.rb @@ -43,10 +43,8 @@ registration_number: '076.550.640-83', full_name: 'Roberto dos Santos', residence: unit11 - owner = create :resident, - registration_number: '734.706.130-01', - email: 'owner@email.com', - properties: [unit11] + + owner = create :resident, properties: [unit11] get '/api/v1/get_tenant_residence?registration_number=076.550.640-83' @@ -108,8 +106,8 @@ owner = create :resident, registration_number: '734.706.130-01', full_name: 'Roberto dos Santos', - email: 'owner@email.com', properties: [unit11, unit12] + resident = create :resident, registration_number: '076.550.640-83', full_name: 'Ednaldo Pereira', diff --git a/spec/requests/apis/units_spec.rb b/spec/requests/apis/units_spec.rb index a6109837..b009053c 100644 --- a/spec/requests/apis/units_spec.rb +++ b/spec/requests/apis/units_spec.rb @@ -14,7 +14,6 @@ residence: unit11 owner = create :resident, registration_number: '734.706.130-01', - email: 'owner@email.com', properties: [unit11] get '/api/v1/units/1' @@ -37,10 +36,7 @@ unit_type = create :unit_type, description: 'Duplex com varanda', metreage: '145.54' unit11 = tower.floors[0].units[0] unit11.update(unit_type:) - owner = create :resident, - registration_number: '734.706.130-01', - email: 'owner@email.com', - properties: [unit11] + owner = create :resident, properties: [unit11] get '/api/v1/units/1' diff --git a/spec/requests/common_area_spec.rb b/spec/requests/common_area_spec.rb index c136aa65..c2d3d01e 100644 --- a/spec/requests/common_area_spec.rb +++ b/spec/requests/common_area_spec.rb @@ -3,11 +3,11 @@ describe 'Common Areas' do context 'GET /common_areas' do it 'must be authenticated as Super Manager or condo associated' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo common_area = create(:common_area, condo:) - login_as condo_manager, scope: :manager + login_as manager, scope: :manager get common_area_path common_area expect(response).to redirect_to root_path @@ -27,10 +27,10 @@ end it 'and he´s not associated or is not a super' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo - login_as condo_manager, scope: :manager + login_as manager, scope: :manager post condo_common_areas_path condo, params: { common_area: { name: 'Salão de Festas', max_occupancy: 100, description: 'Realize sua festa em nosso salão', rules: 'Não pode ser utilizado após as 22 horas' } } @@ -53,11 +53,11 @@ end it 'and he´s not associated or is not a super' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo common_area = create(:common_area, condo:) - login_as condo_manager, scope: :manager + login_as manager, scope: :manager patch common_area_path common_area, params: { common_area: { name: 'Área Comum Editada' } } common_area.reload diff --git a/spec/requests/condo_management_spec.rb b/spec/requests/condo_spec.rb similarity index 55% rename from spec/requests/condo_management_spec.rb rename to spec/requests/condo_spec.rb index 3a8af612..083f1cd5 100644 --- a/spec/requests/condo_management_spec.rb +++ b/spec/requests/condo_spec.rb @@ -3,10 +3,10 @@ describe 'Manager' do context 'sees condo' do it 'and cannot see details from a condo that he`s not associated' do - condo_manager = create :manager, is_super: false - condo = create :condo, name: 'Condominio Criado' + manager = create :manager, is_super: false + condo = create :condo - login_as condo_manager, scope: :manager + login_as manager, scope: :manager get condo_path condo expect(response).to redirect_to root_path @@ -15,18 +15,17 @@ context 'register condo' do it 'and is not authenticated' do - post(condos_path, params: { condo: { name: 'Condominio Residencial Paineiras', - registration_number: '38.352.640/0001-33' } }) - expect(response).to redirect_to(new_manager_session_path) + post condos_path + + expect(response).to redirect_to new_manager_session_path expect(Condo.all).to eq [] end it 'and must be authenticated as Super Manager' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false - login_as condo_manager, scope: :manager - post(condos_path, params: { condo: { name: 'Condominio Residencial Paineiras', - registration_number: '38.352.640/0001-33' } }) + login_as manager, scope: :manager + post condos_path expect(response).to redirect_to root_path expect(Condo.all).to eq [] @@ -35,27 +34,27 @@ context 'edit condo' do it 'and is not authenticated' do - condo = create(:condo, name: 'Condominio Criado') + condo = create :condo, name: 'Condomínio Criado' - patch(condo_path(condo), params: { condo: { name: 'Condominio Editado' } }) + patch(condo_path(condo), params: { condo: { name: 'Condomínio Editado' } }) expect(response).to redirect_to(new_manager_session_path) - expect(condo.name).to eq 'Condominio Criado' + expect(condo.name).to eq 'Condomínio Criado' end it 'and must be associated to the condo' do condo_manager = create :manager, is_super: false - other_manager = create :manager, email: 'naoaut@email.com', is_super: false - condo = create :condo, name: 'Condominio Criado' + other_manager = create :manager, is_super: false + condo = create :condo, name: 'Condomínio Criado' condo.managers << condo_manager login_as other_manager, scope: :manager - patch(condo_path(condo), params: { condo: { name: 'Condominio Editado' } }) + patch(condo_path(condo), params: { condo: { name: 'Condomínio Editado' } }) condo.reload expect(response).to redirect_to root_path - expect(condo.name).not_to eq 'Condominio Editado' + expect(condo.name).not_to eq 'Condomínio Editado' end end @@ -72,11 +71,11 @@ end it 'and must be authenticated as a Super Manager to delegate a manager to condo' do - condo_manager = create :manager, is_super: false - other_manager = create :manager, email: 'naoaut@email.com', is_super: false - condo = create :condo, name: 'Condominio Criado' + manager = create :manager, is_super: false + other_manager = create :manager, is_super: false + condo = create :condo, name: 'Condomínio Criado' - login_as condo_manager, scope: :manager + login_as manager, scope: :manager post associate_manager_condo_path condo, params: { manager_id: other_manager.id } condo.reload diff --git a/spec/requests/form_request_towers_spec.rb b/spec/requests/form_request_towers_spec.rb index cc7e5819..98bcb0a1 100644 --- a/spec/requests/form_request_towers_spec.rb +++ b/spec/requests/form_request_towers_spec.rb @@ -26,7 +26,7 @@ get find_towers_residents_path 'condo' => condo - expect(response).to redirect_to new_manager_session_path + expect(response).to redirect_to root_path end it 'must be authenticated as manager' do diff --git a/spec/requests/manager_edit_superintendent_spec.rb b/spec/requests/manager_edit_superintendent_spec.rb index bc0425d6..6763b4c9 100644 --- a/spec/requests/manager_edit_superintendent_spec.rb +++ b/spec/requests/manager_edit_superintendent_spec.rb @@ -14,13 +14,13 @@ end it 'must be authenticated as condo manager to edit a superintendent' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo, name: 'Condomínio X' resident = create(:resident, :with_residence, condo:) superintendent = create(:superintendent, condo:, tenant: resident, start_date: Date.current, end_date: Date.current >> 2) - login_as condo_manager, scope: :manager + login_as manager, scope: :manager get edit_condo_superintendent_path(condo, superintendent) @@ -41,11 +41,11 @@ end end - context 'patch /condos/:condo_id/superintendents' do + context 'PATCH /condos/:condo_id/superintendents' do it 'must be authenticated to edit an superintendent' do condo = create :condo, name: 'Condomínio X' resident = create(:resident, :with_residence, condo:) - resident2 = create(:resident, :with_residence, email: 'Adrolado@email.com', condo:) + resident2 = create(:resident, :with_residence, condo:) superintendent = create(:superintendent, condo:, tenant: resident, start_date: Date.current, end_date: Date.current >> 2) @@ -60,12 +60,12 @@ it 'must be authenticated as condo manager to edit a superintendent' do condo = create :condo, name: 'Condomínio X' resident = create(:resident, :with_residence, condo:) - resident2 = create(:resident, :with_residence, email: 'Adrolado@email.com', condo:) + resident2 = create(:resident, :with_residence, condo:) superintendent = create(:superintendent, condo:, tenant: resident, start_date: Date.current, end_date: Date.current >> 2) - condo_manager = create :manager, is_super: false - login_as condo_manager, scope: :manager + manager = create :manager, is_super: false + login_as manager, scope: :manager params = { superintendent: { tenant_id: resident2.id }, condo_id: condo.id } @@ -78,7 +78,7 @@ it 'must be authenticated as manager' do condo = create :condo, name: 'Condomínio X' resident = create(:resident, :with_residence, condo:) - resident2 = create(:resident, :with_residence, email: 'Adrolado@email.com', condo:) + resident2 = create(:resident, :with_residence, condo:) superintendent = create(:superintendent, condo:, tenant: resident, start_date: Date.current, end_date: Date.current >> 2) diff --git a/spec/requests/manager_registers_superintendent_spec.rb b/spec/requests/manager_registers_superintendent_spec.rb index e984e5f6..b5c4029a 100644 --- a/spec/requests/manager_registers_superintendent_spec.rb +++ b/spec/requests/manager_registers_superintendent_spec.rb @@ -11,10 +11,10 @@ end it 'must be authenticated as condo manager to register a superintendent' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo - login_as condo_manager, scope: :manager + login_as manager, scope: :manager get new_condo_superintendent_path(condo) @@ -50,9 +50,9 @@ it 'must be authenticated as condo manager to register a superintendent' do condo = create :condo resident = create(:resident, :with_residence, condo:) - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false - login_as condo_manager, scope: :manager + login_as manager, scope: :manager params = { superintendent: { start_date: Date.current, end_date: Date.current >> 2, tenant_id: resident.id }, condo_id: condo.id } diff --git a/spec/requests/manager_registers_users_spec.rb b/spec/requests/manager_registers_users_spec.rb index 863ddf17..7d28d1b3 100644 --- a/spec/requests/manager_registers_users_spec.rb +++ b/spec/requests/manager_registers_users_spec.rb @@ -3,19 +3,17 @@ describe 'Manager registers users' do context 'POST /managers' do it 'must be authenticated to register an administrator' do - post managers_path, params: { manager: { full_name: 'João Carvalho', registration_number: '642.028.670-09', - email: 'joao@email.com', password: 'password' } } + post managers_path expect(response).to redirect_to new_manager_session_path expect(flash[:alert]).to eq 'Para continuar, faça login ou registre-se.' end it 'must be authenticated as Super Manager to register a manager' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false - login_as condo_manager, scope: :manager - post managers_path, params: { manager: { full_name: 'Julia Silva', registration_number: '642.028.670-09', - email: 'julia@email.com', password: 'password' } } + login_as manager, scope: :manager + post managers_path, params: { manager: { full_name: 'Julia Silva' } } expect(response).to redirect_to root_path expect(flash[:alert]).to eq 'Você não tem permissão para fazer isso' @@ -25,7 +23,7 @@ context 'POST /residents' do it 'must be authenticated to register a resident' do - post residents_path, params: { resident: { full_name: 'Julia Silva' } } + post residents_path expect(response).to redirect_to new_manager_session_path expect(flash[:alert]).to eq 'Para continuar, faça login ou registre-se.' diff --git a/spec/requests/reservation_spec.rb b/spec/requests/reservation_spec.rb index db3c5501..301d9983 100644 --- a/spec/requests/reservation_spec.rb +++ b/spec/requests/reservation_spec.rb @@ -54,7 +54,7 @@ it 'and residents can only cancel their own reservations' do common_area = create :common_area first_resident = create :resident - second_resident = create :resident, email: 'second@email.com' + second_resident = create :resident reservation = create :reservation, common_area:, resident: first_resident login_as second_resident, scope: :resident diff --git a/spec/requests/resident_confirms_data_spec.rb b/spec/requests/resident_confirms_data_spec.rb index d1dccd02..f7f2baad 100644 --- a/spec/requests/resident_confirms_data_spec.rb +++ b/spec/requests/resident_confirms_data_spec.rb @@ -15,7 +15,7 @@ it 'and cannot confirm another resident data' do first_resident = create :resident, status: :mail_not_confirmed - second_resident = create :resident, email: 'pedro@email.com', status: :mail_not_confirmed + second_resident = create :resident, status: :mail_not_confirmed login_as second_resident, scope: :resident patch resident_path(first_resident), params: { resident: { password: '123456' } } diff --git a/spec/requests/resident_edits_photo_spec.rb b/spec/requests/resident_edits_photo_spec.rb index 96e04472..6fbfcfe2 100644 --- a/spec/requests/resident_edits_photo_spec.rb +++ b/spec/requests/resident_edits_photo_spec.rb @@ -22,7 +22,7 @@ it 'and cannot edit another resident photo' do resident = create :resident - other_resident = create :resident, email: 'a@email.com' + other_resident = create :resident login_as other_resident, scope: :resident get edit_photo_resident_path resident @@ -45,18 +45,18 @@ resident = create :resident login_as manager, scope: :manager - patch update_photo_resident_path resident + expect(response).to redirect_to root_path end it 'and cannot edit another resident photo' do resident = create :resident - other_resident = create :resident, email: 'a@email.com' + other_resident = create :resident login_as other_resident, scope: :resident - patch update_photo_resident_path resident + expect(response).to redirect_to root_path end end diff --git a/spec/requests/resident_registers_visitor_request_spec.rb b/spec/requests/resident_registers_visitor_spec.rb similarity index 92% rename from spec/requests/resident_registers_visitor_request_spec.rb rename to spec/requests/resident_registers_visitor_spec.rb index 6dad7758..626c07eb 100644 --- a/spec/requests/resident_registers_visitor_request_spec.rb +++ b/spec/requests/resident_registers_visitor_spec.rb @@ -27,8 +27,8 @@ it 'and cannot register a visitor to another resident' do tower = create :tower, floor_quantity: 1, units_per_floor: 2 - first_resident = create :resident, email: 'joao@email.com', residence: tower.floors[0].units[0] - second_resident = create :resident, email: 'maria@email.com', residence: tower.floors[0].units[1] + first_resident = create :resident, residence: tower.floors[0].units[0] + second_resident = create :resident, residence: tower.floors[0].units[1] login_as first_resident, scope: :resident post resident_visitors_path(second_resident), params: { visitor: { full_name: 'João Almeida', diff --git a/spec/requests/superintendent_register_fine_spec.rb b/spec/requests/superintendent_register_fine_spec.rb new file mode 100644 index 00000000..c45fb0d1 --- /dev/null +++ b/spec/requests/superintendent_register_fine_spec.rb @@ -0,0 +1,135 @@ +require 'rails_helper' + +describe 'Superintendent register fine' do + context 'GET /condos/:condo_id/fines/new' do + it 'and must be authenticated' do + condo = create :condo, name: 'Condomínio X' + + get new_condo_fine_path(condo) + + expect(response).to redirect_to root_path + end + + it 'and must be authenticated as a superintendent to access' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, condo:) + unit11 = tower.floors.first.units.first + resident = create :resident, full_name: 'Dona Alvara', residence: unit11, email: 'alvara@email.com' + + login_as resident, scope: :resident + + get new_condo_fine_path(condo) + + expect(response).to redirect_to root_path + end + + it 'and is authenticated as a manager' do + condo = create :condo, name: 'Condomínio X' + manager = create :manager + + login_as manager, scope: :manager + + get new_condo_fine_path(condo) + + expect(response).to redirect_to root_path + end + end + + context 'POST /condos/:condo_id/fines' do + it 'and must be authenticated' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, condo:) + unit11 = tower.floors.first.units.first + create :resident, properties: [unit11] + + params = { single_charge: { tower_id: '1', floor: '1', unit: '1', + description: 'Barulho dms', value_cents: '5000' }, condo_id: '1' } + + post(condo_fines_path(condo), params:) + + expect(response).to redirect_to root_path + expect(SingleCharge.last).to eq nil + end + + it 'and must be authenticated as a superintendent to access' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, condo:) + unit11 = tower.floors.first.units.first + resident = create :resident, properties: [unit11] + + login_as resident, scope: :resident + + params = { single_charge: { tower_id: '1', floor: '1', unit: '1', + description: 'Barulho dms', value_cents: '5000' }, condo_id: '1' } + + post(condo_fines_path(condo), params:) + + expect(response).to redirect_to root_path + expect(SingleCharge.last).to eq nil + end + + it 'and is authenticated as a manager' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, condo:) + unit11 = tower.floors.first.units.first + create :resident, properties: [unit11] + manager = create :manager + + login_as manager, scope: :manager + + params = { single_charge: { tower_id: '1', floor: '1', unit: '1', + description: 'Barulho dms', value_cents: '5000' }, condo_id: '1' } + + post(condo_fines_path(condo), params:) + + expect(response).to redirect_to root_path + expect(SingleCharge.last).to eq nil + end + + it 'returns failure message if theres an external server error' do + condo = create(:condo, name: 'Condomínio X') + tower = create(:tower, condo:) + unit11 = tower.floors.first.units.first + resident = create(:resident, full_name: 'Dona Alvara', properties: [unit11], email: 'alvara@email.com') + create(:superintendent, condo:, tenant: resident, start_date: Time.zone.today, + end_date: Time.zone.today >> 2) + + login_as resident, scope: :resident + + create_params = { + description: 'Multa por barulho durante a madrugada', + value_cents: 10_000, + charge_type: :fine, + issue_date: Time.zone.today, + tower_id: tower.id, + floor: unit11.floor.identifier, + unit: unit11.identifier + } + + single_charge = + { single_charge: { + description: 'Multa por barulho durante a madrugada', + value_cents: 10_000, + charge_type: :fine, + issue_date: Time.zone.today, + condo_id: condo.id, + common_area_id: nil, + unit_id: unit11.id + } } + + fake_response = instance_double(Faraday::Response, status: 422, success?: false, body: {}) + fake_connection = instance_double(Faraday::Connection) + + allow(Faraday).to receive(:new).and_return(fake_connection) + allow(fake_connection).to receive(:post) + .with('/api/v1/single_charges/', single_charge.to_json, 'Content-Type' => 'application/json') + .and_return(fake_response) + + post condo_fines_path(condo), params: { condo_id: condo.id, single_charge: create_params } + + expect(response).to have_http_status(:unprocessable_entity) + expect(flash.now[:alert]).to eq(I18n.t('alerts.single_charge.fine_not_created')) + expect(SingleCharge.last).to eq nil + end + end +end diff --git a/spec/requests/tower_spec.rb b/spec/requests/tower_spec.rb index f79baad5..c7a40348 100644 --- a/spec/requests/tower_spec.rb +++ b/spec/requests/tower_spec.rb @@ -3,11 +3,11 @@ describe 'Towers' do context 'GET /towers' do it 'must be authenticated as Super Manager or condo associated' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo tower = create(:tower, condo:) - login_as condo_manager, scope: :manager + login_as manager, scope: :manager get tower_path tower expect(response).to redirect_to root_path @@ -42,11 +42,11 @@ expect(Tower.last.name).not_to eq 'Torre do Rubinhos' end - it 'and he´s not associated or is not a super' do - condo_manager = create :manager, is_super: false + it 'and he is not associated or is not a super' do + manager = create :manager, is_super: false condo = create :condo - login_as condo_manager, scope: :manager + login_as manager, scope: :manager post condo_towers_path condo, params: { tower: { name: 'Torre do Rubinhos', floor_quantity: 3, @@ -97,8 +97,8 @@ expect(second_unit_type.reload.fraction).to eq 7.40741 end - it 'and he´s not associated or is not a super' do - condo_manager = create :manager, is_super: false + it 'and he is not associated or is not a super' do + manager = create :manager, is_super: false condo = create :condo first_unit_type = create(:unit_type, condo:, metreage: 50) second_unit_type = create(:unit_type, condo:, metreage: 100) @@ -107,7 +107,7 @@ tower = create(:tower, floor_quantity: 3, units_per_floor: 2, condo:) unit_types = { '0' => first_unit_type.id, '1' => second_unit_type.id } - login_as condo_manager, scope: :manager + login_as manager, scope: :manager patch update_floor_units_condo_tower_path(condo, tower), params: { unit_types: } tower.reload diff --git a/spec/requests/unit_request_spec.rb b/spec/requests/unit_spec.rb similarity index 100% rename from spec/requests/unit_request_spec.rb rename to spec/requests/unit_spec.rb diff --git a/spec/requests/unit_type_management_spec.rb b/spec/requests/unit_type_management_spec.rb index 70bad4c3..5fb7afae 100644 --- a/spec/requests/unit_type_management_spec.rb +++ b/spec/requests/unit_type_management_spec.rb @@ -3,11 +3,11 @@ describe 'Unit Types' do context 'GET /unit_types' do it 'must be authenticated as Super Manager or condo associated' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo unit_type = create(:unit_type, condo:) - login_as condo_manager, scope: :manager + login_as manager, scope: :manager get unit_type_path unit_type expect(response).to redirect_to root_path @@ -25,11 +25,11 @@ expect(UnitType.count).to eq 0 end - it 'and he´s not associated or is not a super' do - condo_manager = create :manager, is_super: false + it 'and he is not associated or is not a super' do + manager = create :manager, is_super: false condo = create :condo - login_as condo_manager, scope: :manager + login_as manager, scope: :manager post condo_unit_types_path condo, params: { unit_type: { description: 'Apartamento Duplex', metreage: 60, fraction: 3 } } @@ -50,11 +50,11 @@ end it 'and he´s not associated or is not a super' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false condo = create :condo unit_type = create :unit_type, condo:, description: 'Apartamento Duplex' - login_as condo_manager, scope: :manager + login_as manager, scope: :manager patch unit_type_path unit_type, params: { unit_type: { description: 'Apartamento Triplex' } } unit_type.reload diff --git a/spec/system/announcements/user_sees_announcements_spec.rb b/spec/system/announcements/user_sees_announcements_spec.rb index 695dd288..ece8d04e 100644 --- a/spec/system/announcements/user_sees_announcements_spec.rb +++ b/spec/system/announcements/user_sees_announcements_spec.rb @@ -3,7 +3,7 @@ describe 'User sees announcements' do it 'with more than 3 announcements' do first_manager = create :manager, full_name: 'Rodrigo Silva', is_super: true - second_manager = create :manager, full_name: 'Joaquina Rodrigues', email: 'joaquina@email.com', is_super: false + second_manager = create :manager, full_name: 'Joaquina Rodrigues', is_super: false condo = create :condo condo.managers << second_manager first_announcement = create :announcement, condo:, manager: first_manager, title: 'Reunião de condomínio' diff --git a/spec/system/common_area/manager_registers_new_common_area_spec.rb b/spec/system/common_area/manager_registers_new_common_area_spec.rb index 4cb493b6..c3d8f2e8 100644 --- a/spec/system/common_area/manager_registers_new_common_area_spec.rb +++ b/spec/system/common_area/manager_registers_new_common_area_spec.rb @@ -18,7 +18,7 @@ expect(current_path).to eq new_condo_common_area_path(condo) end - it 'and only sees associtated condos' do + it 'and only sees associated condos' do condo_manager = create :manager, is_super: false first_condo = create :condo, name: 'Condomínio dos rubinhos' second_condo = create :condo, name: 'Condomínio correto' diff --git a/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb b/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb index d1b639de..50f986bd 100644 --- a/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb +++ b/spec/system/common_area/reservation/resident_cancel_common_area_reservation_spec.rb @@ -67,6 +67,9 @@ login_as resident, scope: :resident visit common_area_path common_area + url = "#{Rails.configuration.api['base_url']}/single_charges/#{reservation.id}/cancel" + allow(Faraday).to receive(:patch).with(url).and_raise(Faraday::ConnectionFailed) + within('.table > tbody > tr:nth-child(1) > .wday-5') do accept_confirm { click_on 'Cancelar' } reservation.reload diff --git a/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb b/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb index 66f7fd74..78386939 100644 --- a/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb +++ b/spec/system/common_area/reservation/resident_reserves_common_area_spec.rb @@ -41,8 +41,20 @@ it 'fail if the connection is lost with external application' do common_area = create :common_area resident = create :resident, :with_residence, condo: common_area.condo - allow(Faraday).to receive(:get).and_raise(Faraday::ConnectionFailed) - allow(Faraday).to receive(:post).and_raise(Faraday::ConnectionFailed) + url = "#{Rails.configuration.api['base_url']}/single_charges/" + single_charge_json = { single_charge: { + description: nil, + value_cents: common_area.fee, + charge_type: 'common_area_fee', + issue_date: Date.new(2024, 7, 5), + condo_id: common_area.condo.id, + common_area_id: common_area.id, + unit_id: resident.residence.id + } }.to_json + + allow(Faraday).to receive(:post) + .with(url, single_charge_json, 'Content-Type' => 'application/json') + .and_raise(Faraday::ConnectionFailed) travel_to '01/07/2024' do login_as resident, scope: :resident diff --git a/spec/system/condos/manager_register_condo_spec.rb b/spec/system/condos/manager_register_condo_spec.rb index 3b4ddeb7..a3944431 100644 --- a/spec/system/condos/manager_register_condo_spec.rb +++ b/spec/system/condos/manager_register_condo_spec.rb @@ -22,8 +22,8 @@ end it 'must be authenticated as Super Manager' do - condo_manager = create :manager, is_super: false - login_as condo_manager, scope: :manager + manager = create :manager, is_super: false + login_as manager, scope: :manager visit root_path within 'nav' do diff --git a/spec/system/resident/manager_sets_resident_as_tenant_spec.rb b/spec/system/resident/manager_sets_resident_as_tenant_spec.rb index 20ff0b04..719c9347 100644 --- a/spec/system/resident/manager_sets_resident_as_tenant_spec.rb +++ b/spec/system/resident/manager_sets_resident_as_tenant_spec.rb @@ -39,7 +39,7 @@ expect(page).to have_current_path resident_path(resident), wait: 3 expect(mail).to have_received(:deliver).once - expect(page).to have_content 'Atualizado com sucesso!' + expect(page).to have_content 'Convite para cadastro de morador enviado com sucesso!' resident.reload expect(resident.residence).not_to eq nil expect(resident.mail_not_confirmed?).to eq true @@ -67,7 +67,7 @@ sleep 1 expect(current_path).to eq resident_path resident - expect(page).to have_content 'Atualizado com sucesso!' + expect(page).to have_content 'Convite para cadastro de morador enviado com sucesso!' resident.reload expect(resident.residence).to eq nil end diff --git a/spec/system/superintendent/superintendent_register_fine_spec.rb b/spec/system/superintendent/superintendent_register_fine_spec.rb new file mode 100644 index 00000000..90bf478d --- /dev/null +++ b/spec/system/superintendent/superintendent_register_fine_spec.rb @@ -0,0 +1,173 @@ +require 'rails_helper' + +describe 'Superintendent register fine' do + it 'successful' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, name: 'Torre X', floor_quantity: 3, units_per_floor: 2, condo:) + unit11 = tower.floors[0].units[0] + unit22 = tower.floors[1].units[1] + create :resident, properties: [unit22], residence: unit22, email: 'fernando@email.com' + resident_super = create :resident, residence: unit11, email: 'alvara@email.com' + create(:superintendent, condo:, tenant: resident_super, start_date: Time.zone.today, + end_date: Time.zone.today >> 2) + single_charge = + { single_charge: { + description: 'Som alto', + value_cents: 50_059, + charge_type: :fine, + issue_date: Time.zone.today, + condo_id: condo.id, + common_area_id: nil, + unit_id: unit22.id + } } + + fake_response = instance_double(Faraday::Response, status: 201, success?: true, body: { message: :created }.to_json) + fake_connection = instance_double(Faraday::Connection) + + allow(Faraday).to receive(:new).and_return(fake_connection) + allow(fake_connection).to receive(:post) + .with('/api/v1/single_charges/', single_charge.to_json, 'Content-Type' => 'application/json') + .and_return(fake_response) + + login_as resident_super, scope: :resident + + visit root_path + click_on 'Condomínio X' + click_on 'Lançar Multa' + + within '#form_data' do + select 'Torre X', from: 'Torre' + select '2', from: 'Andar' + select '2', from: 'Unidade' + fill_in 'Valor', with: '500,59' + fill_in 'Descrição', with: 'Som alto' + click_on 'Lançar Multa' + end + + expect(page).to have_current_path condo_path(condo), wait: 2 + expect(page).to have_content 'Multa lançada com sucesso para a Unidade 22' + end + + it 'server error failure in external application' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, name: 'Torre X', floor_quantity: 3, units_per_floor: 2, condo:) + unit11 = tower.floors[0].units[0] + unit22 = tower.floors[1].units[1] + create :resident, properties: [unit22], residence: unit22, email: 'fernando@email.com' + resident_super = create :resident, residence: unit11, email: 'alvara@email.com' + create(:superintendent, condo:, tenant: resident_super, start_date: Time.zone.today, + end_date: Time.zone.today >> 2) + single_charge = + { single_charge: { + description: 'Som alto', + value_cents: 50_059, + charge_type: :fine, + issue_date: Time.zone.today, + condo_id: condo.id, + common_area_id: nil, + unit_id: unit22.id + } } + + fake_connection = instance_double(Faraday::Connection) + + allow(Faraday).to receive(:new).and_return(fake_connection) + allow(fake_connection).to receive(:post) + .with('/api/v1/single_charges/', single_charge.to_json, 'Content-Type' => 'application/json') + .and_raise(Faraday::ConnectionFailed) + + login_as resident_super, scope: :resident + + visit root_path + click_on 'Condomínio X' + click_on 'Lançar Multa' + + within '#form_data' do + select 'Torre X', from: 'Torre' + select '2', from: 'Andar' + select '2', from: 'Unidade' + fill_in 'Valor', with: '500,59' + fill_in 'Descrição', with: 'Som alto' + click_on 'Lançar Multa' + end + + expect(page).to have_content 'Falha de comunicação com o servidor' + end + + it 'with missing params' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, name: 'Torre X', floor_quantity: 3, units_per_floor: 2, condo:) + unit11 = tower.floors[0].units[0] + unit22 = tower.floors[1].units[1] + create :resident, properties: [unit22], residence: unit22, email: 'fernando@email.com' + resident_super = create :resident, residence: unit11, email: 'alvara@email.com' + create(:superintendent, condo:, tenant: resident_super, start_date: Time.zone.today, + end_date: Time.zone.today >> 2) + + login_as resident_super, scope: :resident + + visit root_path + click_on 'Condomínio X' + click_on 'Lançar Multa' + + within '#form_data' do + fill_in 'Valor', with: '' + fill_in 'Descrição', with: '' + click_on 'Lançar Multa' + end + + expect(page).to have_content 'Não foi possível lançar a multa' + expect(page).to have_content 'Valor não é um número' + expect(page).to have_content 'Descrição não pode ficar em branco' + end + + it 'to a unit that has no owner' do + condo = create :condo, name: 'Condomínio X' + tower = create(:tower, name: 'Torre X', floor_quantity: 3, units_per_floor: 2, condo:) + unit11 = tower.floors[0].units[0] + resident_super = create :resident, residence: unit11 + create(:superintendent, condo:, tenant: resident_super, start_date: Time.zone.today, + end_date: Time.zone.today >> 2) + + login_as resident_super, scope: :resident + + visit root_path + click_on 'Condomínio X' + click_on 'Lançar Multa' + + within '#form_data' do + select 'Torre X', from: 'Torre' + select '2', from: 'Andar' + select '2', from: 'Unidade' + fill_in 'Valor', with: 50_000 + fill_in 'Descrição', with: 'Som alto' + click_on 'Lançar Multa' + end + + expect(page).to have_content 'Não foi possível lançar a multa' + expect(page).to have_content 'Unidade não possui um proprietário.' + end + + it 'is not authenticated as a superintendent' do + condo = create :condo, name: 'Condomínio X' + resident = create(:resident, :with_residence, condo:) + + login_as resident, scope: :resident + + visit root_path + click_on 'Condomínio X' + + expect(page).not_to have_link 'Lançar Multa' + end + + it 'is authenticated as a manager' do + create :condo, name: 'Condomínio X' + manager = create :manager + + login_as manager, scope: :manager + + visit root_path + click_on 'Condomínio X' + + expect(page).not_to have_link 'Lançar Multa' + end +end diff --git a/spec/system/towers/administrator_registers_condo_tower_spec.rb b/spec/system/towers/administrator_registers_condo_tower_spec.rb index 8b915b94..7b32eddb 100644 --- a/spec/system/towers/administrator_registers_condo_tower_spec.rb +++ b/spec/system/towers/administrator_registers_condo_tower_spec.rb @@ -45,7 +45,7 @@ expect(Tower.last.floors.last.units.count).to eq 3 end - it 'and only sees associtated condos' do + it 'and only sees associated condos' do condo_manager = create :manager, is_super: false first_condo = create :condo, name: 'Condomínio dos rubinhos' second_condo = create :condo, name: 'Condomínio correto' diff --git a/spec/system/user_sees_homepage_spec.rb b/spec/system/user_sees_homepage_spec.rb index ff7038ef..a44945c9 100644 --- a/spec/system/user_sees_homepage_spec.rb +++ b/spec/system/user_sees_homepage_spec.rb @@ -88,9 +88,9 @@ end it 'and there`s no link on side-bar when there´s no condo associated' do - condo_manager = create :manager, is_super: false + manager = create :manager, is_super: false - login_as condo_manager, scope: :manager + login_as manager, scope: :manager visit root_path within 'nav' do click_on id: 'side-menu' diff --git a/spec/system/visitor/resident_sees_own_visitors_list_spec.rb b/spec/system/visitor/resident_sees_own_visitors_list_spec.rb index 84b798ca..aefcb9c5 100644 --- a/spec/system/visitor/resident_sees_own_visitors_list_spec.rb +++ b/spec/system/visitor/resident_sees_own_visitors_list_spec.rb @@ -157,7 +157,7 @@ end end - context 'and searchs' do + context 'and searches' do it 'with visitor name filter' do resident = create :resident, :with_residence first_visitor = create :visitor, resident:, full_name: 'João Ferreira', identity_number: 145_364 diff --git a/spec/system/visitor_entry/manager_see_visitor_entries_spec.rb b/spec/system/visitor_entry/manager_see_visitor_entries_spec.rb index 3f90900a..ae1a37b1 100644 --- a/spec/system/visitor_entry/manager_see_visitor_entries_spec.rb +++ b/spec/system/visitor_entry/manager_see_visitor_entries_spec.rb @@ -96,15 +96,15 @@ it 'with visit date filter' do manager = create :manager condo = create :condo - travel_to '04/07/2024' do + travel_to Time.zone.local(2024, 7, 4, 22, 0) do create :visitor_entry, condo:, full_name: 'Nome Visitante Ontem' end - travel_to '05/07/2024' do + travel_to Time.zone.local(2024, 7, 5, 22, 1) do create :visitor_entry, condo:, full_name: 'Nome Primeiro Visitante' end - travel_to '05/07/2024 00:30' do + travel_to Time.zone.local(2024, 7, 5, 22, 2) do create :visitor_entry, condo:, full_name: 'Nome Último Visitante' login_as manager, scope: :manager @@ -136,7 +136,7 @@ end it 'with all filters' do - travel_to '05/07/2024' do + travel_to Time.zone.local(2024, 7, 5, 22, 1) do manager = create :manager condo = create :condo create :visitor_entry, condo:, full_name: 'Nome Primeiro Visitante', identity_number: '145697'