module ProjectorPWS
ProjectorPWS
Module: Root Module for ProjectorPWS
.
ProjectorPWS
Module: Root Module for ProjectorPWS
.
ProjectorPWS
Module
Constants
- BASE_URL
Base URL
- DAYS_PER_WEEK
Days Per Week
- EXTRA_NAMESPACES
- HOURS_PER_DAY
Hours Per Day
- HOURS_PER_DAY_REAL
Real Hours Per Day
- MINUTES_PER_DAY
Minutes Per Day
- MINUTES_PER_HOUR
Minutes Per Hour
- MINUTES_PER_WEEK
Minutes Per Week
- NAMESPACE
Namespaces
- URL_PATH
URL Path
- VERSION
Version
- WEEKEND_START_TIME
Weekend Start Time
- WEEK_END
- WEEK_START
Work Week
- WSDL
Service Definition
Public Class Methods
Authenticate
# File lib/projector_pws.rb, line 68 def self.authenticate username, password, account_code = nil # Prepare URLs next_url = BASE_URL last_url = '' # Prepare Credentials creds = {} creds['req:AccountCode'] = account_code if account_code creds['req:Password'] = password creds['req:UserName'] = username # Loop to obtain Ticket c = nil ticket = nil until ticket # Authenticate begin c = open next_url r = c.call(:pws_authenticate, message: { 'pws:serviceRequest' => creds }).body[:pws_authenticate_response][:pws_authenticate_result] last_url = next_url next_url = r[:redirect_url] rescue Savon::SOAPFault => e raise "Authentication failed - #{e.to_hash[:fault][:detail][:pws_fault][:messages][:pws_message][:error_text]}" end raise 'API Error (redirect loop)' if next_url == last_url ticket = r[:session_ticket] end # Yield if block given if block_given? r = yield c, ticket unauthenticate c, ticket return r end [c, ticket] end
Compute Resource Active Hours
# File lib/projector_pws.rb, line 377 def self.compute_resource_active_hours wsched # Extract Working Minutes work = wsched.inject(0) { |a, e| a + e[:working_minutes].to_i } # Determine Active Hours work.to_f / MINUTES_PER_HOUR.to_f end
Compute Resource Free Hours
# File lib/projector_pws.rb, line 387 def self.compute_resource_free_hours scheduled_hours, wsched # Get active hours active_hours = compute_resource_active_hours wsched # Compute time off and holidays into active hours active_hours = active_hours - scheduled_hours[:toff] active_hours = active_hours - (scheduled_hours[:hday] || 0) # Compute free time (active unscheduled time) active_hours - scheduled_hours[:work] end
Current Week End
# File lib/projector_pws.rb, line 486 def self.current_week_end current_week_start.wnext(WEEK_END) end
Current Week Start
# File lib/projector_pws.rb, line 481 def self.current_week_start is_weekend? ? Date.today.wnext(WEEK_START) : (Date.today.monday? ? Date.today : Date.today.wlast(WEEK_START)) end
# File lib/projector_pws.rb, line 190 def self.get_client c, ticket, client_uid params = {'req:SessionTicket' => ticket } params['req:ClientIdentities'] = { 'com:PwsClientRef' => { 'com:ClientUid' => client_uid }} c.call(:pws_get_client, message: {'pws:serviceRequest' => params}).body[:pws_get_client_response][:pws_get_client_result][:clients][:pws_client_element] end
Get Cost Centers
# File lib/projector_pws.rb, line 302 def self.get_cost_centers c, ticket # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:IncludeEngagementCostCentersFlag'] = true params['tim:IncludeResourceCostCentersFlag'] = true params['tim:IncludeNonResourceNonEngagementCostCentersFlag'] = true # Fetch Resources c.call(:pws_get_cost_center_list, message: { 'pws:serviceRequest' => params }).body[:pws_get_cost_center_list_response][:pws_get_cost_center_list_result][:cost_centers] end
# File lib/projector_pws.rb, line 172 def self.get_engagement c, ticket, engagement_uid raise "Engagement Code Needed" if !engagement_uid # prepare params params = {'req:SessionTicket' => ticket } params['sch:EngagementIdentities'] = {'com:PwsEngagementRef' => {'com:EngagementUid' => engagement_uid}} # Fetch Engagement Details c.call(:pws_get_engagement, message: {'pws:serviceRequest' => params}).body[:pws_get_engagement_response][:pws_get_engagement_result][:engagements][:pws_engagement_element] end
# File lib/projector_pws.rb, line 181 def self.get_engagements c, ticket, include_closed = false, max_rows = nil # Prepare Params params = {'req:SessionTicket' => ticket } params['sch:IncludeClosedFlag'] = include_closed if include_closed && (include_closed.class == TrueClass || include_closed.class == FalseClass) params['sch:MaxRowsToReturn'] = max_rows if max_rows && max_rows.class == Integer # Fetch Engagement List c.call(:pws_get_engagement_list, message: {'pws:serviceRequest' => params}).body[:pws_get_engagement_list_response][:pws_get_engagement_list_result][:engagements][:pws_engagement_summary] end
Get Expense Document
# File lib/projector_pws.rb, line 315 def self.get_expense_document c, ticket, doc_number, include_cost_cards = true, include_receipts = false # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:ExpenseDocumentIdentity'] = { 'com:DocumentNumber' => doc_number } params['tim:RetrieveCostCardsFlag'] = include_cost_cards params['tim:RetrieveReceiptsFlag'] = include_receipts # Fetch Expense Document c.call(:pws_get_expense_document, message: { 'pws:serviceRequest' => params }).body[:pws_get_expense_document_response][:pws_get_expense_document_result][:expense_document] end
Get Expense Documents
# File lib/projector_pws.rb, line 328 def self.get_expense_documents c, ticket, reps = nil # Prepare Params params = { 'req:SessionTicket' => ticket } if reps params['tim:ExpenseDocumentIdentity'] = [] reps.each { |r| params['tim:ExpenseDocumentIdentity'] << { 'com:DocumentNumber' => r } } end # Fetch Expense Documents c.call(:pws_get_expense_document, message: { 'pws:serviceRequest' => params }).body[:pws_get_expense_document_response][:pws_get_expense_document_result] end
Get Free Resources (non-busy) with associated minutes
# File lib/projector_pws.rb, line 364 def self.get_free_resources c, ticket, start_date = current_week_start, end_date = current_week_end # Get all resources res = ProjectorPWS.get_resources c, ticket # Collect free time res.collect { |r| { resource: r, free_hours: get_resource_free_hours(c, ticket, r, start_date, end_date).to_f } }.select { |x| x[:free_hours] > 0 } end
Get Project Details
# File lib/projector_pws.rb, line 139 def self.get_project c, ticket, project_uid # prepare params params = {'req:SessionTicket' => ticket } params['sch:Mode'] = "R" # Had to build the Hash this way to counter 'String not Matched Issue', ruby -v 2.5.1, rails -v 5.1.6 if project_uid params['sch:ProjectIdentities'] = {'com:PwsProjectRef' => { 'com:ProjectUid' => project_uid } } end # Fetch Project Details c.call(:pws_get_project, message: {'pws:serviceRequest' => params}).body[:pws_get_project_response][:pws_get_project_result][:projects][:pws_project_element] end
Get Project Time Baseline
# File lib/projector_pws.rb, line 153 def self.get_project_time_baseline c, ticket, time_baseline_uid # prepare params params = {'req:SessionTicket' => ticket} raise "Time Baseline Uid Missing" if !time_baseline_uid params['sch:ProjectTimeBaselineIdentities'] = {'com:PwsProjectTimeBaselineRef' => {'com:ProjectTimeBaselineUid' => time_baseline_uid}} # Fetch Time Baseline Info c.call(:pws_get_project_time_baseline, message: { 'pws:serviceRequest' => params}).body[:pws_get_project_time_baseline_response][:pws_get_project_time_baseline_result][:project_time_baselines][:pws_project_time_baseline_element] end
Get Project Time Baselines
# File lib/projector_pws.rb, line 163 def self.get_project_time_baselines c, ticket, time_baseline_uids # prepare params params = {'req:SessionTicket' => ticket} raise "Time Baseline Uids Missing" unless time_baseline_uids.is_a?(Array) params['sch:ProjectTimeBaselineIdentities'] = time_baseline_uids.collect { |i| { 'com:PwsProjectTimeBaselineRef' => { 'com:ProjectTimeBaselineUid' => i } } } # Fetch Time Baseline Info c.call(:pws_get_project_time_baseline, message: { 'pws:serviceRequest' => params}).body[:pws_get_project_time_baseline_response][:pws_get_project_time_baseline_result][:project_time_baselines][:pws_project_time_baseline_element] end
Get Project List
# File lib/projector_pws.rb, line 129 def self.get_projects c, ticket, engagement_code = nil # Prepare Params params = {'req:SessionTicket' => ticket } params['sch:QueryString'] = engagement_code.to_s if engagement_code params['sch:IncludeClosedFlag'] = true # Fetch Projects c.call(:pws_get_project_list, message: {'pws:serviceRequest' => params }).body[:pws_get_project_list_response][:pws_get_project_list_result][:projects][:pws_project_summary] end
Get Report Output
# File lib/projector_pws.rb, line 117 def self.get_report c, ticket, report_uid, format = nil # Prepare Params params = { 'req:SessionTicket' => ticket } params['rep:ReportIdentity'] = { 'com:ReportUid' => report_uid } params['rep:Format'] = format if format # Fetch Report c.call(:pws_get_report_output, message: { 'pws:serviceRequest' => params }).body end
Get Resource Active Hours
# File lib/projector_pws.rb, line 411 def self.get_resource_active_hours c, ticket, resource, start_date = current_week_start, end_date = current_week_end, wsched = nil # Acquire working schedule for resource wsched ||= ProjectorPWS.get_resource_working_schedule(c, ticket, resource[:resource_uid], start_date, end_date)[:pws_working_schedule_day] rescue(return(0)) wsched = [wsched] unless wsched.is_a? Array wsched.compact! compute_resource_active_hours wsched end
Get Resource Available Timeoff
# File lib/projector_pws.rb, line 263 def self.get_resource_available_timeoff c, ticket, resource_uid = nil, start_date = current_week_start, end_date = current_week_end # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz' params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid } if resource_uid params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz' # Fetch Resource Available Timeoff c.call(:pws_get_resource_available_time_off, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_available_time_off_response][:pws_get_resource_available_time_off_result][:resource_available_time_off_schedule] end
Get Resource Cost Cards
# File lib/projector_pws.rb, line 289 def self.get_resource_cost_cards c, ticket, resource_uid = nil, exclude_before = nil, flags = { approved: true } # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:ExcludeApprovedCardsBefore'] = exclude_before.strftime '%Y-%m-%dz' if exclude_before %w(approved approved_to_pay draft paid received rejected submitted transmitted).each { |f| params["tim:Include#{f.camelcase}Flag"] = flags[f.to_sym] if flags.include? f.to_sym } params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid } if resource_uid # Fetch Resource Cost Cards c.call(:pws_get_resource_cost_cards, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_cost_cards_response][:pws_get_resource_cost_cards_result][:cost_cards] end
Get Resource Free Hours
# File lib/projector_pws.rb, line 401 def self.get_resource_free_hours c, ticket, resource, start_date = current_week_start, end_date = current_week_end, scheduled_hours = nil, wsched = nil, logger # Get scheduled hours scheduled_hours ||= get_resource_scheduled_hours c, ticket, resource, start_date, end_date free_hours = compute_resource_free_hours scheduled_hours, wsched logger.info "#FREE HOURS: #{free_hours}" free_hours end
Get Resource Schedule
# File lib/projector_pws.rb, line 248 def self.get_resource_schedule c, ticket, resource_uid = nil, start_date = current_week_start, end_date = current_week_end # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz' params['tim:IncludeScheduledTimeFlag'] = :true params['tim:IncludeTimeOffFlag'] = :true params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid } if resource_uid params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz' # Fetch Resource Schedule c.call(:pws_get_resource_schedule, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_schedule_response][:pws_get_resource_schedule_result][:resource_schedule] end
Get Resource Scheduled Hours
# File lib/projector_pws.rb, line 421 def self.get_resource_scheduled_hours c, ticket, resource, start_date = current_week_start, end_date = current_week_end, sched = nil # Get schedule sched ||= get_resource_schedule(c, ticket, resource[:resource_uid], start_date, end_date) rescue(return({ work: 0, toff: 0, hday: 0 })) # Extract scheduled work sched_work = sched[:roles][:pws_schedule_role] rescue [] sched_work = [sched_work] unless sched_work.is_a? Array sched_work.compact! # Extract scheduled time off time_off = sched[:time_off][:pws_schedule_time_off] rescue [] time_off = [time_off] unless time_off.is_a? Array time_off.compact! # Extract Holidays holidays = sched[:holidays][:pws_schedule_holiday] rescue [] holidays = [holidays] unless holidays.is_a? Array holidays.compact! # Run through time off { collect total minutes } time_off_minutes = time_off.inject(0) do |a, e| # Extract Dates dates = e[:time_off_dates][:pws_schedule_time_off_date] rescue [] dates = [dates] unless dates.is_a? Array dates.compact! # Collect time off dates a + dates.inject(0) { |da, de| da + time_off_minutes(de[:time_off_minutes].to_i) } end # Run through Holidays { collect total minutes } holiday_minutes = holidays.reject { |e| e[:date] < start_date || e[:date] > end_date || e[:date].saturday? || e[:date].sunday? }.inject(0) { |a, e| a + time_off_minutes(e[:time_off_minutes].to_i) } # Run through schedule { collect total minutes } scheduled_minutes = sched_work.inject(0) do |a, e| # Extract bookings bookings = e[:bookings][:pws_schedule_booking] rescue [] bookings = [bookings] unless bookings.is_a? Array bookings.compact! # Collect bookings a + (bookings.inject(0) { |ba, be| ba + be[:scheduled_minutes].to_i }) end { work: scheduled_minutes.to_f / MINUTES_PER_HOUR.to_f, toff: time_off_minutes.to_f / MINUTES_PER_HOUR.to_f, hday: holiday_minutes.to_f / MINUTES_PER_HOUR.to_f } end
Get Resource Working Schedule
# File lib/projector_pws.rb, line 276 def self.get_resource_working_schedule c, ticket, resource_uid = nil, start_date = current_week_start, end_date = current_week_end # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz' params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid } if resource_uid params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz' # Fetch Resource Working Schedule c.call(:pws_get_resource_working_schedule, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_working_schedule_response][:pws_get_resource_working_schedule_result][:working_schedule] end
Get Resources
# File lib/projector_pws.rb, line 197 def self.get_resources c, ticket, include_inactive = false # Prepare Params params = { 'req:SessionTicket' => ticket } params['req:IncludeInactiveFlag'] = include_inactive # Fetch Resources c.call(:pws_get_resource_list, message: { 'pws:serviceRequest' => params }).body[:pws_get_resource_list_response][:pws_get_resource_list_result][:resources][:pws_resource_summary] end
Get Resource Time Cards
# File lib/projector_pws.rb, line 229 def self.get_time_cards c, ticket, resource_uid, start_date = current_week_start, end_date = current_week_end # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz' params['tim:IncludeApprovedFlag'] = :true params['tim:IncludeDraftFlag'] = :true params['tim:IncludeRejectedFlag'] = :true params['tim:IncludeSubmittedFlag'] = :true params['tim:IncludeTimeCardsFlag'] = :true params['tim:IncludeTimeOffCardsFlag'] = :false params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid } if resource_uid params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz' # Fetch Time Entry Time Off c.call(:pws_get_time_cards, message: { 'pws:serviceRequest' => params }).body[:pws_get_time_cards_response][:pws_get_time_cards_result].try(:[], :time_entry_projects) end
Get Resource Time Entry Time Off
# File lib/projector_pws.rb, line 217 def self.get_time_entry_time_off c, ticket, resource_uid, start_date = current_week_start, end_date = current_week_end # Prepare Params params = {'req:SessionTicket' => ticket } params['tim:EndDate'] = end_date.strftime '%Y-%m-%dz' params['tim:ResourceIdentity'] = { 'com:ResourceUid' => resource_uid } if resource_uid params['tim:StartDate'] = start_date.strftime '%Y-%m-%dz' # Fetch Time Entry Time Off c.call(:pws_get_time_entry_time_off, message: { 'pws:serviceRequest' => params }).body[:pws_get_time_entry_time_off_response][:pws_get_time_entry_time_off_result].try(:[], :time_entry_time_off).try(:[], :pws_time_entry_time_off) end
Get Single Resource
# File lib/projector_pws.rb, line 207 def self.get_user c, ticket, user_uid params = { 'req:SessionTicket' => ticket } # Prepare Params params['req:UserIdentities'] = { 'com:PwsUserRef' => { 'com:UserUid' => user_uid }} # Fetch Resource Details c.call(:pws_get_user, message: {'pws:serviceRequest' => params}) end
Is Weekend
# File lib/projector_pws.rb, line 491 def self.is_weekend? (Date.today.thursday? && (DateTime.now >= DateTime.now.change(hour: WEEKEND_START_TIME))) || Date.today.friday? || Date.today.saturday? || Date.today.sunday? end
Open Client
# File lib/projector_pws.rb, line 61 def self.open url = BASE_URL c = Savon.client wsdl: WSDL, endpoint: service_url(url), namespace: NAMESPACE, env_namespace: :soapenv, namespace_identifier: :pws, namespaces: EXTRA_NAMESPACES return yield c if block_given? c end
Generate Service URL
# File lib/projector_pws.rb, line 476 def self.service_url base_url "#{base_url}/#{URL_PATH}" end
Update Cost Cards Payment Workflow Status
# File lib/projector_pws.rb, line 342 def self.set_cost_cards_payment_workflow_status c, ticket, cost_card_uids, status, send_approval_email = false, send_approval_to_pay_email = false, send_paid_email = true # Prepare Params params = { 'req:SessionTicket' => ticket } params['tim:PaymentWorkflowStatus'] = status params['tim:SendApprovalEmailFlag'] = send_approval_email params['tim:SendApprovalToPayEmailFlag'] = send_approval_to_pay_email params['tim:SendPaidEmailFlag'] = send_paid_email params['tim:StatusOrders'] = { 'tim:PwsCostPwsChangeOrder' => { 'tim:ApproveToPayFlag' => true, 'tim:CostCardIdentities' => { 'tim:PwsVersionedCostCardRef' => cost_card_uids.collect { |cc| { 'com:CostCardUid' => cc } } } } } # Set Cost Card Payment Workflow Status c.call(:pws_set_cost_card_payment_workflow_status, message: { 'pws:serviceRequest' => params }).body[:pws_set_cost_card_payment_workflow_status_response][:pws_set_cost_card_payment_workflow_status_result] end
Time Off Minutes (adjust for full-day holidays)
# File lib/projector_pws.rb, line 496 def self.time_off_minutes x (x == HOURS_PER_DAY_REAL * MINUTES_PER_HOUR) ? (HOURS_PER_DAY * MINUTES_PER_HOUR) : x end
Unauthenticate
# File lib/projector_pws.rb, line 110 def self.unauthenticate c, ticket # Unauthenticate c.call(:pws_unauthenticate, message: { 'pws:serviceRequest' => { 'req:SessionTicket' => ticket } }).body end