Skip to content

Conversation

@layoutd
Copy link
Contributor

@layoutd layoutd commented Oct 27, 2025

NOTE: This PR branches from #182 and will need merge conflict resolution with #184 and #185 (all modify the batch() method). The conflicts are trivial - just combining initialization calls.

Builds on: #182

Summary

Adds exact ratio distribution for coupon and refund generation in batch mode, eliminating variance from probabilistic distribution.

Current Behavior (Probabilistic)

With 100 orders at 0.5 coupon ratio:

  • ❌ Get 45-55 coupons (varies due to random chance)
  • ❌ Can't predict exact counts for testing

New Behavior (Deterministic)

With 100 orders at 0.5 coupon ratio:

  • ✅ Get exactly 50 coupons (pre-calculated distribution)
  • ✅ Predictable counts for testing and verification

Implementation

Coupon Distribution

Pre-generates an array of boolean flags:

// 100 orders, 0.5 ratio → exactly 50 true, 50 false
[true, true, ..., false, false]
shuffle($flags);

Odd number handling: Uses round() for non-exact splits:

  • 11 orders @ 0.5 ratio → round(11 × 0.5) = round(5.5) = 6 with coupons, 5 without

Refund Distribution

Pre-generates refund type flags with exact split using integer constants for memory efficiency:

// Integer constants for memory optimization
const REFUND_TYPE_NONE = 0;
const REFUND_TYPE_FULL = 1;
const REFUND_TYPE_PARTIAL = 2;
const REFUND_TYPE_MULTI = 3;

// 100 orders, 0.4 refund ratio → 40 refunds total:
// - 20 full (50%)
// - 10 single partial (25%)
// - 10 multi-partial (25%)
[1, 1, ..., 2, 2, ..., 3, 3, ..., 0, 0, ...]
shuffle($flags);

Odd number handling: Remainder goes to multi-partial:

  • 11 orders @ 0.4 ratio → 4 total refunds (rounded)
    • round(4 × 0.5) = 2 full
    • round(4 × 0.25) = 1 partial
    • 4 - 2 - 1 = 1 multi (remainder)
    • 11 - 4 = 7 none

Memory efficiency: For 20,000 orders, integers use ~160 KB vs strings ~160-320 KB, plus better CPU cache locality.

Benefits

  1. Deterministic Testing - Exact ratios make test verification trivial
  2. No Variance - Eliminates "it's random so ¯_(ツ)_/¯" excuse
  3. Backwards Compatible - Single orders still use probabilistic approach
  4. Memory Efficient - Integer constants instead of strings for large batches
  5. Performance - No impact (simple array operations with good cache locality)

Testing

# Test exact coupon ratio
wp wc generate orders 100 --coupon-ratio=0.5
# Result: EXACTLY 50 orders with coupons

# Test odd numbers (rounding)
wp wc generate orders 11 --coupon-ratio=0.5
# Result: EXACTLY 6 orders with coupons (5.5 rounds up)

# Test exact refund ratio  
wp wc generate orders 100 --status=completed --refund-ratio=0.4
# Result: EXACTLY 20 full, 10 partial, 10 multi-partial refunds

layoutd and others added 30 commits October 23, 2025 01:13
Co-authored-by: Copilot <[email protected]>
- Add detailed logging when orders cannot be refunded due to empty line items
- Consolidate refund creation error logs into single formatted message
- Add error logging for invalid order instance check

These improvements will help diagnose why some completed orders aren't receiving refunds when --refund-ratio=1.0 is specified.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Adds check to ensure refund amount is greater than 0 before calling wc_create_refund(). This prevents "Invalid refund amount" errors that occur when:
- Orders have 100% discount coupons (total = $0)
- Line items have $0 totals
- Calculation results in 0 or negative amount

Logs order ID, calculated amount, and order total when skipping refund.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
The "Invalid refund amount" error occurred because calculated refund amounts slightly exceeded the available order total due to rounding errors in tax calculations.

Changes:
- Calculate maximum refundable amount (order total - already refunded)
- Cap refund amount to maximum available before calling wc_create_refund()
- Round both calculated refund and max refund to 2 decimal places
- Improve error logging to show order total and already refunded amounts

Example of the issue:
- Order total: $24851.03
- Calculated refund (with 3 decimal tax): $24851.04
- Result: $0.01 over limit → "Invalid refund amount" error

This fix ensures refunds never exceed the mathematically available amount, preventing WooCommerce validation errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
…partial refunds stay under 50%

For full refunds, use the order's actual total instead of summing line items to avoid rounding discrepancies that created tiny 0.01 refunds. For partial refunds, ensure the total stays below 50% of the order total by removing items if needed, preventing two partial refunds from fully refunding an order.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
layoutd and others added 3 commits October 24, 2025 17:43
- Add division-by-zero guards before all $original_qty divisions
- Change parameter checks from !empty() to isset() to support explicit 0 values
- Remove unused variable $removed_item in refund amount calculation

These changes improve robustness and prevent potential PHP warnings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- First refunds are created within 2 months of order completion date
- Second refunds are created within 1 month of first refund date
- Update create_refund() to return refund object instead of boolean
- Pass previous refund to second refund for proper date calculation

This makes generated refund data more realistic for testing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@layoutd layoutd self-assigned this Oct 27, 2025
…ration

- Pre-generate exact counts of coupons/refunds based on ratios
- Ensures 100 orders at 0.5 ratio = exactly 50 coupons (not 45-55)
- Refunds split: 50% full, 25% partial, 25% multi-partial
- Maintains backwards compatibility with single order generation
- Only affects batch mode for predictable test data
Memory optimization for large batches:
- 20,000 orders with strings: ~160-320 KB
- 20,000 orders with integers: ~160 KB + better cache locality
- Constants: REFUND_TYPE_NONE/FULL/PARTIAL/MULTI (0-3)
@layoutd layoutd force-pushed the exact-ratio-distribution branch from 65968e7 to dc91322 Compare October 28, 2025 12:46
@layoutd layoutd requested a review from Copilot October 29, 2025 23:36
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements exact ratio distribution for batch order generation to ensure that coupon and refund ratios are applied deterministically in batch mode rather than probabilistically. This addresses accuracy issues where random application could deviate from specified ratios.

Key changes:

  • Added pre-generated flag arrays for exact ratio distribution in batch mode
  • Introduced refund type constants (NONE, FULL, PARTIAL, MULTI) for memory-efficient operations
  • Modified coupon and refund logic to use deterministic flags in batch mode while maintaining backward compatibility with probabilistic single-order generation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

layoutd and others added 4 commits October 30, 2025 01:03
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
Replace magic numbers 0.5 and 0.25 with clearly documented constants
REFUND_DISTRIBUTION_FULL_RATIO and REFUND_DISTRIBUTION_PARTIAL_RATIO
for better maintainability.
Use index-based array access instead of array_shift() to avoid
modifying static arrays during generation. This prevents sync issues
when generate() is called with $save=false.
@layoutd layoutd requested a review from Copilot October 30, 2025 00:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@layoutd layoutd marked this pull request as ready for review October 30, 2025 00:53
Base automatically changed from add-order-coupon-refund-ratios to trunk October 30, 2025 12:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants