Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6-shift management api #7

Merged
merged 33 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c851e4a
feat: #6 define company service endpoint
adrianrbp Aug 8, 2024
e52ff35
config: #6 define endpoints needed by the frontend
adrianrbp Aug 8, 2024
d36919e
feat: #6 enforce json request and responses
adrianrbp Aug 8, 2024
5f7ec92
feat: #6 handle errors when request unknown paths
adrianrbp Aug 8, 2024
381f54f
feat: #6 define weeks route
adrianrbp Aug 8, 2024
f0f4b78
refactor: #6 move Json response related logic from application contro…
adrianrbp Aug 8, 2024
560263b
feat: #6 define weeks basic structure
adrianrbp Aug 8, 2024
5a652c6
feat: #6 endpoint has correct weeks data
adrianrbp Aug 8, 2024
001406a
feat: #6 show past and future weeks based on company service id
adrianrbp Aug 8, 2024
c52a6eb
config: #6 update github test workflow
adrianrbp Aug 8, 2024
7b54b7b
feat: #6 add missing files
adrianrbp Aug 8, 2024
d8bc363
feat: #6 update frontend api requests to ensure json format
adrianrbp Aug 9, 2024
d70d5b0
feat: #6 define service engineers route
adrianrbp Aug 9, 2024
d663d23
feat: #6 define engineers controller, model, factories and seeds
adrianrbp Aug 9, 2024
8f926ee
feat: #6 define json response structure
adrianrbp Aug 9, 2024
9f58463
feat: #6 create company_service_engineer model
adrianrbp Aug 9, 2024
cc207d9
feat: #6 validate associations between company service and engineers …
adrianrbp Aug 9, 2024
ecfd344
feat: #6 limit 3 engineers per company service
adrianrbp Aug 9, 2024
0f60203
feat: #6 update seeds to create CompanyServices with Engineers
adrianrbp Aug 9, 2024
bc2c283
feat: #6 fix company services factory
adrianrbp Aug 9, 2024
74a4fc2
feat: #6 defien service shifts route
adrianrbp Aug 9, 2024
acd7af7
feat: #6 add companyServiceEngineers model and shifts endpoint
adrianrbp Aug 10, 2024
d69537b
refactor: #6 weeks service to test only pulic methods
adrianrbp Aug 10, 2024
d2231a5
fix: #6 future weeks far from current day
adrianrbp Aug 10, 2024
078101c
fix: #6 past weeks older than current day
adrianrbp Aug 10, 2024
621cf7e
fix: #6 seed with FactoryBot to create shifts
adrianrbp Aug 10, 2024
a95566f
fix: #6 update shift factory
adrianrbp Aug 10, 2024
732bde1
fix: #6 add spanish weeks and months
adrianrbp Aug 10, 2024
52e9eec
feat: #6 get engineers assigned to a company service
adrianrbp Aug 10, 2024
c58fb22
feat: #6 add contract_weeks to company service model
adrianrbp Aug 11, 2024
bcb5113
feat: #6 list company service shifts
adrianrbp Aug 11, 2024
3fa0395
refactor: #6 expand company services factory start date
adrianrbp Aug 11, 2024
e7a8bee
config: #6 update readme
adrianrbp Aug 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ jobs:
backend:
name: 'Rails API Tests'
runs-on: ubuntu-latest

services:
postgres:
image: postgres:latest
env:
POSTGRES_USER: postgres_user
POSTGRES_PASSWORD: testpassword
POSTGRES_DB: monitoring_sys_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -18,12 +34,26 @@ jobs:
- name: Install dependencies
run: |
cd backend
gem install bundler
bundle install

- name: Run Rails tests
- name: Set up environment variables
run: |
echo "DATABASE_HOST=localhost" >> $GITHUB_ENV
echo "DATABASE_USER=postgres_user" >> $GITHUB_ENV
echo "DATABASE_PASSWORD=testpassword" >> $GITHUB_ENV

- name: Set up database
run: |
cd backend
RAILS_ENV=test rails db:create
RAILS_ENV=test rails db:migrate
RAILS_ENV=test rails db:seed

- name: Run RSpec tests
run: |
cd backend
bin/rails test
RAILS_ENV=test bundle exec rspec

