diff --git a/README.md b/README.md index 05543710c..6c6dd3742 100644 --- a/README.md +++ b/README.md @@ -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` @@ -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` diff --git a/app/adapters/jira/jira_issue_adapter.rb b/app/adapters/jira/jira_issue_adapter.rb index e790cf5c5..dbedaca68 100644 --- a/app/adapters/jira/jira_issue_adapter.rb +++ b/app/adapters/jira/jira_issue_adapter.rb @@ -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) diff --git a/app/controllers/demands_controller.rb b/app/controllers/demands_controller.rb index 220855f8d..4b65272d9 100644 --- a/app/controllers/demands_controller.rb +++ b/app/controllers/demands_controller.rb @@ -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 diff --git a/app/graphql/types/demand_effort_type.rb b/app/graphql/types/demand_effort_type.rb index 7e34dd640..3d42cad47 100644 --- a/app/graphql/types/demand_effort_type.rb +++ b/app/graphql/types/demand_effort_type.rb @@ -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 diff --git a/app/graphql/types/item_assignment_type.rb b/app/graphql/types/item_assignment_type.rb new file mode 100644 index 000000000..934d57026 --- /dev/null +++ b/app/graphql/types/item_assignment_type.rb @@ -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 diff --git a/app/services/demand_effort_service.rb b/app/services/demand_effort_service.rb index c9fb25ac9..94005b937 100644 --- a/app/services/demand_effort_service.rb +++ b/app/services/demand_effort_service.rb @@ -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) @@ -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) diff --git a/app/spa/src/components/BasicPage.tsx b/app/spa/src/components/BasicPage.tsx index ec9cf4f25..0e3dfb82b 100644 --- a/app/spa/src/components/BasicPage.tsx +++ b/app/spa/src/components/BasicPage.tsx @@ -32,7 +32,7 @@ const BasicPage = ({ return ( <> {loading && ( - + )} diff --git a/app/spa/src/modules/demandEffort/demandEffort.types.ts b/app/spa/src/modules/demandEffort/demandEffort.types.ts index 5780d52fe..40c1541b0 100644 --- a/app/spa/src/modules/demandEffort/demandEffort.types.ts +++ b/app/spa/src/modules/demandEffort/demandEffort.types.ts @@ -1,4 +1,4 @@ -import { Team } from "../team/team.types" +import { Membership, Team } from "../team/team.types" export type DemandEffort = { id: string @@ -21,4 +21,10 @@ export type DemandEffort = { team?: Team demandId?: number demandExternalId?: string + itemAssignment?: ItemAssignment +} + +type ItemAssignment = { + id: number + membership?: Membership } diff --git a/app/spa/src/pages/Demand/DemandEfforts.tsx b/app/spa/src/pages/Demand/DemandEfforts.tsx index 43650c1c6..7ef30cafc 100644 --- a/app/spa/src/pages/Demand/DemandEfforts.tsx +++ b/app/spa/src/pages/Demand/DemandEfforts.tsx @@ -39,6 +39,12 @@ const DEMAND_QUERY = gql` memberRole automaticUpdate membershipEffortPercentage + itemAssignment { + id + membership { + id + } + } } } } @@ -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, @@ -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 ? : "", effort.automaticUpdate ? : "",