Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/modules/recruiting/placement_math.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 |
| Branch | feature/aioe-upgrade |
| Path or archive member | internal/modules/recruiting/placement_math.go |
| Original SHA-256 | 11c217629dbbf61eabc8712bf6390ac6e2c96080b4f23cd158d4dc93125fe435 |
| Git blob SHA | d7976746b84eb9b774b739b5175724961b0d0be5 |
| Reading-copy SHA-256 | 11c217629dbbf61eabc8712bf6390ac6e2c96080b4f23cd158d4dc93125fe435 |
Recovered source transcript
Download complete source text ↓160 lines · 6.4 KB
package recruiting
import (
"time"
"github.com/shopspring/decimal"
)
// Money arithmetic for offers and placements.
//
// Every figure here is exact decimal on values that arrived from Postgres numeric as text. None of it
// touches float64. A bill rate is multiplied by hours and by a wrap rate downstream, and binary floating
// point cannot represent 0.1, so a margin computed through a float would not reconcile with an invoice.
//
// What this file deliberately does NOT compute is projected revenue. Annualising an hourly rate requires
// assuming a full time, full year assignment that nobody has agreed to, and a number like that is
// indistinguishable on a screen from one that was actually contracted. Only quantities that follow from
// recorded facts appear here.
var (
offerStatuses = map[string]bool{
"extended": true, "accepted": true, "declined": true, "rescinded": true, "expired": true,
}
placementStatuses = map[string]bool{
"pending_start": true, "active": true, "completed": true, "terminated": true, "fell_off": true,
}
interviewKinds = map[string]bool{
"phone_screen": true, "technical": true, "client": true, "panel": true, "final": true,
}
interviewOutcomes = map[string]bool{
"scheduled": true, "passed": true, "failed": true, "no_show": true, "cancelled": true, "rescheduled": true,
}
)
// offerTransitions mirrors rm_offer_transition in migration 0055. The database is the authority; this
// exists so the interface can offer only the moves that will be accepted.
var offerTransitions = map[string][]string{
"extended": {"accepted", "declined", "rescinded", "expired"},
"accepted": {"rescinded"},
// declined and expired are terminal. Re offering is a NEW offer so the history keeps both.
"declined": {},
"rescinded": {},
"expired": {},
}
func offerCanMove(from, to string) bool {
for _, t := range offerTransitions[from] {
if t == to {
return true
}
}
return false
}
// placementEnded reports whether a status closes an assignment. An ended placement must carry an end
// date, which the database enforces, and stops being counted as live.
func placementEnded(status string) bool {
return status == "completed" || status == "terminated" || status == "fell_off"
}
// Margin is the economics of one placement or offer, all exact.
type Margin struct {
// GrossPerHour is bill minus pay. Present only for rate priced work.
GrossPerHour *decimal.Decimal `json:"gross_per_hour,omitempty"`
// Pct is gross as a share of bill, to four places. Absent when the bill rate is zero, because a
// share of nothing is undefined rather than zero, and rendering 0.00 would read as a real margin of
// nothing rather than as an unanswerable question.
Pct *decimal.Decimal `json:"margin_pct,omitempty"`
// Fee is the direct hire fee: an explicit amount when one was agreed, otherwise salary times the
// percentage. Present only for direct hire.
Fee *decimal.Decimal `json:"fee,omitempty"`
}
// marginOf computes the economics from whichever pricing shape applies.
//
// The two shapes are never blended. A contract placement earns a spread per hour and a direct hire earns
// a one time fee, and averaging them or summing them into one revenue number produces a figure that
// describes neither. Migration 0048 already requires the right columns per employment type, so this
// reads whichever pair is populated rather than guessing.
func marginOf(employmentType string, bill, pay, salary, feePct, feeAmount *decimal.Decimal) Margin {
var m Margin
if employmentType == "direct_hire" {
switch {
case feeAmount != nil:
f := *feeAmount
m.Fee = &f
case salary != nil && feePct != nil:
// fee_pct is stored as a fraction (0 to 1), so 0.20 of a 150000 salary is 30000.
f := salary.Mul(*feePct).Round(2)
m.Fee = &f
}
return m
}
if bill == nil || pay == nil {
return m
}
g := bill.Sub(*pay)
m.GrossPerHour = &g
if bill.IsZero() {
// Undefined, not zero. Returning nil is what stops a divide by zero and what stops a screen
// claiming a zero percent margin on a rate nobody set.
return m
}
p := g.Div(*bill).Mul(decimal.NewFromInt(100)).Round(4)
m.Pct = &p
return m
}
// Guarantee is the clawback position on a placement.
//
// A staffing guarantee means that if the person leaves within N days of starting, the fee is returned or
// the seat is refilled free. It is the single largest correction to reported revenue in this industry, so
// it is computed from recorded dates rather than tracked by hand.
type Guarantee struct {
Days int `json:"days"`
// EndsOn is the last day covered. Inclusive: a 90 day guarantee on a placement starting the 1st
// covers through day 90, so the boundary case is a real day and not an off by one.
EndsOn string `json:"ends_on,omitempty"`
// DaysRemaining is negative once the guarantee has run out. Absent for an ended placement, where the
// question is no longer about time remaining but about whether it fell inside.
DaysRemaining *int `json:"days_remaining,omitempty"`
// Breached is true when the assignment ended inside the guarantee window in a way that triggers it.
// A completed assignment never breaches, however short: completing early is the client's call.
Breached bool `json:"breached"`
}
// guaranteeOf computes the clawback position.
//
// Only fell_off and terminated breach. completed does not, because an assignment that ran its course is
// not a failure to deliver, and counting it as one would understate a recruiter's performance for work
// the client ended on its own terms.
func guaranteeOf(days int, start time.Time, end *time.Time, status string, today time.Time) Guarantee {
g := Guarantee{Days: days}
if days <= 0 {
return g
}
// Inclusive of the start day: a 90 day guarantee starting on the 1st ends on day 90, which is
// start + 89 days, not start + 90.
endsOn := start.AddDate(0, 0, days-1)
g.EndsOn = endsOn.Format(dateLayout)
if end != nil {
if (status == "fell_off" || status == "terminated") && !end.After(endsOn) {
g.Breached = true
}
return g
}
rem := int(endsOn.Sub(today).Hours() / 24)
g.DaysRemaining = &rem
return g
}
// interviewRoundOK bounds the round number against the CHECK in migration 0048.
func interviewRoundOK(r int) bool { return r >= 1 && r <= 20 }
// interviewConcluded reports whether an outcome requires a completed_at, mirroring interviews_completed_chk.
func interviewConcluded(outcome string) bool {
return outcome == "passed" || outcome == "failed" || outcome == "no_show"
}