Skip to content

Commit

Permalink
fix: avoid duplicating overlapping item assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
lhguerra committed Dec 12, 2024
1 parent 01e5dda commit 77423a1
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 30 deletions.
48 changes: 27 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,39 @@ Have the ultimate management tools in your hands!
- Install PostgreSQL v. 13.3
- Install ImageMagick `brew install imagemagick` or `apt install imagemagick`
- Configure pgsql
- Start postgresql
- Example on macOS (brew instalation): `pg_ctl -D /usr/local/var/postgres start`
- psql postgres
- run `CREATE USER postgres SUPERUSER;`
- run `CREATE DATABASE postgres WITH OWNER postgres;`
- run `\password postgres` and define _postgres_ as user password;
- Start postgresql
- Example on macOS (brew instalation): `pg_ctl -D /usr/local/var/postgres start`
- psql postgres
- run `CREATE USER postgres SUPERUSER;`
- run `CREATE DATABASE postgres WITH OWNER postgres;`
- run `\password postgres` and define _postgres_ as user password;
- Check `config/database.yml` for further information
- You may need to install the `lipq-dev` on Linux environments
- `sudo apt install postgresql libpq-dev`
- `sudo apt install postgresql libpq-dev`
- Install rvm or rbenv - the main development team is using _rvm_
- If you choose rvm then - Install the correct version (the examples will use the ruby-3.2.2)
- `rvm install ruby-3.2.2`
- Create the gemset to the project under the correct version
- In the project folder run:
- `rvm use 3.2.2@flow_climate --create`
- `gem install bundler`
- `bundle install`
- copy the application.yml.example to application.yml
- `rvm install ruby-3.2.2`
- Create the gemset to the project under the correct version
- In the project folder run:
- `rvm use 3.2.2@flow_climate --create`
- `gem install bundler`
- `bundle install`
- copy the application.yml.example to application.yml
- In the project folder run:

- `rake db:create`
- `rake db:migrate`
- `RAILS_ENV=test rake db:migrate`
- `rake db:create`
- `rake db:migrate`
- `RAILS_ENV=test rake db:migrate`

- CI/CD: Github actions