frontend:
name: 'Vue Frontend Tests'
Expand Down
Binary file added 2-availability_management.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 76 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,22 @@
### Componentes
#### Endpoints - Gestion de Turnos (Shifts)
- 1st Dropdown (Services)
- GET /api/company_services
- GET /api/company_services
- [example response](frontend/src/mock/company_services.json)
- 2nd Dropdown (Weeks)
- GET /api/company_services/:id/weeks
- [example response](frontend/src/mock/weeks_service_a.json)
- Engineers Table
- GET /api/company_services/:id/engineers?week=YYYY-WW
- [example response](frontend/src/mock/engineers_a_w1.json)
- Shifts Table
- GET /api/company_services/:id/shifts?week=YYYY-WW
- [example response](frontend/src/mock/shifts_a_w1.json)
#### Endpoints - Gestion de Disponibilidad (Availability)
- Dropdowns anteriores (gestion de turnos) para el filtrado y llenado de semana
- Boton Editar Disponibilidad: Consultar Disponibilidad de ingenieros
- GET /api/company_services/:id/engineers/availability?week=YYYY-WW
- [example response](frontend/src/mock/eng_availability_a_w1.json.json)
- Updates Engineer Availability
- POST /api/company_services/:id/engineers/availability
- week
Expand All @@ -51,12 +56,66 @@

#### Modelos
1. Servicios monitoreados
- Bloques de 1h
- Horario establecido (grupo de bloques)
2. Semana
3. Engineer
4. Turno (bloques de 1 hora)
5. Asignacion (Relacion Ingeniero - Hora)
- Contrato: Fechas Establecidas
2. Engineer
3. CompanyServiceEngineer
- Asignar 3 ingenieros encargados del servicio durante el contrato.
4. Shift (Turno) - bloques de 1 hora
- Contrato: Horas por dia de semana establecidas (grupo de bloques)
5. EngineerShift
- Bloque asignado a ingeniero
6. Availability (Disponibilidad) - Must: engineer

#### Modelos - Instancias Ejemplo
1. CompanyService
id: 1
name: "Service A"
contract_start_date: "2024-08-01"
contract_end_date: "2024-08-31"

2. Engineer
id: 1
name:"Alice Smith"
color:"Bob Johnson"

3. Shift
company_service:1
engineer:(sin asignar)
week:"2024-32"
day:"Monday"
start_time:"2024-08-07 09:00:00"
end_time:"2024-08-07 10:00:00"

4. Availability
engineer:1
week:"2024-32"
day:"Monday"
start_time:"2024-08-07 09:00:00"
end_time:"2024-08-07 10:00:00"
available:true

#### Modelos - Instancias Factory Bot
```ruby
# 1. CompanyService
FactoryBot.attributes_for :company_service
=> {:name=>"Farrell, Mohr and Haley", :contract_start_date=>Thu, 18 Jul 2024, :contract_end_date=>Tue, 20 Aug 2024}

# 2. Engineer
FactoryBot.attributes_for :engineer
=> {:name=>"Russell Hermann", :color=>"#0c0d0d"}

# 3. CompanyServiceEngineer
#FactoryBot.attributes_for :company_service_engineer

# 4. Shift
FactoryBot.attributes_for :shift
=> {:week=>"2024-32", :day=>"Tuesday", :start_time=>"13:00", :end_time=>"18:00"}
# 5. EngineerShift

# 6. Availability
FactoryBot.attributes_for :availability

```

#### Arquitectura Frontend (Grafica Figma)
- View
Expand All @@ -65,6 +124,7 @@
- CompanyServiceApi.ts
#### Arquitectura Backend (Grafica Figma)


