Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/modules/recruiting/requisition_dto.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/modules/recruiting/requisition_dto.go |
| Original SHA-256 | a0ef23ec5620095168ebb092f220104ff876c3a3b32f7f439335b8f093b41c20 |
| Git blob SHA | a7e00e94317e7f8fa1d05daac7741800d917ff48 |
| Reading-copy SHA-256 | a0ef23ec5620095168ebb092f220104ff876c3a3b32f7f439335b8f093b41c20 |
Recovered source transcript
Download complete source text ↓194 lines · 9.1 KB
package recruiting
import (
"time"
"github.com/shopspring/decimal"
)
// Requisition is a job order: a role a client has asked this organization to fill.
//
// Money is carried as decimal and rendered as a JSON string, never a float. A bill rate is multiplied by
// hours and by a wrap rate downstream, and binary floating point cannot represent 0.1 exactly, so a rate
// that survived a round trip through a JSON number would not necessarily be the rate that was agreed.
//
// The three clocks are reported separately because they answer different questions. AgeDays is the wall
// clock a client sees. WorkingDays removes time the order spent on hold, which is the number that says
// how fast this organization actually works. HeldDays is the difference, shown so neither number has to
// be taken on trust.
type Requisition struct {
ID string `json:"id"`
ClientID string `json:"client_id,omitempty"`
ClientName string `json:"client_name,omitempty"`
// The hiring manager is constrained by the database to be a contact AT this client, so a submittal
// cannot be addressed to someone at a different company.
HiringManagerID string `json:"hiring_manager_id,omitempty"`
HiringManagerName string `json:"hiring_manager_name,omitempty"`
// Ownership is the lock, the same rule clients use. An unowned order is claimable by anyone with
// write capability; an owned one is edited by its holder or an admin.
OwnerUserID string `json:"owner_user_id,omitempty"`
OwnerName string `json:"owner_name,omitempty"`
// RequirementID bridges to the federal capture side when a job order came from a solicitation.
RequirementID string `json:"requirement_id,omitempty"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
LaborCategory string `json:"labor_category,omitempty"`
Openings int `json:"openings"`
Priority string `json:"priority"`
EmploymentType string `json:"employment_type"`
Status string `json:"status"`
// Clearance is a self reported indicator throughout this product, never a verified status.
RequiredLevel string `json:"required_level"`
RequiredPoly string `json:"required_poly"`
WorkLocation string `json:"work_location,omitempty"`
RemoteAllowed bool `json:"remote_allowed"`
BillRateMin *decimal.Decimal `json:"bill_rate_min,omitempty"`
BillRateMax *decimal.Decimal `json:"bill_rate_max,omitempty"`
PayRateMin *decimal.Decimal `json:"pay_rate_min,omitempty"`
PayRateMax *decimal.Decimal `json:"pay_rate_max,omitempty"`
SalaryMin *decimal.Decimal `json:"salary_min,omitempty"`
SalaryMax *decimal.Decimal `json:"salary_max,omitempty"`
// WHERE THIS REQUISITION CAME FROM, which changes how it is worked. A vendor management system
// distributes one req to a preferred vendor list, and most of those run five to ten agencies competing on
// the same role against a hard deadline. A desk that treats that identically to a client phone call loses
// the first kind.
IntakeSource string `json:"intake_source"`
VMSName string `json:"vms_name,omitempty"`
VMSRequisitionRef string `json:"vms_requisition_ref,omitempty"`
SubmissionDeadline string `json:"submission_deadline,omitempty"`
CompetingVendors *int `json:"competing_vendors,omitempty"`
MaxSubmissions *int `json:"max_submissions,omitempty"`
// HoursToDeadline is negative once it has passed. It is computed rather than left to the browser because
// the deadline is the single most operationally important field on a VMS req and the most often missed,
// and a screen that has to work out urgency itself is a screen that will work it out differently.
HoursToDeadline *float64 `json:"hours_to_deadline,omitempty"`
OpenedAt string `json:"opened_at"`
TargetFillDate string `json:"target_fill_date,omitempty"`
ClosedAt string `json:"closed_at,omitempty"`
OnHoldSince string `json:"on_hold_since,omitempty"`
AgeDays float64 `json:"age_days"`
WorkingDays float64 `json:"working_days"`
HeldDays float64 `json:"held_days"`
// DaysToTarget is negative when the target fill date has passed. Nil when no target was set, which
// is different from zero and must not be rendered as "due today".
DaysToTarget *int `json:"days_to_target,omitempty"`
CreatedAt string `json:"created_at"`
// UpdatedAt doubles as the optimistic concurrency token.
UpdatedAt string `json:"updated_at"`
}
// RequisitionList is an envelope so the caller learns the total without a second query.
type RequisitionList struct {
Requisitions []Requisition `json:"requisitions"`
Limit int `json:"limit"`
Offset int `json:"offset"`
Total int `json:"total"`
}
// RequisitionEvent is one status change. Append only, and the source of every duration Phase 17 reports.
type RequisitionEvent struct {
ID string `json:"id"`
FromStatus string `json:"from_status,omitempty"`
ToStatus string `json:"to_status"`
DaysInFrom float64 `json:"days_in_from"`
Note string `json:"note,omitempty"`
ActorUserID string `json:"actor_user_id,omitempty"`
ActorUserName string `json:"actor_user_name,omitempty"`
OccurredAt string `json:"occurred_at"`
}
// RequisitionDetail is an order with its history, which is how the detail screen reads it.
type RequisitionDetail struct {
Requisition
Events []RequisitionEvent `json:"events"`
}
// CreateRequisitionInput. Only a title is required. A job order is usually opened from a phone call
// with the rate and the manager still unknown, and demanding them up front makes people type
// placeholders that are worse than a blank.
type CreateRequisitionInput struct {
ClientID string `json:"client_id"`
HiringManagerID string `json:"hiring_manager_id"`
RequirementID string `json:"requirement_id"`
Title string `json:"title"`
Description string `json:"description"`
LaborCategory string `json:"labor_category"`
Openings int `json:"openings"`
Priority string `json:"priority"`
EmploymentType string `json:"employment_type"`
Status string `json:"status"`
RequiredLevel string `json:"required_level"`
RequiredPoly string `json:"required_poly"`
WorkLocation string `json:"work_location"`
RemoteAllowed bool `json:"remote_allowed"`
BillRateMin string `json:"bill_rate_min"`
BillRateMax string `json:"bill_rate_max"`
PayRateMin string `json:"pay_rate_min"`
PayRateMax string `json:"pay_rate_max"`
SalaryMin string `json:"salary_min"`
SalaryMax string `json:"salary_max"`
TargetFillDate string `json:"target_fill_date"`
IntakeSource string `json:"intake_source"`
VMSName string `json:"vms_name"`
VMSRequisitionRef string `json:"vms_requisition_ref"`
SubmissionDeadline string `json:"submission_deadline"`
CompetingVendors *int `json:"competing_vendors"`
MaxSubmissions *int `json:"max_submissions"`
}
// UpdateRequisitionInput carries the editable fields plus the concurrency token. Pointers so an omitted
// field means leave it alone, which is different from an empty string meaning clear it.
//
// Status is deliberately absent. A status change moves clocks and writes an event, so it goes through
// ChangeStatus, where the transition graph decides whether it is legal. Allowing it here would let a
// PATCH write any status directly and bypass the entire lifecycle.
type UpdateRequisitionInput struct {
ExpectedUpdatedAt string `json:"expected_updated_at"`
ClientID *string `json:"client_id,omitempty"`
HiringManagerID *string `json:"hiring_manager_id,omitempty"`
Title *string `json:"title,omitempty"`
Description *string `json:"description,omitempty"`
LaborCategory *string `json:"labor_category,omitempty"`
Openings *int `json:"openings,omitempty"`
Priority *string `json:"priority,omitempty"`
EmploymentType *string `json:"employment_type,omitempty"`
RequiredLevel *string `json:"required_level,omitempty"`
RequiredPoly *string `json:"required_poly,omitempty"`
WorkLocation *string `json:"work_location,omitempty"`
RemoteAllowed *bool `json:"remote_allowed,omitempty"`
BillRateMin *string `json:"bill_rate_min,omitempty"`
BillRateMax *string `json:"bill_rate_max,omitempty"`
PayRateMin *string `json:"pay_rate_min,omitempty"`
PayRateMax *string `json:"pay_rate_max,omitempty"`
SalaryMin *string `json:"salary_min,omitempty"`
SalaryMax *string `json:"salary_max,omitempty"`
TargetFillDate *string `json:"target_fill_date,omitempty"`
}
// ChangeStatusInput. The note is what makes the event trail readable a year later: "client froze the
// program" and "candidate accepted elsewhere" are the same transition and different stories.
type ChangeStatusInput struct {
ExpectedUpdatedAt string `json:"expected_updated_at"`
Status string `json:"status"`
Note string `json:"note"`
}
const dateLayout = "2006-01-02"
// dateStr renders a Postgres date. Only the date part, because a target fill date has no time of day and
// showing one would imply a precision the field does not have.
func dateStr(t *time.Time) string {
if t == nil {
return ""
}
return t.UTC().Format(dateLayout)
}