- Check [Github Actions](https://github.com/TallerWebSolutions/flow_climate/tree/develop/.github/workflows)
- Check [Github Actions](https://github.com/TallerWebSolutions/flow_climate/tree/develop/.github/workflows)

- The build relies on `rspec` and `rubocop` success
- In the project folder you should be able to run and check the output of:

- `rspec`
- `rubocop -A`
- `rspec`
- `rubocop -A`

- Run console: `rails c`
- Run server: `rails s`
Expand All @@ -87,10 +87,16 @@ npm run build

## Troubleshoot

fe_sendauth: no password supplied
### fe_sendauth: no password supplied

When syncing production database this error may occur. Check the following:

- /var/lib/pgsql/data/pg_hba.conf (may be another path in your OS) is set to use md5 in local and 127.0.0.1/32
- You have a postgres user with the same name as your OS user and all privileges.
- You have a password file in your home directory. https://www.postgresql.org/docs/current/libpq-pgpass.html

### NameError: uninitialized constant Jira - in LOCAL environment

Generate a new token at https://id.atlassian.com/manage-profile/security/api-tokens

Update the corresponding Jira::JiraAccount with the new token in the field `api_token`
20 changes: 15 additions & 5 deletions app/adapters/jira/jira_issue_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,20 +232,30 @@ def read_unassigned_responsibles(demand, history_date, from_name)

def read_assigned_responsibles(demand, history_date, responsible_name)
membership = MembershipsRepository.instance.find_or_create_by_name(demand.team, responsible_name, :developer, history_date)
dedup_assignment_id = duplicated_assignment(demand, history_date, membership)

return dedup_assignment_id if dedup_assignment_id.present?

item_assignment = demand.item_assignments.create(membership: membership, start_time: history_date)

Slack::SlackNotificationService.instance.notify_item_assigned(item_assignment, company_demand_url(demand.company, demand))

item_assignment.id
end

def duplicated_assignment(demand, history_date, membership)
already_assigned = demand.item_assignments.where(membership: membership, finish_time: nil)

return already_assigned.first.id if already_assigned.present?

overlapping_assignment = demand.item_assignments.where(membership: membership).where('finish_time <= :history_date', history_date: history_date)
return overlapping_assignment.first.id if overlapping_assignment.present?

item_assignment = demand.item_assignments.where(membership: membership, start_time: history_date).first

return item_assignment.id if item_assignment.present?

item_assignment = demand.item_assignments.create(membership: membership, start_time: history_date)

Slack::SlackNotificationService.instance.notify_item_assigned(item_assignment, company_demand_url(demand.company, demand))

item_assignment.id
nil
end

def read_portfolio_unit(demand, jira_issue)
Expand Down
1 change: 1 addition & 0 deletions app/controllers/demands_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def build_search_for_demands
demandable.demands
end
end

# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/MethodLength
Expand Down
1 change: 1 addition & 0 deletions app/graphql/types/demand_effort_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class DemandEffortType < Types::BaseObject
field :effort_value, Float, null: false
field :finish_time_to_computation, GraphQL::Types::ISO8601DateTime, null: false
field :id, ID, null: false
field :item_assignment, Types::ItemAssignmentType, null: false
field :main_effort_in_transition, Boolean, null: false
field :management_percentage, Float, null: false
field :member_role, String, null: true
Expand Down
19 changes: 19 additions & 0 deletions app/graphql/types/item_assignment_type.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module Types
class ItemAssignmentType < Types::BaseObject
field :assignment_for_role, Boolean
field :assignment_notified, Boolean, null: false
field :created_at, GraphQL::Types::ISO8601DateTime, null: false
field :demand, Types::DemandType, null: false
field :discarded_at, GraphQL::Types::ISO8601DateTime
field :finish_time, GraphQL::Types::ISO8601DateTime
field :id, ID, null: false
field :item_assignment_effort, Float, null: false
field :lock_version, Integer
field :membership, Types::Teams::MembershipType, null: false
field :pull_interval, Float
field :start_time, GraphQL::Types::ISO8601DateTime, null: false
field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
end
end
2 changes: 2 additions & 0 deletions app/services/demand_effort_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def build_efforts_to_demand(demand)

demand.demand_efforts.where.not(id: demand_effort_ids).map(&:destroy)
end

# rubocop:enable Metrics/AbcSize

def update_demand_effort_caches(demand)
Expand Down Expand Up @@ -162,6 +163,7 @@ def effort_by_dates(demand, demand_effort, effort_start_time, end_time)

effort_in_hours
end

# rubocop:enable Metrics/MethodLength

def day_off?(day_to_effort, demand)
Expand Down
2 changes: 1 addition & 1 deletion app/spa/src/components/BasicPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const BasicPage = ({
return (
<>
{loading && (
<Backdrop open>
<Backdrop open sx={{ zIndex: 10 }}>
<CircularProgress color="secondary" />
</Backdrop>
)}
Expand Down
8 changes: 7 additions & 1 deletion app/spa/src/modules/demandEffort/demandEffort.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Team } from "../team/team.types"
import { Membership, Team } from "../team/team.types"

export type DemandEffort = {
id: string
Expand All @@ -21,4 +21,10 @@ export type DemandEffort = {
team?: Team
demandId?: number
demandExternalId?: string
itemAssignment?: ItemAssignment
}

type ItemAssignment = {
id: number
membership?: Membership
}
10 changes: 8 additions & 2 deletions app/spa/src/pages/Demand/DemandEfforts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ const DEMAND_QUERY = gql`
memberRole
automaticUpdate
membershipEffortPercentage
itemAssignment {
id
membership {
id
}
}
}
}
}
Expand Down Expand Up @@ -78,7 +84,7 @@ const DemandEfforts = () => {
const tableRows =
demand?.demandEfforts?.map((effort) => [
effort.id,
effort.who || "",
`${effort.who} \n Membership ID: ${effort.itemAssignment?.membership?.id}`,
effort.memberRole || "",
effort.stage || "",
effort.effortValue ? Number(effort.effortValue).toFixed(2) : 0,
Expand All @@ -97,7 +103,7 @@ const DemandEfforts = () => {
(Number(effort.pairingPercentage || 0) * 100).toFixed(2),
(Number(effort.managementPercentage || 0) * 100).toFixed(2),
Number(effort.membershipEffortPercentage || 0).toFixed(2),
effort.totalBlocked || 0,
effort.totalBlocked?.toFixed(2) || 0,
effort.mainEffortInTransition ? <CheckIcon color="primary" /> : "",
effort.automaticUpdate ? <CheckIcon color="primary" /> : "",
<Link
Expand Down
18 changes: 18 additions & 0 deletions spec/adapters/jira/jira_issue_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@
expect(updated_demand.item_assignments.open_assignments).to eq []
end
end

it 'only adds new assignment if there is not one running already' do
travel_to Time.zone.local(2020, 8, 24, 10) do
demand = Fabricate :demand, company: company, team: team, external_id: 'CRE-726'
other_company_team_member = Fabricate :team_member, jira_account_user_email: 'bar', jira_account_id: 'xpto'

membership = Fabricate :membership, team: demand.team, team_member: team_member, member_role: :developer, start_date: 1.month.ago, end_date: nil
Fabricate :membership, team: team, team_member: other_company_team_member, hours_per_month: 120, start_date: 2.months.ago, end_date: nil

overlapping_assignment = Fabricate :item_assignment, demand: demand, membership: membership, start_time: 2.hours.ago, finish_time: 1.hour.ago

jira_issue_changelog = file_fixture('issue_changelog_paginated_page_one.json').read
described_class.instance.process_jira_issue_changelog(jira_account, JSON.parse(jira_issue_changelog), demand, team_member)

expect(ItemAssignment.count).to eq 2
expect(demand.item_assignments).to include(overlapping_assignment)
end
end
end

context 'when the members do not exist yet' do
Expand Down

0 comments on commit 77423a1

Please sign in to comment.