Groups and budgets: pooled team credit budgets in WooCommerce

Groups and Budgets gives a WooCommerce store one pooled credit budget per team, plus a manager approval step on the credit draws that members make against that pool. The module ships switched off. This page documents how CreditKit Pro 2.2.0 enforces a pooled budget, when a draw reaches a manager, what each team role sees, and which behaviours are out of scope.

How do I give my team a shared budget in WooCommerce?

Switch on Groups and Budgets in wp-admin under CreditKit → Settings → Features, where the option is stored as enable_teams and defaults to false. Create the team at CreditKit → Groups & Budgets → Teams & budgets and fill in Budget limit (credits). Every member you add to that team then draws against that single pooled figure.

The team record lives in the wp_pcs_teams table, where budget figures are stored as DECIMAL(10,2) credits for a ceiling of 99,999,999.99 credits per team. Membership lives in wp_pcs_team_members under a unique key on (team, user).

Team fieldAccepted valuesEffect
Budget limit (credits)Whole number, 0 or higherCaps the credits members may draw in one period. 0 means unlimited, and consumption is still counted.
Budget periodMonthly, Quarterly, YearlySets the reset interval. The column is a MySQL ENUM, so no other value is accepted.
Require approval above a thresholdOn, OffTurns the manager approval gate on for this team.
Approval threshold (credits)Whole number, 0 or higherA draw of this credit count or more goes to the manager.
ManagerOne WordPress userReceives approval-request and budget-limit emails, and sees the approvals queue.
DepartmentFree text, up to 100 charactersGroups several teams into one row in Reports.

Enforcement is a single conditional SQL statement, not a read-then-write check in PHP. CreditKit Pro reserves budget with UPDATE wp_pcs_teams SET budget_spent = budget_spent + %s WHERE id = %d AND status = 'active' AND ( budget_limit = 0 OR budget_spent + %s <= budget_limit ) and treats one affected row as a successful reservation. Two members submitting at the same moment cannot both pass a stale check.

Can WooCommerce require manager approval before an order goes through?

CreditKit Pro gates a team member’s credit draw, not an arbitrary WooCommerce order. A member picks a credit bundle and a quantity in the request form, and the request is measured in credits as bundle credits × quantity. A normal WooCommerce checkout for a physical product is never held for approval by this module.

The gate fires only when the team has Require approval above a threshold enabled and the requested credit count is greater than or equal to the team’s approval threshold. Below that threshold, with budget headroom available, the draw completes instantly and the credits land in the member’s balance in the same request. An over-threshold request deliberately reserves no budget at submission time; the reservation happens when the manager approves, so pending requests never lock up the pool.

A manager actions the queue in two places: the Approvals tab at CreditKit → Groups & Budgets, and the customer-facing My Team page at /my-account/my-team/. Both routes call the same AJAX handlers, which require a valid pcs_enterprise_nonce, the approve_credit_requests capability, and a per-team ownership check through pcs_user_manages_team(). A manager of team A therefore cannot approve a request belonging to team B by editing the request ID.

The approve step is a conditional UPDATE … SET status = 'approved' WHERE id = %d AND status = 'pending' whose affected-row count is checked before any credits are granted. A double-click, a replayed request, or two managers approving at the same second grants the credits exactly once. CreditKit Pro emails the manager when a request is queued, and emails the requester when the request is approved or rejected.

What happens when a member’s request would overdraw the budget?

The request is queued for the team manager instead of being refused, and the member is told why. This is the behaviour most WooCommerce B2B plugins do not have, and it is what makes a pooled budget safe to hand to a team.

Consider a team with a 5,000-credit monthly limit, 4,800 credits already consumed, and an approval threshold of 1,000 credits. A member requests a 500-credit bundle. The request sits below the approval threshold, so CreditKit Pro attempts the atomic reservation first. The reservation fails, because 4,800 + 500 exceeds 5,000. Rather than returning an error, CreditKit Pro writes the request to wp_pcs_approval_requests with status pending, prefixes the stored justification with [Auto-queued: exceeds team budget], and emails the team manager.

The member sees the response Request queued for approval because it exceeds the team budget, and the row appears under My Requests with a Pending badge. The manager sees the same row in the approvals queue with the auto-queue marker in the justification column, which distinguishes a budget overrun from an ordinary over-threshold request. No member of the team can quietly push the pool past its limit through the request form.

One scope limit matters here. The cap applies to the team credit-request path. A team member who buys a credit bundle through normal WooCommerce checkout, and an administrator who runs a bulk grant, both add to budget_spent without passing the reservation gate, so those two routes can carry a team past its limit. CreditKit Pro emails the team manager once, on the purchase that crosses the limit.

