batch, 'coupons', $index ); $type = (string) $random->pick( array( 'percent', 'fixed_product' ) ); $plan = array( 'code' => self::code( $ctx->batch, $index ), 'type' => $type, 'amount' => 'percent' === $type ? $random->int( 5, 30 ) : $random->int( 2, 20 ), 'usage_limit' => $random->chance( 30 ) ? $random->int( 10, 100 ) : 0, 'expires' => $random->chance( 30 ) ? $ctx->to + DAY_IN_SECONDS * $random->int( 30, 365 ) : 0, ); /** This filter is documented in src/Modules/TestData/Make/Products.php */ $plan = (array) apply_filters( 'apwc_test_data_item', $plan, 'coupon', $index, $ctx->batch ); $code = wc_format_coupon_code( (string) ( $plan['code'] ?? '' ) ); if ( '' === $code ) { $code = wc_format_coupon_code( self::code( $ctx->batch, $index ) ); } $existing = (int) wc_get_coupon_id_by_code( $code ); if ( $existing ) { // A resumed step made it already; a real coupon with this code is never touched. if ( (string) get_post_meta( $existing, Marker::META, true ) !== $ctx->batch ) { return 0; } if ( ! Marker::verified( 'post', $existing, $ctx->batch ) ) { Marker::sign( 'post', $existing, $ctx->batch ); } return $existing; } $coupon = new \WC_Coupon(); $coupon->update_meta_data( Marker::META, $ctx->batch ); $coupon->set_code( $code ); $coupon->set_description( __( 'Test coupon made by Admin Powerups test data.', 'admin-powerups-for-woocommerce' ) ); // Whatever a filter did: never a whole-cart discount. $coupon->set_discount_type( 'fixed_product' === ( $plan['type'] ?? '' ) ? 'fixed_product' : 'percent' ); $coupon->set_amount( max( 0, min( 'percent' === $coupon->get_discount_type() ? 100 : 1000000, (float) ( $plan['amount'] ?? 10 ) ) ) ); $coupon->set_email_restrictions( array( '*@' . $ctx->domain ) ); $coupon->set_individual_use( true ); $products = $ctx->pool( 'products' ); if ( $products ) { $coupon->set_product_ids( $products ); } if ( (int) ( $plan['usage_limit'] ?? 0 ) > 0 ) { $coupon->set_usage_limit( (int) $plan['usage_limit'] ); } if ( (int) ( $plan['expires'] ?? 0 ) > 0 ) { $coupon->set_date_expires( (int) $plan['expires'] ); } try { $id = (int) $coupon->save(); if ( $id && ! $products ) { // No test products: a restriction nothing matches (a coupon ID is never a product). $coupon->set_product_ids( array( $id ) ); $coupon->save(); } } catch ( \Throwable $e ) { // Inserted before the error: sign it, so Clean up can remove it. Products::half_made( (int) $coupon->get_id(), $ctx->batch ); throw $e; } if ( $id ) { Marker::sign( 'post', $id, $ctx->batch ); $ctx->created( 'coupon', $id ); } return $id; } /** * The code of coupon number $index: secret (the site's salt), the same on every call. * * @since 1.0.0 * @param string $batch Batch ID. * @param int $index Index. * @return string */ public static function code( string $batch, int $index ): string { $hash = Marker::hmac( 'coupon|' . $batch . '|' . $index ); $code = 'TEST-'; for ( $i = 0; $i < 10; $i++ ) { $code .= self::ALPHABET[ hexdec( substr( $hash, $i * 2, 2 ) ) % strlen( self::ALPHABET ) ]; } return $code; } }