Skip to content

Commit b042261

Browse files
committed
Merge remote-tracking branch 'origin/trunk' into optimize-order-date-generation
2 parents 09500f2 + 2858ffd commit b042261

File tree

3 files changed

+137
-15
lines changed

3 files changed

+137
-15
lines changed

includes/Generator/Coupon.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ class Coupon extends Generator {
2424
public static function generate( $save = true, $assoc_args = array() ) {
2525
parent::maybe_initialize_generators();
2626

27-
$defaults = array(
28-
'min' => 5,
29-
'max' => 100,
30-
'discount_type' => 'fixed_cart',
31-
);
27+
$defaults = array(
28+
'min' => 5,
29+
'max' => 100,
30+
'discount_type' => 'fixed_cart',
31+
);
3232

3333
$args = wp_parse_args( $assoc_args, $defaults );
3434

includes/Generator/Order.php

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Order extends Generator {
3232
* Maximum days after first refund for second refund (1 month).
3333
*/
3434
const SECOND_REFUND_MAX_DAYS = 30;
35-
35+
3636
/**
3737
* Pre-generated dates for batch order creation (ensures chronological order by ID).
3838
*
@@ -53,6 +53,7 @@ public static function generate( $save = true, $assoc_args = array() ) {
5353
$order = new \WC_Order();
5454
$customer = self::get_customer();
5555
if ( ! $customer instanceof \WC_Customer ) {
56+
error_log( 'Order generation failed: Could not generate or retrieve customer' );
5657
error_log( 'Order generation failed: Could not generate or retrieve customer' );
5758
return false;
5859
}
@@ -63,6 +64,11 @@ public static function generate( $save = true, $assoc_args = array() ) {
6364
return false;
6465
}
6566

67+
if ( empty( $products ) ) {
68+
error_log( 'Order generation failed: No products available to add to order' );
69+
return false;
70+
}
71+
6672
foreach ( $products as $product ) {
6773
$quantity = self::$faker->numberBetween( 1, 10 );
6874
$order->add_product( $product, $quantity );
@@ -123,9 +129,30 @@ public static function generate( $save = true, $assoc_args = array() ) {
123129

124130
$order->set_date_created( $date );
125131

132+
// Handle legacy --coupons flag
126133
// Handle legacy --coupons flag
127134
$include_coupon = ! empty( $assoc_args['coupons'] );
128135

136+
// Handle --coupon-ratio parameter
137+
if ( isset( $assoc_args['coupon-ratio'] ) ) {
138+
$coupon_ratio = floatval( $assoc_args['coupon-ratio'] );
139+
140+
// Validate ratio is between 0.0 and 1.0
141+
if ( $coupon_ratio < 0.0 || $coupon_ratio > 1.0 ) {
142+
$coupon_ratio = max( 0.0, min( 1.0, $coupon_ratio ) );
143+
}
144+
145+
// Apply coupon based on ratio
146+
if ( $coupon_ratio >= 1.0 ) {
147+
$include_coupon = true;
148+
} elseif ( $coupon_ratio > 0 && wp_rand( 1, 100 ) <= ( $coupon_ratio * 100 ) ) {
149+
$include_coupon = true;
150+
} else {
151+
$include_coupon = false;
152+
}
153+
}
154+
155+
129156
// Handle --coupon-ratio parameter
130157
if ( isset( $assoc_args['coupon-ratio'] ) ) {
131158
$coupon_ratio = floatval( $assoc_args['coupon-ratio'] );
@@ -157,13 +184,29 @@ public static function generate( $save = true, $assoc_args = array() ) {
157184
}
158185
}
159186
}
187+
$coupon = self::get_or_create_coupon();
188+
if ( $coupon ) {
189+
$apply_result = $order->apply_coupon( $coupon );
190+
if ( is_wp_error( $apply_result ) ) {
191+
error_log( 'Coupon application failed: ' . $apply_result->get_error_message() . ' (Coupon: ' . $coupon->get_code() . ')' );
192+
} else {
193+
// Recalculate totals after applying coupon
194+
$order->calculate_totals( true );
195+
}
196+
}
197+
}
160198

199+
// Orders created before 2024-01-09 represents orders created before the attribution feature was added.
161200
// Orders created before 2024-01-09 represents orders created before the attribution feature was added.
162201
if ( ! ( strtotime( $date ) < strtotime( '2024-01-09' ) ) ) {
163202
$attribution_result = OrderAttribution::add_order_attribution_meta( $order, $assoc_args );
164203
if ( $attribution_result && is_wp_error( $attribution_result ) ) {
165204
error_log( 'Order attribution meta addition failed: ' . $attribution_result->get_error_message() );
166205
}
206+
$attribution_result = OrderAttribution::add_order_attribution_meta( $order, $assoc_args );
207+
if ( $attribution_result && is_wp_error( $attribution_result ) ) {
208+
error_log( 'Order attribution meta addition failed: ' . $attribution_result->get_error_message() );
209+
}
167210
}
168211

169212
// Set paid and completed dates based on order status.
@@ -185,6 +228,41 @@ public static function generate( $save = true, $assoc_args = array() ) {
185228
return false;
186229
}
187230

231+
// Handle --refund-ratio parameter for completed orders
232+
if ( isset( $assoc_args['refund-ratio'] ) && 'completed' === $status ) {
233+
$refund_ratio = floatval( $assoc_args['refund-ratio'] );
234+
235+
// Validate ratio is between 0.0 and 1.0
236+
if ( $refund_ratio < 0.0 || $refund_ratio > 1.0 ) {
237+
$refund_ratio = max( 0.0, min( 1.0, $refund_ratio ) );
238+
}
239+
240+
$should_refund = false;
241+
242+
if ( $refund_ratio >= 1.0 ) {
243+
// Always refund if ratio is 1.0 or higher
244+
$should_refund = true;
245+
} elseif ( $refund_ratio > 0 && wp_rand( 1, 100 ) <= ( $refund_ratio * 100 ) ) {
246+
// Use random chance for ratios between 0 and 1
247+
$should_refund = true;
248+
}
249+
250+
if ( $should_refund ) {
251+
// Create first refund with date within 2 months of completion
252+
$first_refund = self::create_refund( $order );
253+
254+
// Some partial refunds get a second refund (always partial)
255+
if ( $first_refund && is_object( $first_refund ) && wp_rand( 1, 100 ) <= self::SECOND_REFUND_PROBABILITY ) {
256+
self::create_refund( $order, true, $first_refund );
257+
}
258+
}
259+
}
260+
$save_result = $order->save();
261+
if ( is_wp_error( $save_result ) ) {
262+
error_log( 'Order save failed: ' . $save_result->get_error_message() );
263+
return false;
264+
}
265+
188266
// Handle --refund-ratio parameter for completed orders
189267
if ( isset( $assoc_args['refund-ratio'] ) && 'completed' === $status ) {
190268
$refund_ratio = floatval( $assoc_args['refund-ratio'] );
@@ -239,6 +317,7 @@ public static function generate( $save = true, $assoc_args = array() ) {
239317
public static function batch( $amount, array $args = array() ) {
240318
$amount = self::validate_batch_amount( $amount );
241319
if ( is_wp_error( $amount ) ) {
320+
error_log( 'Batch generation failed: ' . $amount->get_error_message() );
242321
error_log( 'Batch generation failed: ' . $amount->get_error_message() );
243322
return $amount;
244323
}
@@ -290,6 +369,10 @@ public static function get_customer() {
290369
error_log( 'Customer generation failed: Customer::generate() returned invalid result' );
291370
}
292371

372+
if ( ! $customer instanceof \WC_Customer ) {
373+
error_log( 'Customer generation failed: Customer::generate() returned invalid result' );
374+
}
375+
293376
return $customer;
294377
}
295378

@@ -382,6 +465,11 @@ protected static function get_random_products( int $min_amount = 1, int $max_amo
382465
return array();
383466
}
384467

468+
if ( $num_existing_products === 0 ) {
469+
error_log( 'No published products found in database' );
470+
return array();
471+
}
472+
385473
$num_products_to_get = wp_rand( $min_amount, $max_amount );
386474

387475
if ( $num_products_to_get > $num_existing_products ) {
@@ -400,6 +488,13 @@ protected static function get_random_products( int $min_amount = 1, int $max_amo
400488
return array();
401489
}
402490

491+
foreach ( $product_ids as $product_id ) {
492+
$product_ids = $query->get_products();
493+
if ( empty( $product_ids ) ) {
494+
error_log( 'WC_Product_Query returned no product IDs' );
495+
return array();
496+
}
497+
403498
foreach ( $product_ids as $product_id ) {
404499
$product = wc_get_product( $product_id );
405500

@@ -408,6 +503,11 @@ protected static function get_random_products( int $min_amount = 1, int $max_amo
408503
continue;
409504
}
410505

506+
if ( ! $product ) {
507+
error_log( "Failed to retrieve product with ID: {$product_id}" );
508+
continue;
509+
}
510+
411511
if ( $product->is_type( 'variable' ) ) {
412512
$available_variations = $product->get_available_variations();
413513
if ( empty( $available_variations ) ) {
@@ -418,8 +518,13 @@ protected static function get_random_products( int $min_amount = 1, int $max_amo
418518
if ( $variation && $variation->exists() ) {
419519
$products[] = $variation;
420520
}
521+
$variation = new \WC_Product_Variation( $available_variations[ $index ]['variation_id'] );
522+
if ( $variation && $variation->exists() ) {
523+
$products[] = $variation;
524+
}
421525
} else {
422526
$products[] = $product;
527+
$products[] = $product;
423528
}
424529
}
425530

includes/Generator/Product.php

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ protected static function generate_variable_product() {
303303
'sku' => sanitize_title( $name ) . '-' . self::$faker->ean8,
304304
'global_unique_id' => self::$faker->randomElement( [ self::$faker->ean13, self::$faker->isbn10 ] ),
305305
'attributes' => $attributes,
306-
'tax_status' => 'taxable',
306+
'tax_status' => self::$faker->randomElement( [ 'taxable', 'shipping', 'none' ] ),
307307
'tax_class' => '',
308308
'manage_stock' => $will_manage_stock,
309309
'stock_quantity' => $will_manage_stock ? self::$faker->numberBetween( -100, 100 ) : null,
@@ -328,18 +328,21 @@ protected static function generate_variable_product() {
328328
$possible_attributes = array_reverse( wc_array_cartesian( $variation_attributes ) );
329329
foreach ( $possible_attributes as $possible_attribute ) {
330330
$price = self::$faker->randomFloat( 2, 1, 1000 );
331-
$is_on_sale = self::$faker->boolean( 30 );
331+
$is_on_sale = self::$faker->boolean( 35 );
332+
$has_sale_schedule = $is_on_sale && self::$faker->boolean( 40 ); // ~40% of on-sale variations have a schedule.
332333
$sale_price = $is_on_sale ? self::$faker->randomFloat( 2, 0, $price ) : '';
334+
$date_on_sale_from = $has_sale_schedule ? self::$faker->dateTimeBetween( '-3 days', '+3 days' )->format( DATE_ATOM ) : '';
335+
$date_on_sale_to = $has_sale_schedule ? self::$faker->dateTimeBetween( '+4 days', '+4 months' )->format( DATE_ATOM ) : '';
333336
$is_virtual = self::$faker->boolean( 20 );
334337
$variation = new \WC_Product_Variation();
335338
$variation->set_props( array(
336339
'parent_id' => $product->get_id(),
337340
'attributes' => $possible_attribute,
338341
'regular_price' => $price,
339342
'sale_price' => $sale_price,
340-
'date_on_sale_from' => '',
341-
'date_on_sale_to' => self::$faker->iso8601( date( 'c', strtotime( '+1 month' ) ) ),
342-
'tax_status' => 'taxable',
343+
'date_on_sale_from' => $date_on_sale_from,
344+
'date_on_sale_to' => $date_on_sale_to,
345+
'tax_status' => self::$faker->randomElement( [ 'taxable', 'shipping', 'none' ] ),
343346
'tax_class' => '',
344347
'manage_stock' => $will_manage_stock,
345348
'stock_quantity' => $will_manage_stock ? self::$faker->numberBetween( -20, 100 ) : null,
@@ -352,6 +355,12 @@ protected static function generate_variable_product() {
352355
'downloadable' => false,
353356
'image_id' => self::get_image(),
354357
) );
358+
359+
// Set COGS if the feature is enabled.
360+
if ( wc_get_container()->get( 'Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController' )->feature_is_enabled() ) {
361+
$variation->set_props( array( 'cogs_value' => round( $price * ( 1 - self::$faker->numberBetween( 15, 60 ) / 100 ), 2 ) ) );
362+
}
363+
355364
$variation->save();
356365
}
357366
$data_store = $product->get_data_store();
@@ -370,8 +379,11 @@ protected static function generate_simple_product() {
370379
$will_manage_stock = self::$faker->boolean();
371380
$is_virtual = self::$faker->boolean();
372381
$price = self::$faker->randomFloat( 2, 1, 1000 );
373-
$is_on_sale = self::$faker->boolean( 30 );
382+
$is_on_sale = self::$faker->boolean( 35 );
383+
$has_sale_schedule = $is_on_sale && self::$faker->boolean( 40 ); // ~40% scheduled, rest indefinite.
374384
$sale_price = $is_on_sale ? self::$faker->randomFloat( 2, 0, $price ) : '';
385+
$date_on_sale_from = $has_sale_schedule ? self::$faker->dateTimeBetween( '-3 days', '+3 days' )->format( DATE_ATOM ) : '';
386+
$date_on_sale_to = $has_sale_schedule ? self::$faker->dateTimeBetween( '+4 days', '+4 months' )->format( DATE_ATOM ) : '';
375387
$product = new \WC_Product();
376388

377389
$image_id = self::get_image();
@@ -387,10 +399,10 @@ protected static function generate_simple_product() {
387399
'global_unique_id' => self::$faker->randomElement( [ self::$faker->ean13, self::$faker->isbn10 ] ),
388400
'regular_price' => $price,
389401
'sale_price' => $sale_price,
390-
'date_on_sale_from' => '',
391-
'date_on_sale_to' => self::$faker->iso8601( date( 'c', strtotime( '+1 month' ) ) ),
402+
'date_on_sale_from' => $date_on_sale_from,
403+
'date_on_sale_to' => $date_on_sale_to,
392404
'total_sales' => self::$faker->numberBetween( 0, 10000 ),
393-
'tax_status' => 'taxable',
405+
'tax_status' => self::$faker->randomElement( [ 'taxable', 'shipping', 'none' ] ),
394406
'tax_class' => '',
395407
'manage_stock' => $will_manage_stock,
396408
'stock_quantity' => $will_manage_stock ? self::$faker->numberBetween( -100, 100 ) : null,
@@ -416,6 +428,11 @@ protected static function generate_simple_product() {
416428
'gallery_image_ids' => $gallery,
417429
) );
418430

431+
// Set COGS if the feature is enabled.
432+
if ( wc_get_container()->get( 'Automattic\WooCommerce\Internal\CostOfGoodsSold\CostOfGoodsSoldController' )->feature_is_enabled() ) {
433+
$product->set_props( array( 'cogs_value' => round( $price * ( 1 - self::$faker->numberBetween( 15, 60 ) / 100 ), 2 ) ) );
434+
}
435+
419436
return $product;
420437
}
421438

0 commit comments

Comments
 (0)