Roles: member, lead, manager

Team role is stored per seat in wp_pcs_team_members.role and is separate from the WordPress user role. The My Team page renders a different set of panels for each value.

RoleMy Team page showsCan do
MemberOwn credit balance, the team allowance figure, days until the budget resets, the request form, and own request historySubmit credit requests
LeadEverything a member sees, plus the pooled budget table (period, limit, used, remaining) with a progress bar, plus a read-only list of team members and their rolesSubmit credit requests
ManagerEverything a lead sees, plus the pending approvals table with Approve and Reject buttons, plus the 20 most recent team ledger rowsSubmit credit requests, approve or reject requests for the team

Structural changes stay in wp-admin by design. Adding a member, removing a member, changing a seat’s role, and editing the budget are admin actions guarded by the manage_team_credits capability, and the My Team endpoint exposes no route for any of them. The endpoint resolves the viewer’s team from their own membership row, never from a URL parameter, so a member cannot load another team’s dashboard.

Recurring allowances and budget resets

A daily WP-Cron event named pcs_budget_period_reset rolls team budgets over. For each active team carrying spend, CreditKit Pro computes the next boundary from the stored period_start: monthly advances to the first day of the next month, quarterly advances three calendar months to the first of the month, and yearly advances one year. Boundaries snap to 00:00 in the site timezone, so a monthly period does not drift off the first of the month. When the boundary has passed, one statement sets budget_spent back to 0.00 and stamps the new period start, and the reset is written to wp_pcs_audit_log with source cron.

Recurring per-person grants are separate from the pooled budget. Set one at CreditKit → Groups & Budgets → Allowances & Bulk, where an allowance takes an amount in credits and a period of weekly, monthly, quarterly or yearly. Setting an allowance requires the bulk_credit_operations capability, and the grant is recorded as a bonus transaction on the member’s ledger. Both cron jobs check enable_teams and grant nothing while the module is off.

The same admin tab carries bulk credit assignment for one-off grants. A single batch is capped at 500 users, a per-user grant is capped at 100,000 credits, and a batch whose total exceeds 10,000 credits additionally requires the approve_credit_requests capability. All three ceilings are filterable, and every batch writes one audit-log entry.

The team ledger and reports

Every team credit grant is written to wp_pcs_enterprise_purchases with the member, the bundle, the credit count and the purchase price. The team detail screen in wp-admin renders the 50 most recent rows, and the manager view of My Team renders the 20 most recent. A bulk grant is stored with bundle ID 0 and the description Bulk grant, so a manual top-up is distinguishable from a bundle draw in the same ledger.

Reporting lives at CreditKit → Reports, which requires the WordPress manage_options capability because its store-wide scope exposes every customer. The Teams scope reports Team, Department, Budget limit (credits), Consumed (credits), Utilisation %, and an approximate currency value kept for audit reference only. CSV export runs through an admin-post handler that neutralises spreadsheet formula injection on every text cell.

Per-team discounts

A team can buy credit bundles below list price. CreditKit Pro reads the WordPress option pcs_team_discount_{team_id} as a whole-number percentage and applies it to the bundle price through the pcs_bundle_price filter for every member of that team. A value of 15 sells every bundle to that team at 85% of its list price.

wp option update pcs_team_discount_4 15

Version 2.2.0 ships no admin field for this option, so set it with WP-CLI as above, with update_option() in site code, or through any options editor. Integrators who need pricing logic beyond a flat percentage should hook pcs_bundle_price directly, which receives the price, the bundle object and the user ID.

What this doesn’t do

  • Daily and weekly budget periods do not exist. The budget_period column is an ENUM of monthly, quarterly and yearly, and any other value is rejected before the write.
  • Volume-discount tiers were retired on the team path in version 2.2.0. The pcs_volume_discount_tiers filter is no longer applied when a team member buys a bundle, because the tiers were denominated in currency while team budgets are counted in credits. Per-team discounts are unaffected.
  • A budget limit of 0 means unlimited, not zero. Set a positive limit on any team that must be capped.
  • Approval gates a credit draw against the team budget. Holding an arbitrary WooCommerce order for sign-off before it is placed is outside this module.
  • The module is off on a fresh install, and no team menu, cron job or My Team tab appears until enable_teams is switched on.
  • A user holds one active team seat at a time. Assigning a user who already belongs to a team returns User is already assigned to a team.
  • The per-team Notification emails field is saved to the database, and version 2.2.0 still sends budget-limit and approval-request emails to the team manager’s WordPress account address only.

Everything described here is CreditKit Pro version 2.2.0 as shipped. The settings reference covers the Features tab that switches the module on, and the demo store runs the module with teams already configured.