### Ejecución
#### Ambiente de desarrollo
- Se ha usado Devcontainer y docker-compose para facilitar el desarrollo usando contenedores y vscode
Expand All @@ -77,12 +137,17 @@
- abrir command palette: ctrl + shift + p
- Seleccionar: Reopen in container
- Seleccionar: "Rails API Container"
- Dentro ejecutar: `rails s`
- Dentro ejecutar:
```bash
rails db:setup
rails s -b 0.0.0.0
```
- Ejecutar el contenedor Vue Container:
- abrir command palette: ctrl + shift + p
- Seleccionar: Reopen in container
- Seleccionar: "Vue Container"
- Dentro ejecutar: `yarn dev`
- Dentro ejecutar mocked: `yarn dev`
- (alternativa) Dentro ejecutar api: `yarn serve:api`
- navegar a 0.0.0.0:8080 para empezar a usar la app
- Ejecutar tests e2e:
```bash
Expand All @@ -106,6 +171,8 @@ docker-compose -f .devcontainer/docker-compose.yml up
### Screenshots
#### Ejecución
![figma-1](./1-shift_management.png)
![figma-2](./2-availability_management.png)


#### Figma
![figma-1](./shift-availability-management-figma.jpg)
Expand Down
1 change: 1 addition & 0 deletions backend/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
class ApplicationController < ActionController::API
include JsonResponse
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module CompanyServices
class EngineersController < ApplicationController
def index
company_service = CompanyService.find(params[:company_service_id])
week = params[:week]
@engineers = company_service.engineers
end
end
end
7 changes: 7 additions & 0 deletions backend/app/controllers/company_services/shifts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module CompanyServices
class ShiftsController < ApplicationController
def index
@shifts = FetchShiftsService.new(params[:company_service_id],params[:week]).call
end
end
end
Empty file.
26 changes: 26 additions & 0 deletions backend/app/controllers/concerns/json_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module JsonResponse
extend ActiveSupport::Concern

included do
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
rescue_from ActionController::RoutingError, with: :render_not_found

before_action :ensure_json_request
before_action :set_default_format

def render_not_found
render json: { error: 'Not Found' }, status: :not_found
end

end

private
def set_default_format
request.format = :json
end

def ensure_json_request
return if request.format.json?
render json: { error: 'Not Acceptable' }, status: :not_acceptable
end
end
5 changes: 5 additions & 0 deletions backend/app/controllers/weeks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class WeeksController < ApplicationController
def index
@weeks = WeekService.new(params[:company_service_id]).call
end
end
3 changes: 3 additions & 0 deletions backend/app/models/company_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@
# updated_at :datetime not null
#
class CompanyService < ApplicationRecord
has_many :company_service_engineers, dependent: :destroy
has_many :engineers, through: :company_service_engineers
has_many :shifts, dependent: :destroy
end
24 changes: 24 additions & 0 deletions backend/app/models/company_service_engineer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# == Schema Information
#
# Table name: company_service_engineers
#
# id :bigint not null, primary key
# company_service_id :bigint not null
# engineer_id :bigint not null
# created_at :datetime not null
# updated_at :datetime not null
#
class CompanyServiceEngineer < ApplicationRecord
belongs_to :company_service
belongs_to :engineer

validate :limited_engineers

private

def limited_engineers
if company_service.present? && company_service.company_service_engineers.count >= 3
errors.add(:base, "Cannot assign more than 3 engineers to a company service")
end
end
end
14 changes: 14 additions & 0 deletions backend/app/models/engineer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# == Schema Information
#
# Table name: engineers
#
# id :bigint not null, primary key
# name :string
# color :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Engineer < ApplicationRecord
has_many :company_service_engineers, dependent: :destroy
has_many :company_services, through: :company_service_engineers
end
16 changes: 16 additions & 0 deletions backend/app/models/shift.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: shifts
#
# id :bigint not null, primary key
# company_service_id :bigint not null
# week :string
# day :string
# start_time :time
# end_time :time
# created_at :datetime not null
# updated_at :datetime not null
#
class Shift < ApplicationRecord
belongs_to :company_service
end
60 changes: 60 additions & 0 deletions backend/app/services/fetch_shifts_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
class FetchShiftsService
def initialize(company_service_id, week)
@company_service = CompanyService.find(company_service_id)
@week = week
end

def call
shifts_by_day.map do |day, shifts|
{
day: day,
dayLabel: formatted_day_label(day),
time_blocks: format_time_blocks(shifts)
}
end
end

private

def shifts_by_day
# "Monday" => [shifts]
@company_service.shifts
.where(week: @company_service.contract_start_week)
.group_by(&:day)
end

def formatted_day_label(day)
current_year = Date.today.year
week_number = @week.split('-').last.to_i
day_index = Date::DAYNAMES.index(day.capitalize)
day_index = day_index == 0 ? 7 : day_index
date = Date.commercial(
current_year,
week_number,
day_index
)
# I18n.l(date, format: "%A %d de %B", locale: I18n.locale)
I18n.l(date, format: :long, locale: :es)
end

def format_time_blocks(shifts)
shifts.map do |shift|
{
start_time: shift.start_time.strftime("%H:%W"),
end_time: shift.end_time.strftime("%H:%W"),
amount_of_hours: ((shift.end_time - shift.start_time) / 1.hour).to_i,
engineer: nil #format_engineer(shift.engineer)
}
end
end

def format_engineer(engineer)
return nil unless engineer.present?

{
id: engineer.id,
name: engineer.name,
color: engineer.color
}
end
end
Loading
Loading