diff --git a/app/graphql/types/teams/membership_type.rb b/app/graphql/types/teams/membership_type.rb index 1ea64f575..491f2f494 100644 --- a/app/graphql/types/teams/membership_type.rb +++ b/app/graphql/types/teams/membership_type.rb @@ -6,6 +6,7 @@ class MembershipType < Types::BaseObject field :created_at, GraphQL::Types::ISO8601DateTime, null: false field :effort_percentage, Float field :end_date, GraphQL::Types::ISO8601Date + field :expected_hour_value, Float field :hours_per_month, Integer field :id, ID, null: false field :member_role, Integer, null: false diff --git a/app/models/membership.rb b/app/models/membership.rb index 9a2318044..0b76605b8 100644 --- a/app/models/membership.rb +++ b/app/models/membership.rb @@ -98,6 +98,12 @@ def stages_to_work_on stages_to_work_on end + def expected_hour_value + return 0 if hours_per_month.zero? + + monthly_payment / hours_per_month + end + def monthly_payment return 0 if team_member.monthly_payment.blank? diff --git a/app/spa/src/components/ProjectDemandsCharts.tsx b/app/spa/src/components/ProjectDemandsCharts.tsx index 65c76c439..1b32e835b 100644 --- a/app/spa/src/components/ProjectDemandsCharts.tsx +++ b/app/spa/src/components/ProjectDemandsCharts.tsx @@ -164,7 +164,7 @@ const ProjectDemandsCharts = ({ t("charts_tab.project_charts.demands_burn_up_label_ideal"), t("charts_tab.project_charts.demands_burn_up_label_delivered"), project.demandsBurnup - ) + ) const projectHoursBurnupChartData = buildBurnupData( t("charts_tab.project_charts.hours_burn_up_label_scope"), @@ -172,7 +172,7 @@ const ProjectDemandsCharts = ({ t("charts_tab.project_charts.hours_burn_up_label_delivered"), project.hoursBurnup ) - + const leadTimeP80ChartData = [ { id: project.name, diff --git a/app/spa/src/components/TeamMemberDashboardCharts.tsx b/app/spa/src/components/TeamMemberDashboardCharts.tsx index e64e4c93c..7629d7342 100644 --- a/app/spa/src/components/TeamMemberDashboardCharts.tsx +++ b/app/spa/src/components/TeamMemberDashboardCharts.tsx @@ -85,15 +85,16 @@ const TeamMemberDashboardCharts = ({ const lineChartData = [ { id: teamMember.name, - data: teamMember.teamMemberConsolidationList? teamMember.teamMemberConsolidationList.map( - ({ valuePerHourPerformed, consolidationDate }) => { - - return { - x: String(consolidationDate || ''), - y: Number(valuePerHourPerformed || 0), - } - } - ) : [], + data: teamMember.teamMemberConsolidationList + ? teamMember.teamMemberConsolidationList.map( + ({ valuePerHourPerformed, consolidationDate }) => { + return { + x: String(consolidationDate || ""), + y: Number(valuePerHourPerformed || 0), + } + } + ) + : [], }, ] @@ -158,22 +159,20 @@ const TeamMemberDashboardCharts = ({ /> )} - {projectHoursData && ( + {projectHoursData && ( - ( - - ), - }} - /> - + ( + + ), + }} + /> + )} ) diff --git a/app/spa/src/components/TeamMemberDashboardTables.tsx b/app/spa/src/components/TeamMemberDashboardTables.tsx index 0c38f2be5..61b4f7c95 100644 --- a/app/spa/src/components/TeamMemberDashboardTables.tsx +++ b/app/spa/src/components/TeamMemberDashboardTables.tsx @@ -24,13 +24,13 @@ const TeamMemberDashboardTables = ({ const [searchParams, setSearchParams] = useSearchParams() const normalizeQueryStringFilters = (filters: FieldValues) => - Object.keys(filters) - .filter((key) => { - return String(filters[key]).length > 0 && filters[key] !== "null" - }) - .reduce>((acc, el) => { - return { ...acc, [el]: filters[el] } - }, {}) + Object.keys(filters) + .filter((key) => { + return String(filters[key]).length > 0 && filters[key] !== "null" + }) + .reduce>((acc, el) => { + return { ...acc, [el]: filters[el] } + }, {}) const demandShortestLeadTime = teamMember.demandShortestLeadTime?.leadtime || 0 @@ -130,23 +130,25 @@ const TeamMemberDashboardTables = ({ t("dashboard.latestEfforts.effortValue"), ] - const latestEffortsRows = teamMember?.demandEffortsList?.demandEfforts?.map((effort) => [ - - {effort.team?.name} - , - , - , - - {effort.demandExternalId} - , - `${(effort.effortValue || 0).toFixed(2)}`, - ]) + const latestEffortsRows = teamMember?.demandEffortsList?.demandEfforts?.map( + (effort) => [ + + {effort.team?.name} + , + , + , + + {effort.demandExternalId} + , + `${(effort.effortValue || 0).toFixed(2)}`, + ] + ) const latestProjectsRows = teamMember.projectsList?.projects?.map((project) => [ @@ -230,21 +232,23 @@ const TeamMemberDashboardTables = ({ {searchParams && ( - setSearchParams({ - ...normalizeQueryStringFilters(effortsFilters || {}), - pageNumber: String(newPage + 1), - }), - }} - /> + title={t("dashboard.latestEfforts.title")} + subtitle={`${t("dashboard.latestEfforts.effortsValueSum")} ${ + teamMember?.demandEffortsList?.effortsValueSum || 0 + }`} + headerCells={latestEffortsHeader} + rows={latestEffortsRows || []} + pagination={{ + count: teamMember?.demandEffortsList?.demandEffortsCount || 0, + rowsPerPage: 10, + page: effortsFilters.pageNumber - 1, + onPageChange: (_, newPage: number) => + setSearchParams({ + ...normalizeQueryStringFilters(effortsFilters || {}), + pageNumber: String(newPage + 1), + }), + }} + /> )} diff --git a/app/spa/src/components/ui/DateLocale.tsx b/app/spa/src/components/ui/DateLocale.tsx index 26814b9bd..855218e8b 100644 --- a/app/spa/src/components/ui/DateLocale.tsx +++ b/app/spa/src/components/ui/DateLocale.tsx @@ -8,7 +8,7 @@ type DateLocaleProps = { isPtBr?: boolean } -const DateLocale = ({ date, time, isPtBr = true}: DateLocaleProps) => { +const DateLocale = ({ date, time, isPtBr = true }: DateLocaleProps) => { const dateFormat = isPtBr ? "dd/MM/yyyy" : "MM/dd/yyyy" const format = time ? `${dateFormat} HH:mm` : dateFormat diff --git a/app/spa/src/modules/team/team.types.ts b/app/spa/src/modules/team/team.types.ts index b4e872e5a..795bd87cb 100644 --- a/app/spa/src/modules/team/team.types.ts +++ b/app/spa/src/modules/team/team.types.ts @@ -9,7 +9,6 @@ import { Demand } from "../demand/demand.types" import { ProjectConsolidation } from "../project/projectConsolidation.types" import { ReplenishingConsolidation } from "../replenishing/replenishingConsolidation.types" - export type TeamMembersHourlyRate = { periodDate?: string valuePerHourPerformed?: number @@ -66,6 +65,8 @@ export type MembershipEfficiencyData = { realizedMoneyInMonth?: number avgHoursPerDemand?: number cardsCount?: number + expectedHourValue?: number + realizedHourValue?: number } export type Membership = { @@ -75,10 +76,10 @@ export type Membership = { teamMemberName?: string hoursPerMonth?: number effortPercentage?: number + expectedHourValue?: number startDate?: string endDate?: string memberRole?: number memberRoleDescription?: string teamMembersHourlyRateList?: TeamMembersHourlyRate[] - } diff --git a/app/spa/src/modules/teamMember/teamMember.types.ts b/app/spa/src/modules/teamMember/teamMember.types.ts index 00b903a6d..d82c12d72 100644 --- a/app/spa/src/modules/teamMember/teamMember.types.ts +++ b/app/spa/src/modules/teamMember/teamMember.types.ts @@ -47,10 +47,12 @@ export type TeamMember = { yAxisProjectsNames: string[] } demandEfforts?: DemandEffort[] - demandEffortsList?: { - demandEfforts?: DemandEffort[] - demandEffortsCount?: number - effortsValueSum?: number - } + demandEffortsList?: DemandEffortsList teamMemberConsolidationList?: TeamMemberConsolidation[] } + +type DemandEffortsList = { + demandEfforts?: DemandEffort[] + demandEffortsCount?: number + effortsValueSum?: number +} diff --git a/app/spa/src/pages/TeamMembers/TeamMemberDashboard.tsx b/app/spa/src/pages/TeamMembers/TeamMemberDashboard.tsx index 430bfb880..3c9370733 100644 --- a/app/spa/src/pages/TeamMembers/TeamMemberDashboard.tsx +++ b/app/spa/src/pages/TeamMembers/TeamMemberDashboard.tsx @@ -11,7 +11,12 @@ import TeamMemberDashboardCharts from "../../components/TeamMemberDashboardChart import { FieldValues } from "react-hook-form" const TEAM_MEMBER_QUERY = gql` - query TeamMember($id: ID!, $fromDate: ISO8601Date, $untilDate: ISO8601Date, $pageNumber: Int) { + query TeamMember( + $id: ID! + $fromDate: ISO8601Date + $untilDate: ISO8601Date + $pageNumber: Int + ) { teamMember(id: $id) { id name @@ -116,7 +121,11 @@ const TEAM_MEMBER_QUERY = gql` slug } } - demandEfforts(fromDate: $fromDate, untilDate: $untilDate, pageNumber: $pageNumber) { + demandEfforts( + fromDate: $fromDate + untilDate: $untilDate + pageNumber: $pageNumber + ) { id effortValue effortMoney @@ -141,35 +150,39 @@ const TEAM_MEMBER_QUERY = gql` automaticUpdate membershipEffortPercentage } - teamMemberConsolidationList{ + teamMemberConsolidationList { consolidationDate valuePerHourPerformed } - demandEffortsList(fromDate: $fromDate, untilDate: $untilDate, pageNumber: $pageNumber) { - demandEfforts{ - id - effortValue - effortMoney - startTimeToComputation - finishTimeToComputation - stagePercentage - pairingPercentage - managementPercentage - totalBlocked - mainEffortInTransition - stage - who - team { + demandEffortsList( + fromDate: $fromDate + untilDate: $untilDate + pageNumber: $pageNumber + ) { + demandEfforts { id - name - } - createdAt - updatedAt - demandId - demandExternalId - memberRole - automaticUpdate - membershipEffortPercentage + effortValue + effortMoney + startTimeToComputation + finishTimeToComputation + stagePercentage + pairingPercentage + managementPercentage + totalBlocked + mainEffortInTransition + stage + who + team { + id + name + } + createdAt + updatedAt + demandId + demandExternalId + memberRole + automaticUpdate + membershipEffortPercentage } demandEffortsCount effortsValueSum @@ -207,7 +220,7 @@ const TeamMemberDashboard = () => { id: Number(teamMemberId), fromDate: effortsQueryFilters.fromDate, untilDate: effortsQueryFilters.untilDate, - pageNumber: (effortsQueryFilters.pageNumber || 1), + pageNumber: effortsQueryFilters.pageNumber || 1, }, }) const companySlug = me?.currentCompany?.slug diff --git a/app/spa/src/pages/Teams/TeamDashboard.tsx b/app/spa/src/pages/Teams/TeamDashboard.tsx index 249f543da..2499161f5 100644 --- a/app/spa/src/pages/Teams/TeamDashboard.tsx +++ b/app/spa/src/pages/Teams/TeamDashboard.tsx @@ -29,7 +29,6 @@ import TeamBasicPage from "../../modules/team/components/TeamBasicPage" import { Team } from "../../modules/team/team.types" import MemberGeneralInfo from "./MemberGeneralInfo" - const TEAM_DASHBOARD_QUERY = gql` query TeamDashboard($teamId: ID!, $startDate: ISO8601Date, $endDate: ISO8601Date) { team(id: $teamId) { @@ -205,19 +204,24 @@ const TeamDashboard = () => { }, ] -const lineChartMembershipData = team?.memberships? team?.memberships?.map((membership)=> { - const seila = { id: membership?.teamMemberName? membership.teamMemberName : "", - data: membership?.teamMembersHourlyRateList? membership?.teamMembersHourlyRateList?.map( - ( teamMembersHourlyRate ) => { - return { - x: String(teamMembersHourlyRate.periodDate || ''), - y: String(teamMembersHourlyRate.valuePerHourPerformed || 0), + const lineChartMembershipData = team?.memberships + ? team?.memberships?.map((membership) => { + const seila = { + id: membership?.teamMemberName ? membership.teamMemberName : "", + data: membership?.teamMembersHourlyRateList + ? membership?.teamMembersHourlyRateList?.map( + (teamMembersHourlyRate) => { + return { + x: String(teamMembersHourlyRate.periodDate || ""), + y: String(teamMembersHourlyRate.valuePerHourPerformed || 0), + } + } + ) + : [], } - } - - ) : []} - return seila -}):[] + return seila + }) + : [] return ( - ( diff --git a/spec/models/membership_spec.rb b/spec/models/membership_spec.rb index c41f0d263..4c9ed3948 100644 --- a/spec/models/membership_spec.rb +++ b/spec/models/membership_spec.rb @@ -396,4 +396,24 @@ end end end + + describe '#expected_hour_value' do + context 'with hours per month' do + it 'returns the monthly payment divided by the hours per month' do + team_member = Fabricate :team_member, hours_per_month: 160, monthly_payment: 10_000 + membership = Fabricate :membership, team_member: team_member, hours_per_month: 100 + + expect(membership.expected_hour_value).to eq 62.5 + end + end + + context 'without hours per month' do + it 'returns zero' do + team_member = Fabricate :team_member, hours_per_month: 160, monthly_payment: 10_000 + membership = Fabricate :membership, team_member: team_member, hours_per_month: 0 + + expect(membership.expected_hour_value).to eq 0 + end + end + end end