wiq-cli 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/docs/deferred.md +8 -1
- data/docs/wiq_api_notes.md +54 -0
- data/lib/wiq/cli.rb +6 -0
- data/lib/wiq/commands/parents.rb +114 -0
- data/lib/wiq/commands/payouts.rb +124 -0
- data/lib/wiq/commands/wrestlers.rb +19 -6
- data/lib/wiq/version.rb +1 -1
- data/lib/wiq.rb +2 -0
- data/share/skills/wiq/SKILL.md +39 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: eb99112754a10af0b80b20d71425f95e864fb28a3db78a1c3d0e7d75340ebf8f
|
|
4
|
+
data.tar.gz: ee12d73a7e5053dd48540c73c35e4327bb3f4456998f3182725b2a1d40a99403
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 92e5c6842312a60ad606f711b5c6893c2a2c761e181b0c999dcf0fcb6bb1e92f8cc3b25dadd6c365656b91f7b242666b43131e5680ec440036c67868f04eb794
|
|
7
|
+
data.tar.gz: a4e06d43acf373996c31593b6a736555ab9b5aa71a4d7c0baf606f8dc76fa090f3ae7519820ec04ed6ca1167375b977261d12312bca2fe07b70de86f902430e6
|
data/docs/deferred.md
CHANGED
|
@@ -68,9 +68,16 @@ Last updated: 2026-05-12 (after L1 ships).
|
|
|
68
68
|
--all flag, base payload kept tight. Filters translate to Ransack
|
|
69
69
|
(--first-name, --last-name, --weight-class, --academic-class, --age,
|
|
70
70
|
--roster, --profile-type) + legacy free-text --query. --expand opts
|
|
71
|
-
into rosters / registration_answers
|
|
71
|
+
into rosters / registration_answers / notification_preferences
|
|
72
|
+
(coach-only, Aug 2026 — see wiq_api_notes.md) per row. Multi-roster
|
|
72
73
|
intersection deferred (API supports it; CLI surface didn't justify
|
|
73
74
|
the complexity for v1). `wiq wrestlers show <id>` paired.
|
|
75
|
+
- ~~**`wiq parents list/show`**~~ SHIPPED narrow (Aug 2026, alongside
|
|
76
|
+
the `expand_notification_preferences` param from wrestling PR #2460).
|
|
77
|
+
Filters: --query (legacy name search), --first-name / --last-name
|
|
78
|
+
(Ransack). --expand notification_preferences (coach-only). Slim
|
|
79
|
+
payload by design (id, user_id, type, names); no wrestler refs —
|
|
80
|
+
family linkage stays on the wrestlers side.
|
|
74
81
|
- **`wiq url parse <url>`** — extract team/roster/event IDs from WIQ web
|
|
75
82
|
URLs. Initial-plan item; useful for agents pasted URLs by humans.
|
|
76
83
|
- **`wiq paid_sessions create/update`**, **`wiq rosters create/update`**,
|
data/docs/wiq_api_notes.md
CHANGED
|
@@ -390,6 +390,60 @@ them. PATs minted by parents/wrestlers will 403 here.
|
|
|
390
390
|
shape (`category`, `subcategory`, `detail_category`, `total_net_amount`)
|
|
391
391
|
— special-case it in the formatter.
|
|
392
392
|
|
|
393
|
+
## Wrestlers + parents: `expand_notification_preferences`
|
|
394
|
+
|
|
395
|
+
Shipped Aug 2026 (wrestling PR #2460). All four endpoints accept
|
|
396
|
+
`expand_notification_preferences=true`:
|
|
397
|
+
|
|
398
|
+
- `GET /api/v1/wrestlers` / `GET /api/v1/wrestlers/:id`
|
|
399
|
+
- `GET /api/v1/parents` / `GET /api/v1/parents/:id`
|
|
400
|
+
|
|
401
|
+
When set, each profile gains two fields, mirroring the "Notified via"
|
|
402
|
+
section on the web profile pages:
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"wiq_app_installed": true,
|
|
407
|
+
"notification_preferences": {
|
|
408
|
+
"email": true, "sms": false, "push": true, "push_user_pref": true
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Things to know:
|
|
414
|
+
|
|
415
|
+
- **Coach-gated, silently.** `expand_notification_preferences?` in
|
|
416
|
+
`base_controller.rb` requires `current_profile.coach?`. A parent- or
|
|
417
|
+
wrestler-bound PAT gets a normal 200 with the fields simply absent —
|
|
418
|
+
no error. Don't diagnose missing fields as a bug; check the PAT's
|
|
419
|
+
profile type first (`wiq auth status`).
|
|
420
|
+
- **Nullable prefs.** `notification_preference` is a `has_one` that may
|
|
421
|
+
not exist; each key can be `null` (rendered via `np&.email` etc.).
|
|
422
|
+
Treat `null` as "no explicit preference recorded", not "off".
|
|
423
|
+
- The controller eager-loads `:notification_preference` only when the
|
|
424
|
+
flag is set, so the index cost is opt-in.
|
|
425
|
+
|
|
426
|
+
CLI exposure: `wiq wrestlers list|show --expand notification_preferences`
|
|
427
|
+
(composes with `rosters`, `registration_answers` in the same CSV) and
|
|
428
|
+
`wiq parents list|show --expand notification_preferences`.
|
|
429
|
+
|
|
430
|
+
While we're here, the parents endpoints themselves
|
|
431
|
+
(`app/controllers/api/v1/parents_controller.rb`):
|
|
432
|
+
|
|
433
|
+
- Index scope is `team.parent_profiles.teammates` ordered by first
|
|
434
|
+
name — guest parents (camp signups) are excluded. Policy scope:
|
|
435
|
+
coaches see the whole team (roster-restricted coaches see only their
|
|
436
|
+
allowed parents), wrestlers see their own guardians, parents see
|
|
437
|
+
nobody.
|
|
438
|
+
- Filters: legacy `?query=` name search, plus Ransack limited to
|
|
439
|
+
`id, first_name, last_name` (`ParentProfile.ransackable_attributes`).
|
|
440
|
+
- The jbuilder payload is slim: `id, user_id, type, first_name,
|
|
441
|
+
last_name, full_name` (+ the expand fields above). No wrestler refs —
|
|
442
|
+
walk the family from the wrestler side (`wiq wrestlers show <id>`
|
|
443
|
+
embeds parent refs).
|
|
444
|
+
- `show` uses `ParentProfile.with_deleted` — soft-deleted parents still
|
|
445
|
+
resolve by id.
|
|
446
|
+
|
|
393
447
|
## Check-ins (attendance)
|
|
394
448
|
|
|
395
449
|
Two index endpoints + create/update on the event-scoped path.
|
data/lib/wiq/cli.rb
CHANGED
|
@@ -83,10 +83,16 @@ module Wiq
|
|
|
83
83
|
desc "wrestlers SUBCOMMAND", "Search wrestlers — narrow ID-discovery surface (list, show)"
|
|
84
84
|
subcommand "wrestlers", Wiq::Commands::Wrestlers
|
|
85
85
|
|
|
86
|
+
desc "parents SUBCOMMAND", "Search parents — narrow ID-discovery surface (list, show)"
|
|
87
|
+
subcommand "parents", Wiq::Commands::Parents
|
|
88
|
+
|
|
86
89
|
desc "charges SUBCOMMAND", "Payment history — list charges by family, status, type, date (admin only)"
|
|
87
90
|
subcommand "charges", Wiq::Commands::Charges
|
|
88
91
|
|
|
89
92
|
desc "billing_profiles SUBCOMMAND", "Look up a parent or coach's billing profile (admin only)"
|
|
90
93
|
subcommand "billing_profiles", Wiq::Commands::BillingProfiles
|
|
94
|
+
|
|
95
|
+
desc "payouts SUBCOMMAND", "Bank payouts / deposits — list and show (admin only)"
|
|
96
|
+
subcommand "payouts", Wiq::Commands::Payouts
|
|
91
97
|
end
|
|
92
98
|
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wiq
|
|
4
|
+
module Commands
|
|
5
|
+
class Parents < Base
|
|
6
|
+
DEFAULT_PER_PAGE = 20
|
|
7
|
+
|
|
8
|
+
desc "list", "Search parents — narrow ID-discovery surface"
|
|
9
|
+
long_desc <<~DESC
|
|
10
|
+
Narrow listing over the team's parent profiles (teammates only —
|
|
11
|
+
guest parents from camp signups are excluded server-side). Rows
|
|
12
|
+
are slim: id, user_id, type, first_name, last_name, full_name.
|
|
13
|
+
Sorted by first name. Default page size is 20; there's no --all
|
|
14
|
+
flag.
|
|
15
|
+
|
|
16
|
+
Filters:
|
|
17
|
+
--query free-text name search (legacy `?query=`)
|
|
18
|
+
--first-name q[first_name_cont]
|
|
19
|
+
--last-name q[last_name_cont]
|
|
20
|
+
|
|
21
|
+
--expand opts into a wider payload:
|
|
22
|
+
notification_preferences Adds wiq_app_installed + a
|
|
23
|
+
notification_preferences object
|
|
24
|
+
(email, sms, push, push_user_pref)
|
|
25
|
+
per parent — "which parents can we
|
|
26
|
+
reach, and how?". Coach PATs only;
|
|
27
|
+
the server silently omits it for
|
|
28
|
+
parent/wrestler tokens.
|
|
29
|
+
|
|
30
|
+
The parent → wrestler linkage is NOT in this payload. To see a
|
|
31
|
+
family's kids, go the other direction: `wiq wrestlers show <id>`
|
|
32
|
+
embeds parent refs, or `wiq wrestlers list --query <last name>`.
|
|
33
|
+
DESC
|
|
34
|
+
method_option :query, type: :string, desc: "Free-text name search"
|
|
35
|
+
method_option :first_name, type: :string, desc: "First name (contains)"
|
|
36
|
+
method_option :last_name, type: :string, desc: "Last name (contains)"
|
|
37
|
+
method_option :expand, type: :string,
|
|
38
|
+
desc: "CSV: notification_preferences"
|
|
39
|
+
method_option :per_page, type: :numeric, default: DEFAULT_PER_PAGE,
|
|
40
|
+
desc: "Page size (default 20; narrow surface)"
|
|
41
|
+
def list
|
|
42
|
+
params = build_list_params
|
|
43
|
+
|
|
44
|
+
records, total = fetch_index("/api/v1/parents", params, key: "parent_profiles")
|
|
45
|
+
render_index(
|
|
46
|
+
records, total: total,
|
|
47
|
+
summary: "Listed #{records.size} parents#{summary_filters_suffix}.",
|
|
48
|
+
breadcrumbs: [
|
|
49
|
+
{ "cmd" => "wiq parents show <id>", "description" => "Drill into one parent" },
|
|
50
|
+
{ "cmd" => "wiq billing_profiles show <id> --profile-type ParentProfile",
|
|
51
|
+
"description" => "Billing profile for a parent (admin only)" },
|
|
52
|
+
{ "cmd" => "wiq wrestlers list --last-name <name>",
|
|
53
|
+
"description" => "Find the family's wrestlers (parent refs embedded)" }
|
|
54
|
+
]
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
desc "show ID", "Fetch a single parent profile"
|
|
59
|
+
long_desc <<~DESC
|
|
60
|
+
Single-parent drill-down. Same slim payload as the index (id,
|
|
61
|
+
user_id, type, names); soft-deleted parents still resolve here.
|
|
62
|
+
|
|
63
|
+
Pass --expand for additional sections:
|
|
64
|
+
notification_preferences wiq_app_installed + notification_preferences
|
|
65
|
+
(email, sms, push, push_user_pref) —
|
|
66
|
+
"can this parent be reached, and how?"
|
|
67
|
+
Coach PATs only; silently omitted for
|
|
68
|
+
parent/wrestler tokens.
|
|
69
|
+
DESC
|
|
70
|
+
method_option :expand, type: :string,
|
|
71
|
+
desc: "CSV: notification_preferences"
|
|
72
|
+
def show(id)
|
|
73
|
+
params = {}
|
|
74
|
+
params["expand_notification_preferences"] = true if expand_includes?("notification_preferences")
|
|
75
|
+
parent = client.get("/api/v1/parents/#{id}", params)
|
|
76
|
+
render(parent,
|
|
77
|
+
summary: "Parent #{parent["id"]} — #{parent["full_name"]}",
|
|
78
|
+
breadcrumbs: [
|
|
79
|
+
{ "cmd" => "wiq billing_profiles show #{parent["id"]} --profile-type ParentProfile",
|
|
80
|
+
"description" => "Billing profile for this parent (admin only)" },
|
|
81
|
+
{ "cmd" => "wiq wrestlers list --last-name #{parent["last_name"]}",
|
|
82
|
+
"description" => "Likely wrestlers for this family" }
|
|
83
|
+
])
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
no_commands do
|
|
87
|
+
# Extracted so the spec can verify the option → query-param mapping
|
|
88
|
+
# without round-tripping a real Faraday connection.
|
|
89
|
+
def build_list_params
|
|
90
|
+
params = { "per_page" => options[:per_page] || DEFAULT_PER_PAGE }
|
|
91
|
+
params["query"] = options[:query] if options[:query]
|
|
92
|
+
params["q[first_name_cont]"] = options[:first_name] if options[:first_name]
|
|
93
|
+
params["q[last_name_cont]"] = options[:last_name] if options[:last_name]
|
|
94
|
+
params["expand_notification_preferences"] = true if expand_includes?("notification_preferences")
|
|
95
|
+
params
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def expand_includes?(part)
|
|
99
|
+
return false unless options[:expand]
|
|
100
|
+
|
|
101
|
+
options[:expand].split(",").map(&:strip).include?(part)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def summary_filters_suffix
|
|
105
|
+
bits = []
|
|
106
|
+
bits << "matching #{options[:query].inspect}" if options[:query]
|
|
107
|
+
bits << "first name ~ #{options[:first_name].inspect}" if options[:first_name]
|
|
108
|
+
bits << "last name ~ #{options[:last_name].inspect}" if options[:last_name]
|
|
109
|
+
bits.empty? ? "" : " (#{bits.join(", ")})"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wiq
|
|
4
|
+
module Commands
|
|
5
|
+
class Payouts < Base
|
|
6
|
+
# Payout.status is a plain text column mirroring the billing
|
|
7
|
+
# partner's normalized status — no integer-enum translation needed
|
|
8
|
+
# (unlike Charge.status). Common values below; the column is not
|
|
9
|
+
# constrained server-side, so --status stays free-form.
|
|
10
|
+
COMMON_STATUSES = %w[paid in_transit scheduled].freeze
|
|
11
|
+
BILLING_PARTNERS = %w[stripe justifi].freeze
|
|
12
|
+
DEFAULT_PER_PAGE = 25
|
|
13
|
+
|
|
14
|
+
desc "list", "List bank payouts / deposits (finance: admin coach only)"
|
|
15
|
+
long_desc <<~DESC
|
|
16
|
+
Returns payouts — the batched deposits Stripe or Justifi (WIQ
|
|
17
|
+
Payments) sends to the club's bank account. Useful for "when does
|
|
18
|
+
our money arrive?", "what landed in the bank last week?", and
|
|
19
|
+
reconciling a bank statement line against WIQ charges.
|
|
20
|
+
|
|
21
|
+
Auth: admin-only (Pundit scope filters non-admin coach PATs to
|
|
22
|
+
empty results; parent/wrestler PATs return 403).
|
|
23
|
+
|
|
24
|
+
Filters translate to Ransack server-side (allowlist: deposits_at,
|
|
25
|
+
status, billing_partner, amount, created_at):
|
|
26
|
+
--status <str> q[status_eq]. Common values: paid,
|
|
27
|
+
in_transit, scheduled. Free-form —
|
|
28
|
+
the column mirrors the billing
|
|
29
|
+
partner's status strings.
|
|
30
|
+
--billing-partner <str> q[billing_partner_eq] — stripe | justifi
|
|
31
|
+
(justifi is branded "WIQ Payments").
|
|
32
|
+
--since <YYYY-MM-DD> q[deposits_at_gteq]
|
|
33
|
+
--until <YYYY-MM-DD> q[deposits_at_lteq]
|
|
34
|
+
|
|
35
|
+
--since/--until filter on deposits_at (when the money reaches the
|
|
36
|
+
bank), not created_at — that's the date a treasurer reconciling a
|
|
37
|
+
bank statement cares about. Rows come back newest-deposit first.
|
|
38
|
+
|
|
39
|
+
Money fields are integer cents. Each row: amount (net deposit),
|
|
40
|
+
payments_count/payments_total, refunds_count/refunds_total,
|
|
41
|
+
fees_total, status, deposits_at, billing_partner, description,
|
|
42
|
+
and destination (bank name + last4). Payouts accrue slowly (a
|
|
43
|
+
few per week), so default page size is #{DEFAULT_PER_PAGE}; pass
|
|
44
|
+
--all with --since to bound an exhaustive scan.
|
|
45
|
+
|
|
46
|
+
To see which individual charges landed in a payout, go through
|
|
47
|
+
the charges side: each `wiq charges list` row embeds its payout,
|
|
48
|
+
so filter charges by date window and group on payout.id.
|
|
49
|
+
DESC
|
|
50
|
+
method_option :status, type: :string,
|
|
51
|
+
desc: "Filter by status (common: #{COMMON_STATUSES.join(", ")})"
|
|
52
|
+
method_option :billing_partner, type: :string, enum: BILLING_PARTNERS,
|
|
53
|
+
desc: "Filter by billing partner (stripe | justifi)"
|
|
54
|
+
method_option :since, type: :string, desc: "Earliest deposits_at (YYYY-MM-DD)"
|
|
55
|
+
method_option :until, type: :string, desc: "Latest deposits_at (YYYY-MM-DD)"
|
|
56
|
+
method_option :per_page, type: :numeric, default: DEFAULT_PER_PAGE,
|
|
57
|
+
desc: "Page size (default #{DEFAULT_PER_PAGE})"
|
|
58
|
+
method_option :all, type: :boolean, default: false,
|
|
59
|
+
desc: "Follow pagination until exhausted"
|
|
60
|
+
def list
|
|
61
|
+
params = build_list_params
|
|
62
|
+
records, total = fetch_index("/api/v1/payouts", params, key: "payouts")
|
|
63
|
+
render_index(
|
|
64
|
+
records, total: total,
|
|
65
|
+
summary: "Listed #{records.size} payouts#{summary_filters_suffix}.",
|
|
66
|
+
breadcrumbs: [
|
|
67
|
+
{ "cmd" => "wiq payouts show <id>",
|
|
68
|
+
"description" => "Inspect a single payout" },
|
|
69
|
+
{ "cmd" => "wiq charges list --since <date> --until <date> --all",
|
|
70
|
+
"description" => "Charges in a window — each row embeds its payout for reconciliation" }
|
|
71
|
+
]
|
|
72
|
+
)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
desc "show ID", "Fetch a single payout"
|
|
76
|
+
long_desc <<~DESC
|
|
77
|
+
Full payout payload: amount, currency, status, deposits_at,
|
|
78
|
+
payments_count/payments_total, refunds_count/refunds_total,
|
|
79
|
+
fees_total, billing_partner (+ billing_partner_id, the Stripe/
|
|
80
|
+
Justifi payout id like po_...), delivery_method, description, and
|
|
81
|
+
destination bank account (holder name, bank name, last4,
|
|
82
|
+
account type). Money fields are integer cents.
|
|
83
|
+
|
|
84
|
+
Auth: admin-only; a payout outside the PAT's team returns 403.
|
|
85
|
+
DESC
|
|
86
|
+
def show(id)
|
|
87
|
+
payout = client.get("/api/v1/payouts/#{id}")
|
|
88
|
+
render(payout,
|
|
89
|
+
summary: "Payout #{payout["id"]} — #{payout["status"]}, " \
|
|
90
|
+
"#{format_cents(payout["amount"])} deposited #{payout["deposits_at"]}",
|
|
91
|
+
breadcrumbs: [
|
|
92
|
+
{ "cmd" => "wiq charges list --since <date> --until <date> --all",
|
|
93
|
+
"description" => "Find this payout's charges (rows embed payout.id)" }
|
|
94
|
+
])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
no_commands do
|
|
98
|
+
def build_list_params
|
|
99
|
+
params = { "per_page" => options[:per_page] || DEFAULT_PER_PAGE }
|
|
100
|
+
params["q[status_eq]"] = options[:status] if options[:status]
|
|
101
|
+
params["q[billing_partner_eq]"] = options[:billing_partner] if options[:billing_partner]
|
|
102
|
+
params["q[deposits_at_gteq]"] = options[:since] if options[:since]
|
|
103
|
+
params["q[deposits_at_lteq]"] = options[:until] if options[:until]
|
|
104
|
+
params
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def summary_filters_suffix
|
|
108
|
+
bits = []
|
|
109
|
+
bits << "status=#{options[:status]}" if options[:status]
|
|
110
|
+
bits << "billing_partner=#{options[:billing_partner]}" if options[:billing_partner]
|
|
111
|
+
bits << "since=#{options[:since]}" if options[:since]
|
|
112
|
+
bits << "until=#{options[:until]}" if options[:until]
|
|
113
|
+
bits.empty? ? "" : " (#{bits.join(", ")})"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def format_cents(cents)
|
|
117
|
+
return "?" unless cents.is_a?(Numeric)
|
|
118
|
+
|
|
119
|
+
format("$%.2f", cents / 100.0)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -35,8 +35,14 @@ module Wiq
|
|
|
35
35
|
client-side.
|
|
36
36
|
|
|
37
37
|
--expand opts into a wider payload:
|
|
38
|
-
rosters
|
|
39
|
-
registration_answers
|
|
38
|
+
rosters Adds full roster details per wrestler
|
|
39
|
+
registration_answers Adds intake-form answers per wrestler
|
|
40
|
+
notification_preferences Adds wiq_app_installed + a
|
|
41
|
+
notification_preferences object
|
|
42
|
+
(email, sms, push, push_user_pref)
|
|
43
|
+
per wrestler. Coach PATs only — the
|
|
44
|
+
server silently omits it for
|
|
45
|
+
parent/wrestler tokens.
|
|
40
46
|
|
|
41
47
|
Base payload is already wider than most index endpoints (parents,
|
|
42
48
|
coach_guardians, profile_photos, basic roster refs all render by
|
|
@@ -58,7 +64,7 @@ module Wiq
|
|
|
58
64
|
desc: "Default 'teammate' matches the WIQ web UI default; " \
|
|
59
65
|
"'all' removes the filter entirely"
|
|
60
66
|
method_option :expand, type: :string,
|
|
61
|
-
desc: "CSV: rosters, registration_answers"
|
|
67
|
+
desc: "CSV: rosters, registration_answers, notification_preferences"
|
|
62
68
|
method_option :per_page, type: :numeric, default: DEFAULT_PER_PAGE,
|
|
63
69
|
desc: "Page size (default 20; narrow surface)"
|
|
64
70
|
def list
|
|
@@ -84,15 +90,21 @@ module Wiq
|
|
|
84
90
|
rosters refs).
|
|
85
91
|
|
|
86
92
|
Pass --expand for additional sections:
|
|
87
|
-
rosters
|
|
88
|
-
registration_answers
|
|
93
|
+
rosters Full roster details with tags
|
|
94
|
+
registration_answers Intake-form answers
|
|
95
|
+
notification_preferences wiq_app_installed + notification_preferences
|
|
96
|
+
(email, sms, push, push_user_pref) —
|
|
97
|
+
"can this family be reached, and how?"
|
|
98
|
+
Coach PATs only; silently omitted for
|
|
99
|
+
parent/wrestler tokens.
|
|
89
100
|
DESC
|
|
90
101
|
method_option :expand, type: :string,
|
|
91
|
-
desc: "CSV: rosters, registration_answers"
|
|
102
|
+
desc: "CSV: rosters, registration_answers, notification_preferences"
|
|
92
103
|
def show(id)
|
|
93
104
|
params = {}
|
|
94
105
|
params["expand_rosters"] = true if expand_includes?("rosters")
|
|
95
106
|
params["expand_registration_answers"] = true if expand_includes?("registration_answers")
|
|
107
|
+
params["expand_notification_preferences"] = true if expand_includes?("notification_preferences")
|
|
96
108
|
wrestler = client.get("/api/v1/wrestlers/#{id}", params)
|
|
97
109
|
render(wrestler,
|
|
98
110
|
summary: "Wrestler #{wrestler["id"]} — #{wrestler["full_name"] || wrestler["display_name"]}",
|
|
@@ -120,6 +132,7 @@ module Wiq
|
|
|
120
132
|
params["q[profile_type_eq]"] = options[:profile_type] if profile_type_filter?
|
|
121
133
|
params["expand_rosters"] = true if expand_includes?("rosters")
|
|
122
134
|
params["expand_registration_answers"] = true if expand_includes?("registration_answers")
|
|
135
|
+
params["expand_notification_preferences"] = true if expand_includes?("notification_preferences")
|
|
123
136
|
params
|
|
124
137
|
end
|
|
125
138
|
|
data/lib/wiq/version.rb
CHANGED
data/lib/wiq.rb
CHANGED
|
@@ -26,6 +26,8 @@ require "wiq/commands/prospect_families"
|
|
|
26
26
|
require "wiq/commands/workflows"
|
|
27
27
|
require "wiq/commands/setup"
|
|
28
28
|
require "wiq/commands/wrestlers"
|
|
29
|
+
require "wiq/commands/parents"
|
|
29
30
|
require "wiq/commands/charges"
|
|
30
31
|
require "wiq/commands/billing_profiles"
|
|
32
|
+
require "wiq/commands/payouts"
|
|
31
33
|
require "wiq/cli"
|
data/share/skills/wiq/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wiq
|
|
3
|
-
description: Use this skill when the user asks about their WrestlingIQ data — rosters, attendance, check-ins, paid sessions and registrations, the prospects/leads pipeline, financial metrics, reports, USAW/AAU memberships, fundraising, online store orders, or per-location/site breakdowns for multi-gym clubs. The `wiq` CLI provides read-only access to /api/v1 via personal access tokens. Recognize phrasings like "how is our pipeline?", "who came to practice this week?", "show me the roster", "what's our MRR?", "which kids need USAW renewal?", "how is the Eastside gym doing?", or anything that maps to a wrestling club's admin workflows.
|
|
3
|
+
description: Use this skill when the user asks about their WrestlingIQ data — rosters, attendance, check-ins, paid sessions and registrations, the prospects/leads pipeline, financial metrics, payouts/bank deposits, reports, USAW/AAU memberships, fundraising, online store orders, or per-location/site breakdowns for multi-gym clubs. The `wiq` CLI provides read-only access to /api/v1 via personal access tokens. Recognize phrasings like "how is our pipeline?", "who came to practice this week?", "show me the roster", "what's our MRR?", "which kids need USAW renewal?", "how is the Eastside gym doing?", or anything that maps to a wrestling club's admin workflows.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# WrestlingIQ CLI Skill
|
|
@@ -284,6 +284,25 @@ charge for the same `(billing_profile_id, chargeable_id,
|
|
|
284
284
|
chargeable_type)` tuple exists AFTER the failure's `created_at`. The
|
|
285
285
|
canonical pattern is in `wiq workflows show failed-payments-recent`.
|
|
286
286
|
|
|
287
|
+
### Payouts (bank deposits)
|
|
288
|
+
|
|
289
|
+
For "when does our money hit the bank?" / "what deposited last week?" /
|
|
290
|
+
bank-statement reconciliation — use the payouts surface (admin PAT only):
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
wiq payouts list --since 2026-08-01 --until 2026-08-18 # deposits in a window
|
|
294
|
+
wiq payouts list --status in_transit # money on the way
|
|
295
|
+
wiq payouts show <id> # one deposit's detail
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`--since/--until` filter on `deposits_at` (bank arrival date), not
|
|
299
|
+
`created_at`. `Payout.status` is a plain string column (paid,
|
|
300
|
+
in_transit, scheduled, ...) — no integer-enum translation, unlike
|
|
301
|
+
charges. All
|
|
302
|
+
money fields are integer cents. To see which charges make up a payout,
|
|
303
|
+
go through charges: each `wiq charges list` row embeds its `payout`,
|
|
304
|
+
so pull charges for the date window and group by `payout.id`.
|
|
305
|
+
|
|
287
306
|
To go from a wrestler name to a billing_profile_id:
|
|
288
307
|
|
|
289
308
|
```bash
|
|
@@ -343,6 +362,25 @@ For exhaustive exports go through `wiq reports run RosterReport`
|
|
|
343
362
|
`profile_type=teammate` (matching the WIQ web UI default); pass
|
|
344
363
|
`--profile-type alumnus|guest|all` to widen.
|
|
345
364
|
|
|
365
|
+
For "can this family be reached, and how?" questions, add
|
|
366
|
+
`--expand notification_preferences` to `wrestlers list|show` or
|
|
367
|
+
`parents list|show`. Each row gains `wiq_app_installed` plus a
|
|
368
|
+
`notification_preferences` object (`email`, `sms`, `push`,
|
|
369
|
+
`push_user_pref`; `null` means no explicit preference recorded). Coach
|
|
370
|
+
PATs only — with a parent/wrestler token the server returns 200 with
|
|
371
|
+
the fields silently absent, so a missing field means "check the
|
|
372
|
+
token's profile type", not "API bug".
|
|
373
|
+
|
|
374
|
+
### Parents
|
|
375
|
+
|
|
376
|
+
`wiq parents list [--query <name>] [--first-name X] [--last-name Y]`
|
|
377
|
+
and `wiq parents show <id>` — slim payload (id, user_id, names) over
|
|
378
|
+
the team's teammate parents. There are no wrestler refs on a parent
|
|
379
|
+
row; to walk a family, start from the wrestler side
|
|
380
|
+
(`wiq wrestlers show <id>` embeds parent refs). Main uses: parent-first
|
|
381
|
+
ID discovery for `wiq billing_profiles show <id> --profile-type
|
|
382
|
+
ParentProfile`, and the notification-reachability expand above.
|
|
383
|
+
|
|
346
384
|
## Locations (multi-site clubs)
|
|
347
385
|
|
|
348
386
|
WIQ has a structured Location model (name + street address, per team).
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: wiq-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- WrestlingIQ
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: thor
|
|
@@ -93,6 +93,8 @@ files:
|
|
|
93
93
|
- lib/wiq/commands/locations.rb
|
|
94
94
|
- lib/wiq/commands/metrics.rb
|
|
95
95
|
- lib/wiq/commands/paid_sessions.rb
|
|
96
|
+
- lib/wiq/commands/parents.rb
|
|
97
|
+
- lib/wiq/commands/payouts.rb
|
|
96
98
|
- lib/wiq/commands/prospect_families.rb
|
|
97
99
|
- lib/wiq/commands/prospects.rb
|
|
98
100
|
- lib/wiq/commands/registrations.rb
|