diff --git a/csharp/coupon/GenerateCouponCodesBatch.cs b/csharp/coupon/GenerateCouponCodesBatch.cs
new file mode 100644
index 0000000..909dbca
--- /dev/null
+++ b/csharp/coupon/GenerateCouponCodesBatch.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using com.ultracart.admin.v2.Api;
+using com.ultracart.admin.v2.Model;
+
+namespace SdkSample.coupon
+{
+ ///
+ /// Batch Coupon Code Generator
+ /// Generates large batches of coupon codes by calling the API repeatedly
+ ///
+ /// Usage: bin/Debug/SdkSample.exe GenerateCouponCodesBatch [total_codes] [output_file]
+ /// Example: bin/Debug/SdkSample.exe GenerateCouponCodesBatch 10OFF 10000 codes.csv
+ ///
+ public class GenerateCouponCodesBatch
+ {
+ private const int BATCH_SIZE = 1000;
+
+ public static void Execute(string[] args)
+ {
+ // Parse command line arguments
+ if (args.Length < 1)
+ {
+ Console.Error.WriteLine("Error: Merchant code is required");
+ Console.Error.WriteLine("Usage: bin/Debug/SdkSample.exe GenerateCouponCodesBatch [total_codes] [output_file]");
+ Console.Error.WriteLine("Example: bin/Debug/SdkSample.exe GenerateCouponCodesBatch 10OFF 10000 codes.csv");
+ Environment.Exit(1);
+ }
+
+ string merchantCode = args[0];
+ int totalCodes = args.Length > 1 ? int.Parse(args[1]) : 10000;
+ string outputFile = args.Length > 2 ? args[2] :
+ $"coupon_codes_{merchantCode}_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}.csv";
+
+ // Validate inputs
+ if (totalCodes < 1 || totalCodes > 100000)
+ {
+ Console.Error.WriteLine($"Error: total_codes must be between 1 and 100,000 (got {totalCodes})");
+ Environment.Exit(1);
+ }
+
+ // Display header
+ Console.WriteLine("Batch Coupon Code Generator");
+ Console.WriteLine("=============================");
+ Console.WriteLine($"Merchant Code: {merchantCode}");
+ Console.WriteLine($"Total Codes: {totalCodes}");
+ Console.WriteLine($"Output File: {outputFile}");
+ Console.WriteLine();
+
+ try
+ {
+ // Initialize API client
+ CouponApi couponApi = new CouponApi(Constants.ApiKey);
+
+ // Look up coupon by merchant code
+ Console.WriteLine("Looking up coupon by merchant code...");
+ CouponResponse couponResponse = couponApi.GetCouponByMerchantCode(merchantCode);
+ int? couponOid = couponResponse.Coupon.CouponOid;
+ Console.WriteLine($"Found coupon OID: {couponOid}");
+ Console.WriteLine();
+
+ // Calculate batching
+ int numBatches = (int)Math.Ceiling((double)totalCodes / BATCH_SIZE);
+ List allCodes = new List();
+
+ Console.WriteLine($"Generating codes in batches of {BATCH_SIZE}...");
+ DateTime startTime = DateTime.Now;
+
+ // Generate codes in batches
+ for (int batchNum = 1; batchNum <= numBatches; batchNum++)
+ {
+ // Calculate batch size
+ int batchSize = (batchNum == numBatches)
+ ? totalCodes - (batchNum - 1) * BATCH_SIZE
+ : BATCH_SIZE;
+
+ // Create request
+ CouponCodesRequest codesRequest = new CouponCodesRequest();
+ codesRequest.Quantity = batchSize;
+ codesRequest.ExpirationDts = DateTime.UtcNow.AddDays(365).ToString("yyyy-MM-ddTHH:mm:ssK");
+
+ // Call API with retry logic
+ int retryCount = 0;
+ bool success = false;
+
+ while (retryCount < 2 && !success)
+ {
+ try
+ {
+ CouponCodesResponse batchResponse = couponApi.GenerateCouponCodes(couponOid, codesRequest);
+ List batchCodes = batchResponse.CouponCodes;
+ allCodes.AddRange(batchCodes);
+ success = true;
+
+ // Display progress
+ double elapsed = (DateTime.Now - startTime).TotalSeconds;
+ Console.WriteLine($"[{batchNum}/{numBatches}] Generated {batchSize} codes (Total: {allCodes.Count}) - Elapsed: {elapsed:F1}s");
+ }
+ catch (Exception e)
+ {
+ retryCount++;
+ if (retryCount < 2)
+ {
+ Console.WriteLine($"Warning: Batch {batchNum} failed, retrying...");
+ Thread.Sleep(2000); // exponential backoff
+ }
+ else
+ {
+ Console.Error.WriteLine($"Error: Failed to generate batch {batchNum} after retries");
+ Console.Error.WriteLine($"Details: {e.Message}");
+ Environment.Exit(1);
+ }
+ }
+ }
+
+ // Rate limiting - sleep between batches (except last)
+ if (batchNum < numBatches)
+ {
+ Thread.Sleep(750);
+ }
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Writing codes to CSV file...");
+
+ // Write to CSV
+ try
+ {
+ using (StreamWriter writer = new StreamWriter(outputFile))
+ {
+ // Write header
+ writer.WriteLine("code,generated_at,batch_number");
+
+ // Write codes
+ int batchNum = 1;
+ int codesInBatch = 0;
+ string timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssK");
+
+ foreach (string code in allCodes)
+ {
+ writer.WriteLine($"{code},{timestamp},{batchNum}");
+
+ codesInBatch++;
+ if (codesInBatch >= BATCH_SIZE)
+ {
+ batchNum++;
+ codesInBatch = 0;
+ }
+ }
+ }
+
+ Console.WriteLine($"Successfully saved {allCodes.Count} codes to: {outputFile}");
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine($"Error writing to file: {e.Message}");
+ Environment.Exit(1);
+ }
+
+ // Display summary
+ double totalTime = (DateTime.Now - startTime).TotalSeconds;
+ double avgTime = totalTime / numBatches;
+
+ Console.WriteLine();
+ Console.WriteLine("Summary:");
+ Console.WriteLine($"- Merchant Code: {merchantCode}");
+ Console.WriteLine($"- Coupon OID: {couponOid}");
+ Console.WriteLine($"- Total Codes Generated: {allCodes.Count}");
+ Console.WriteLine($"- Batches Processed: {numBatches}");
+ Console.WriteLine($"- Total Time: {totalTime:F1}s");
+ Console.WriteLine($"- Average per batch: {avgTime:F1}s");
+ Console.WriteLine($"- Output File: {Path.GetFullPath(outputFile)}");
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine($"Error: Coupon with merchant code '{merchantCode}' not found");
+ Console.Error.WriteLine($"Details: {ex.Message}");
+ Environment.Exit(1);
+ }
+ }
+ }
+}
diff --git a/java/src/coupon/GenerateCouponCodesBatch.java b/java/src/coupon/GenerateCouponCodesBatch.java
new file mode 100644
index 0000000..55fc575
--- /dev/null
+++ b/java/src/coupon/GenerateCouponCodesBatch.java
@@ -0,0 +1,176 @@
+package coupon;
+
+import com.ultracart.admin.v2.CouponApi;
+import com.ultracart.admin.v2.models.*;
+import com.ultracart.admin.v2.util.ApiException;
+import common.Constants;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Batch Coupon Code Generator
+ * Generates large batches of coupon codes by calling the API repeatedly
+ *
+ * Usage: java -cp target/sdk_samples-1.0-SNAPSHOT.jar coupon.GenerateCouponCodesBatch [total_codes] [output_file]
+ * Example: java -cp target/sdk_samples-1.0-SNAPSHOT.jar coupon.GenerateCouponCodesBatch 10OFF 10000 codes.csv
+ */
+public class GenerateCouponCodesBatch {
+ private static final int BATCH_SIZE = 1000;
+
+ public static void execute(String[] args) {
+ // Parse command line arguments
+ if (args.length < 1) {
+ System.err.println("Error: Merchant code is required");
+ System.err.println("Usage: java -cp target/sdk_samples-1.0-SNAPSHOT.jar coupon.GenerateCouponCodesBatch [total_codes] [output_file]");
+ System.err.println("Example: java -cp target/sdk_samples-1.0-SNAPSHOT.jar coupon.GenerateCouponCodesBatch 10OFF 10000 codes.csv");
+ System.exit(1);
+ }
+
+ String merchantCode = args[0];
+ int totalCodes = args.length > 1 ? Integer.parseInt(args[1]) : 10000;
+ String outputFile = args.length > 2 ? args[2] :
+ "coupon_codes_" + merchantCode + "_" + System.currentTimeMillis() + ".csv";
+
+ // Validate inputs
+ if (totalCodes < 1 || totalCodes > 100000) {
+ System.err.println("Error: total_codes must be between 1 and 100,000 (got " + totalCodes + ")");
+ System.exit(1);
+ }
+
+ // Display header
+ System.out.println("Batch Coupon Code Generator");
+ System.out.println("=============================");
+ System.out.println("Merchant Code: " + merchantCode);
+ System.out.println("Total Codes: " + totalCodes);
+ System.out.println("Output File: " + outputFile);
+ System.out.println();
+
+ try {
+ // Initialize API client
+ CouponApi couponApi = new CouponApi(Constants.API_KEY);
+
+ // Look up coupon by merchant code
+ System.out.println("Looking up coupon by merchant code...");
+ CouponResponse couponResponse = couponApi.getCouponByMerchantCode(merchantCode, null);
+ Integer couponOid = couponResponse.getCoupon().getCouponOid();
+ System.out.println("Found coupon OID: " + couponOid);
+ System.out.println();
+
+ // Calculate batching
+ int numBatches = (int) Math.ceil((double) totalCodes / BATCH_SIZE);
+ List allCodes = new ArrayList<>();
+
+ System.out.println("Generating codes in batches of " + BATCH_SIZE + "...");
+ long startTime = System.currentTimeMillis();
+
+ // Generate codes in batches
+ for (int batchNum = 1; batchNum <= numBatches; batchNum++) {
+ // Calculate batch size
+ int batchSize = (batchNum == numBatches)
+ ? totalCodes - (batchNum - 1) * BATCH_SIZE
+ : BATCH_SIZE;
+
+ // Create request
+ CouponCodesRequest codesRequest = new CouponCodesRequest();
+ codesRequest.setQuantity(batchSize);
+ codesRequest.setExpirationDts(Instant.now().plus(365, ChronoUnit.DAYS).toString());
+
+ // Call API with retry logic
+ int retryCount = 0;
+ boolean success = false;
+
+ while (retryCount < 2 && !success) {
+ try {
+ CouponCodesResponse batchResponse = couponApi.generateCouponCodes(couponOid, codesRequest);
+ List batchCodes = batchResponse.getCouponCodes();
+ allCodes.addAll(batchCodes);
+ success = true;
+
+ // Display progress
+ double elapsed = (System.currentTimeMillis() - startTime) / 1000.0;
+ System.out.printf("[%d/%d] Generated %d codes (Total: %d) - Elapsed: %.1fs%n",
+ batchNum, numBatches, batchSize, allCodes.size(), elapsed);
+ } catch (ApiException e) {
+ retryCount++;
+ if (retryCount < 2) {
+ System.out.println("Warning: Batch " + batchNum + " failed, retrying...");
+ Thread.sleep(2000); // exponential backoff
+ } else {
+ System.err.println("Error: Failed to generate batch " + batchNum + " after retries");
+ System.err.println("Details: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+ }
+
+ // Rate limiting - sleep between batches (except last)
+ if (batchNum < numBatches) {
+ Thread.sleep(750);
+ }
+ }
+
+ System.out.println();
+ System.out.println("Writing codes to CSV file...");
+
+ // Write to CSV
+ try (FileWriter writer = new FileWriter(outputFile)) {
+ // Write header
+ writer.write("code,generated_at,batch_number\n");
+
+ // Write codes
+ int batchNum = 1;
+ int codesInBatch = 0;
+ String timestamp = Instant.now().toString();
+
+ for (String code : allCodes) {
+ writer.write(code + "," + timestamp + "," + batchNum + "\n");
+
+ codesInBatch++;
+ if (codesInBatch >= BATCH_SIZE) {
+ batchNum++;
+ codesInBatch = 0;
+ }
+ }
+
+ System.out.println("Successfully saved " + allCodes.size() + " codes to: " + outputFile);
+ } catch (IOException e) {
+ System.err.println("Error writing to file: " + e.getMessage());
+ System.exit(1);
+ }
+
+ // Display summary
+ double totalTime = (System.currentTimeMillis() - startTime) / 1000.0;
+ double avgTime = totalTime / numBatches;
+
+ System.out.println();
+ System.out.println("Summary:");
+ System.out.println("- Merchant Code: " + merchantCode);
+ System.out.println("- Coupon OID: " + couponOid);
+ System.out.println("- Total Codes Generated: " + allCodes.size());
+ System.out.println("- Batches Processed: " + numBatches);
+ System.out.printf("- Total Time: %.1fs%n", totalTime);
+ System.out.printf("- Average per batch: %.1fs%n", avgTime);
+ System.out.println("- Output File: " + Paths.get(outputFile).toAbsolutePath());
+
+ } catch (ApiException e) {
+ System.err.println("Error: Coupon with merchant code '" + merchantCode + "' not found");
+ System.err.println("Details: " + e.getMessage());
+ System.err.println("Status code: " + e.getCode());
+ System.exit(1);
+ } catch (InterruptedException e) {
+ System.err.println("Error: Thread interrupted");
+ System.err.println("Details: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ public static void main(String[] args) {
+ execute(args);
+ }
+}
diff --git a/javascript/coupon/generateCouponCodesBatch.js b/javascript/coupon/generateCouponCodesBatch.js
new file mode 100644
index 0000000..667cb5b
--- /dev/null
+++ b/javascript/coupon/generateCouponCodesBatch.js
@@ -0,0 +1,175 @@
+import { couponApi } from '../api.js';
+import { DateTime } from 'luxon';
+import * as fs from 'fs';
+
+/**
+ * Batch Coupon Code Generator
+ * Generates large batches of coupon codes by calling the API repeatedly
+ *
+ * Usage: NODE_TLS_REJECT_UNAUTHORIZED=0 node coupon/generateCouponCodesBatch.js [total_codes] [output_file]
+ * Example: NODE_TLS_REJECT_UNAUTHORIZED=0 node coupon/generateCouponCodesBatch.js 10OFF 10000 codes.csv
+ */
+
+export class GenerateCouponCodesBatch {
+ static async execute() {
+ // Parse command line arguments
+ const merchantCode = process.argv[2];
+ const totalCodes = parseInt(process.argv[3] || '10000');
+ const outputFile = process.argv[4] || `coupon_codes_${merchantCode}_${Date.now()}.csv`;
+
+ // Validate inputs
+ if (!merchantCode) {
+ console.error('Error: Merchant code is required');
+ console.error('Usage: node coupon/generateCouponCodesBatch.js [total_codes] [output_file]');
+ console.error('Example: node coupon/generateCouponCodesBatch.js 10OFF 10000 codes.csv');
+ process.exit(1);
+ }
+
+ if (totalCodes < 1 || totalCodes > 100000) {
+ console.error(`Error: total_codes must be between 1 and 100,000 (got ${totalCodes})`);
+ process.exit(1);
+ }
+
+ // Display header
+ console.log('Batch Coupon Code Generator');
+ console.log('=============================');
+ console.log(`Merchant Code: ${merchantCode}`);
+ console.log(`Total Codes: ${totalCodes}`);
+ console.log(`Output File: ${outputFile}`);
+ console.log('');
+
+ try {
+ // Look up coupon by merchant code
+ console.log('Looking up coupon by merchant code...');
+ const couponResponse = await new Promise((resolve, reject) => {
+ couponApi.getCouponByMerchantCode(merchantCode, function (error, data, response) {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(data);
+ }
+ });
+ });
+
+ const couponOid = couponResponse.coupon.coupon_oid;
+ console.log(`Found coupon OID: ${couponOid}`);
+ console.log('');
+
+ // Calculate batching
+ const BATCH_SIZE = 1000;
+ const numBatches = Math.ceil(totalCodes / BATCH_SIZE);
+ const allCodes = [];
+
+ console.log(`Generating codes in batches of ${BATCH_SIZE}...`);
+ const startTime = Date.now();
+
+ // Generate codes in batches
+ for (let batchNum = 1; batchNum <= numBatches; batchNum++) {
+ // Calculate batch size
+ const batchSize = (batchNum === numBatches)
+ ? totalCodes - (batchNum - 1) * BATCH_SIZE
+ : BATCH_SIZE;
+
+ // Create request
+ const codesRequest = {
+ quantity: batchSize,
+ expiration_dts: DateTime.utc().plus({ days: 365 }).toISO()
+ };
+
+ // Call API with retry logic
+ let retryCount = 0;
+ let success = false;
+
+ while (retryCount < 2 && !success) {
+ try {
+ const batchResponse = await new Promise((resolve, reject) => {
+ couponApi.generateCouponCodes(couponOid, codesRequest, function (error, data, response) {
+ if (error) {
+ reject(error);
+ } else {
+ resolve(data);
+ }
+ });
+ });
+
+ const batchCodes = batchResponse.coupon_codes;
+ allCodes.push(...batchCodes);
+ success = true;
+
+ // Display progress
+ const elapsed = (Date.now() - startTime) / 1000;
+ console.log(`[${batchNum}/${numBatches}] Generated ${batchSize} codes (Total: ${allCodes.length}) - Elapsed: ${elapsed.toFixed(1)}s`);
+ } catch (error) {
+ retryCount++;
+ if (retryCount < 2) {
+ console.log(`Warning: Batch ${batchNum} failed, retrying...`);
+ await new Promise(resolve => setTimeout(resolve, 2000)); // exponential backoff
+ } else {
+ console.error(`Error: Failed to generate batch ${batchNum} after retries`);
+ console.error(`Details: ${error.message}`);
+ process.exit(1);
+ }
+ }
+ }
+
+ // Rate limiting - sleep between batches (except last)
+ if (batchNum < numBatches) {
+ await new Promise(resolve => setTimeout(resolve, 750));
+ }
+ }
+
+ console.log('');
+ console.log('Writing codes to CSV file...');
+
+ // Write to CSV
+ try {
+ let csvContent = 'code,generated_at,batch_number\n';
+
+ let batchNum = 1;
+ let codesInBatch = 0;
+ const timestamp = new Date().toISOString();
+
+ for (const code of allCodes) {
+ csvContent += `${code},${timestamp},${batchNum}\n`;
+
+ codesInBatch++;
+ if (codesInBatch >= BATCH_SIZE) {
+ batchNum++;
+ codesInBatch = 0;
+ }
+ }
+
+ fs.writeFileSync(outputFile, csvContent, 'utf8');
+ console.log(`Successfully saved ${allCodes.length} codes to: ${outputFile}`);
+ } catch (error) {
+ console.error(`Error writing to file: ${error.message}`);
+ process.exit(1);
+ }
+
+ // Display summary
+ const totalTime = (Date.now() - startTime) / 1000;
+ const avgTime = totalTime / numBatches;
+
+ console.log('');
+ console.log('Summary:');
+ console.log(`- Merchant Code: ${merchantCode}`);
+ console.log(`- Coupon OID: ${couponOid}`);
+ console.log(`- Total Codes Generated: ${allCodes.length}`);
+ console.log(`- Batches Processed: ${numBatches}`);
+ console.log(`- Total Time: ${totalTime.toFixed(1)}s`);
+ console.log(`- Average per batch: ${avgTime.toFixed(1)}s`);
+ console.log(`- Output File: ${fs.realpathSync(outputFile)}`);
+
+ } catch (error) {
+ if (error.message && error.message.includes('not found')) {
+ console.error(`Error: Coupon with merchant code '${merchantCode}' not found`);
+ } else {
+ console.error(`Error: ${error.message}`);
+ }
+ if (error.status) {
+ console.error(`Status: ${error.status}`);
+ }
+ process.exit(1);
+ }
+ }
+}
diff --git a/php/coupon/generateCouponCodesBatch.php b/php/coupon/generateCouponCodesBatch.php
new file mode 100644
index 0000000..19f3c32
--- /dev/null
+++ b/php/coupon/generateCouponCodesBatch.php
@@ -0,0 +1,161 @@
+ [total_codes] [output_file]
+ * Example: php coupon/generateCouponCodesBatch.php 10OFF 10000 codes.csv
+ */
+
+use ultracart\v2\api\CouponApi;
+use ultracart\v2\models\CouponCodesRequest;
+
+require_once '../vendor/autoload.php';
+require_once '../constants.php';
+
+// Parse command line arguments
+$merchant_code = $argv[1] ?? null;
+$total_codes = isset($argv[2]) ? intval($argv[2]) : 10000;
+$output_file = $argv[3] ?? "coupon_codes_{$merchant_code}_" . time() . ".csv";
+
+// Validate inputs
+if (!$merchant_code) {
+ fwrite(STDERR, "Error: Merchant code is required\n");
+ fwrite(STDERR, "Usage: php coupon/generateCouponCodesBatch.php [total_codes] [output_file]\n");
+ fwrite(STDERR, "Example: php coupon/generateCouponCodesBatch.php 10OFF 10000 codes.csv\n");
+ exit(1);
+}
+
+if ($total_codes < 1 || $total_codes > 100000) {
+ fwrite(STDERR, "Error: total_codes must be between 1 and 100,000 (got {$total_codes})\n");
+ exit(1);
+}
+
+// Display header
+echo "Batch Coupon Code Generator\n";
+echo "=============================\n";
+echo "Merchant Code: {$merchant_code}\n";
+echo "Total Codes: {$total_codes}\n";
+echo "Output File: {$output_file}\n";
+echo "\n";
+
+// Initialize API client
+$coupon_api = CouponApi::usingApiKey(Constants::API_KEY);
+
+// Look up coupon by merchant code
+echo "Looking up coupon by merchant code...\n";
+try {
+ $coupon_response = $coupon_api->getCouponByMerchantCode($merchant_code);
+ $coupon_oid = $coupon_response->getCoupon()->getCouponOid();
+ echo "Found coupon OID: {$coupon_oid}\n";
+ echo "\n";
+} catch (Exception $e) {
+ fwrite(STDERR, "Error: Coupon with merchant code '{$merchant_code}' not found\n");
+ fwrite(STDERR, "Details: " . $e->getMessage() . "\n");
+ exit(1);
+}
+
+// Calculate batching
+const BATCH_SIZE = 1000;
+$num_batches = intval(ceil($total_codes / BATCH_SIZE));
+$all_codes = [];
+
+echo "Generating codes in batches of " . BATCH_SIZE . "...\n";
+$start_time = microtime(true);
+
+// Generate codes in batches
+for ($batch_num = 1; $batch_num <= $num_batches; $batch_num++) {
+ // Calculate batch size
+ if ($batch_num == $num_batches) {
+ $batch_size = $total_codes - ($batch_num - 1) * BATCH_SIZE;
+ } else {
+ $batch_size = BATCH_SIZE;
+ }
+
+ // Create request
+ $codes_request = new CouponCodesRequest();
+ $codes_request->setQuantity($batch_size);
+ $codes_request->setExpirationDts(date('Y-m-d', strtotime('+365 days')) . "T00:00:00+00:00");
+
+ // Call API with retry logic
+ $retry_count = 0;
+ $success = false;
+
+ while ($retry_count < 2 && !$success) {
+ try {
+ $batch_response = $coupon_api->generateCouponCodes($coupon_oid, $codes_request);
+ $batch_codes = $batch_response->getCouponCodes();
+ $all_codes = array_merge($all_codes, $batch_codes);
+ $success = true;
+
+ // Display progress
+ $elapsed = microtime(true) - $start_time;
+ echo "[{$batch_num}/{$num_batches}] Generated {$batch_size} codes (Total: " . count($all_codes) . ") - Elapsed: " . number_format($elapsed, 1) . "s\n";
+ } catch (Exception $e) {
+ $retry_count++;
+ if ($retry_count < 2) {
+ echo "Warning: Batch {$batch_num} failed, retrying...\n";
+ sleep(2); // exponential backoff
+ } else {
+ fwrite(STDERR, "Error: Failed to generate batch {$batch_num} after retries\n");
+ fwrite(STDERR, "Details: " . $e->getMessage() . "\n");
+ exit(1);
+ }
+ }
+ }
+
+ // Rate limiting - sleep between batches (except last)
+ if ($batch_num < $num_batches) {
+ usleep(750000); // 750ms in microseconds
+ }
+}
+
+echo "\n";
+echo "Writing codes to CSV file...\n";
+
+// Write to CSV
+try {
+ $file_handle = fopen($output_file, 'w');
+ if ($file_handle === false) {
+ throw new Exception("Could not open file for writing");
+ }
+
+ // Write header
+ fputcsv($file_handle, ['code', 'generated_at', 'batch_number']);
+
+ // Write codes
+ $batch_num = 1;
+ $codes_in_batch = 0;
+ $timestamp = gmdate('Y-m-d\TH:i:s\Z');
+
+ foreach ($all_codes as $code) {
+ fputcsv($file_handle, [$code, $timestamp, $batch_num]);
+
+ $codes_in_batch++;
+ if ($codes_in_batch >= BATCH_SIZE) {
+ $batch_num++;
+ $codes_in_batch = 0;
+ }
+ }
+
+ fclose($file_handle);
+ echo "Successfully saved " . count($all_codes) . " codes to: {$output_file}\n";
+} catch (Exception $e) {
+ fwrite(STDERR, "Error writing to file: " . $e->getMessage() . "\n");
+ exit(1);
+}
+
+// Display summary
+$total_time = microtime(true) - $start_time;
+$avg_time = $total_time / $num_batches;
+
+echo "\n";
+echo "Summary:\n";
+echo "- Merchant Code: {$merchant_code}\n";
+echo "- Coupon OID: {$coupon_oid}\n";
+echo "- Total Codes Generated: " . count($all_codes) . "\n";
+echo "- Batches Processed: {$num_batches}\n";
+echo "- Total Time: " . number_format($total_time, 1) . "s\n";
+echo "- Average per batch: " . number_format($avg_time, 1) . "s\n";
+echo "- Output File: " . realpath($output_file) . "\n";
diff --git a/python/coupon/generate_coupon_codes_batch.py b/python/coupon/generate_coupon_codes_batch.py
new file mode 100644
index 0000000..209158d
--- /dev/null
+++ b/python/coupon/generate_coupon_codes_batch.py
@@ -0,0 +1,149 @@
+from ultracart.apis import CouponApi
+from ultracart.models import CouponCodesRequest
+import ultracart.rest
+from samples import api_client
+from datetime import datetime, timedelta
+import sys
+import csv
+import time
+import os
+import math
+
+# Batch Coupon Code Generator
+# Generates large batches of coupon codes by calling the API repeatedly
+# Usage: PYTHONPATH=. python coupon/generate_coupon_codes_batch.py [total_codes] [output_file]
+# Example: PYTHONPATH=. python coupon/generate_coupon_codes_batch.py 10OFF 10000 codes.csv
+
+# Parse command line arguments
+merchant_code = sys.argv[1] if len(sys.argv) > 1 else None
+total_codes = int(sys.argv[2]) if len(sys.argv) > 2 else 10000
+output_file = sys.argv[3] if len(sys.argv) > 3 else f"coupon_codes_{merchant_code}_{int(time.time())}.csv"
+
+# Validate inputs
+if not merchant_code:
+ print('Error: Merchant code is required')
+ print('Usage: PYTHONPATH=. python coupon/generate_coupon_codes_batch.py [total_codes] [output_file]')
+ print('Example: PYTHONPATH=. python coupon/generate_coupon_codes_batch.py 10OFF 10000 codes.csv')
+ sys.exit(1)
+
+if total_codes < 1 or total_codes > 100000:
+ print(f'Error: total_codes must be between 1 and 100,000 (got {total_codes})')
+ sys.exit(1)
+
+# Display header
+print('Batch Coupon Code Generator')
+print('=============================')
+print(f'Merchant Code: {merchant_code}')
+print(f'Total Codes: {total_codes}')
+print(f'Output File: {output_file}')
+print('')
+
+# Initialize API client
+coupon_api = CouponApi(api_client())
+
+# Look up coupon by merchant code
+print('Looking up coupon by merchant code...')
+try:
+ coupon_response = coupon_api.get_coupon_by_merchant_code(merchant_code)
+ coupon_oid = coupon_response.coupon.coupon_oid
+ print(f'Found coupon OID: {coupon_oid}')
+ print('')
+except ultracart.rest.ApiException as e:
+ print(f"Error: Coupon with merchant code '{merchant_code}' not found")
+ print(f'Details: {e}')
+ if hasattr(e, 'status'):
+ print(f'Status: {e.status}')
+ sys.exit(1)
+
+# Calculate batching
+BATCH_SIZE = 1000
+num_batches = math.ceil(total_codes / BATCH_SIZE)
+all_codes = []
+
+print(f'Generating codes in batches of {BATCH_SIZE}...')
+start_time = time.time()
+
+# Generate codes in batches
+for batch_num in range(1, num_batches + 1):
+ # Calculate batch size
+ if batch_num == num_batches:
+ batch_size = total_codes - (batch_num - 1) * BATCH_SIZE
+ else:
+ batch_size = BATCH_SIZE
+
+ # Create request
+ codes_request = CouponCodesRequest()
+ codes_request.quantity = batch_size
+ expiration_date = (datetime.now() + timedelta(days=365)).strftime('%Y-%m-%dT%H:%M:%S+00:00')
+ codes_request.expiration_dts = expiration_date
+
+ # Call API with retry logic
+ retry_count = 0
+ success = False
+
+ while retry_count < 2 and not success:
+ try:
+ batch_response = coupon_api.generate_coupon_codes(coupon_oid, codes_request)
+ batch_codes = batch_response.coupon_codes
+ all_codes.extend(batch_codes)
+ success = True
+
+ # Display progress
+ elapsed = time.time() - start_time
+ print(f'[{batch_num}/{num_batches}] Generated {batch_size} codes (Total: {len(all_codes)}) - Elapsed: {elapsed:.1f}s')
+ except ultracart.rest.ApiException as e:
+ retry_count += 1
+ if retry_count < 2:
+ print(f'Warning: Batch {batch_num} failed, retrying...')
+ time.sleep(2) # exponential backoff
+ else:
+ print(f'Error: Failed to generate batch {batch_num} after retries')
+ print(f'Details: {e}')
+ sys.exit(1)
+
+ # Rate limiting - sleep between batches (except last)
+ if batch_num < num_batches:
+ time.sleep(0.75)
+
+print('')
+print('Writing codes to CSV file...')
+
+# Write to CSV
+try:
+ with open(output_file, 'w', newline='') as csvfile:
+ csv_writer = csv.writer(csvfile)
+
+ # Write header
+ csv_writer.writerow(['code', 'generated_at', 'batch_number'])
+
+ # Write codes
+ batch_num = 1
+ codes_in_batch = 0
+ timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
+
+ for code in all_codes:
+ csv_writer.writerow([code, timestamp, batch_num])
+
+ codes_in_batch += 1
+ if codes_in_batch >= BATCH_SIZE:
+ batch_num += 1
+ codes_in_batch = 0
+
+ print(f'Successfully saved {len(all_codes)} codes to: {output_file}')
+except Exception as e:
+ print(f'Error writing to file: {e}')
+ sys.exit(1)
+
+# Display summary
+total_time = time.time() - start_time
+avg_time = total_time / num_batches
+
+print('')
+print('Summary:')
+print(f'- Merchant Code: {merchant_code}')
+print(f'- Coupon OID: {coupon_oid}')
+print(f'- Total Codes Generated: {len(all_codes)}')
+print(f'- Batches Processed: {num_batches}')
+print(f'- Total Time: {total_time:.1f}s')
+print(f'- Average per batch: {avg_time:.1f}s')
+print(f'- Output File: {os.path.abspath(output_file)}')
diff --git a/ruby/coupon/generate_coupon_codes_batch.rb b/ruby/coupon/generate_coupon_codes_batch.rb
new file mode 100644
index 0000000..5288d39
--- /dev/null
+++ b/ruby/coupon/generate_coupon_codes_batch.rb
@@ -0,0 +1,150 @@
+require_relative '../constants'
+require 'ultracart_api'
+require 'csv'
+require 'date'
+
+# Batch Coupon Code Generator
+# Generates large batches of coupon codes by calling the API repeatedly
+# Usage: ruby generate_coupon_codes_batch.rb [total_codes] [output_file]
+# Example: ruby generate_coupon_codes_batch.rb 10OFF 10000 codes.csv
+
+# Parse command line arguments
+merchant_code = ARGV[0]
+total_codes = (ARGV[1] || '10000').to_i
+output_file = ARGV[2] || "coupon_codes_#{merchant_code}_#{Time.now.to_i}.csv"
+
+# Validate inputs
+if merchant_code.nil? || merchant_code.empty?
+ puts 'Error: Merchant code is required'
+ puts 'Usage: ruby generate_coupon_codes_batch.rb [total_codes] [output_file]'
+ puts 'Example: ruby generate_coupon_codes_batch.rb 10OFF 10000 codes.csv'
+ exit 1
+end
+
+if total_codes < 1 || total_codes > 100000
+ puts "Error: total_codes must be between 1 and 100,000 (got #{total_codes})"
+ exit 1
+end
+
+# Display header
+puts 'Batch Coupon Code Generator'
+puts '============================='
+puts "Merchant Code: #{merchant_code}"
+puts "Total Codes: #{total_codes}"
+puts "Output File: #{output_file}"
+puts ''
+
+# Initialize API client
+coupon_api = UltracartClient::CouponApi.new_using_api_key(Constants::API_KEY)
+
+# Look up coupon by merchant code
+puts 'Looking up coupon by merchant code...'
+begin
+ coupon_response = coupon_api.get_coupon_by_merchant_code(merchant_code)
+ coupon_oid = coupon_response.coupon.coupon_oid
+ puts "Found coupon OID: #{coupon_oid}"
+ puts ''
+rescue UltracartClient::ApiError => e
+ puts "Error: Coupon with merchant code '#{merchant_code}' not found"
+ puts "Details: #{e.message}"
+ puts "Status code: #{e.code}" if e.respond_to?(:code)
+ exit 1
+end
+
+# Calculate batching
+BATCH_SIZE = 1000
+num_batches = (total_codes.to_f / BATCH_SIZE).ceil
+all_codes = []
+
+puts "Generating codes in batches of #{BATCH_SIZE}..."
+start_time = Time.now
+
+# Generate codes in batches
+(1..num_batches).each do |batch_num|
+ # Calculate batch size
+ batch_size = if batch_num == num_batches
+ total_codes - (batch_num - 1) * BATCH_SIZE
+ else
+ BATCH_SIZE
+ end
+
+ # Create request
+ codes_request = UltracartClient::CouponCodesRequest.new
+ codes_request.quantity = batch_size
+ codes_request.expiration_dts = (Date.today + 365).strftime('%Y-%m-%d') + 'T00:00:00+00:00'
+
+ # Call API with retry logic
+ retry_count = 0
+ success = false
+
+ while retry_count < 2 && !success
+ begin
+ batch_response = coupon_api.generate_coupon_codes(coupon_oid, codes_request)
+ batch_codes = batch_response.coupon_codes
+ all_codes.concat(batch_codes)
+ success = true
+
+ # Display progress
+ elapsed = Time.now - start_time
+ puts "[#{batch_num}/#{num_batches}] Generated #{batch_size} codes (Total: #{all_codes.length}) - Elapsed: #{elapsed.round(1)}s"
+ rescue UltracartClient::ApiError => e
+ retry_count += 1
+ if retry_count < 2
+ puts "Warning: Batch #{batch_num} failed, retrying..."
+ sleep(2) # exponential backoff
+ else
+ puts "Error: Failed to generate batch #{batch_num} after retries"
+ puts "Details: #{e.message}"
+ exit 1
+ end
+ end
+ end
+
+ # Rate limiting - sleep between batches (except last)
+ sleep(0.75) if batch_num < num_batches
+end
+
+puts ''
+puts 'Writing codes to CSV file...'
+
+# Write to CSV
+begin
+ CSV.open(output_file, 'w') do |csv|
+ # Write header
+ csv << ['code', 'generated_at', 'batch_number']
+
+ # Write codes
+ batch_num = 1
+ codes_in_batch = 0
+ timestamp = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
+
+ all_codes.each do |code|
+ csv << [code, timestamp, batch_num]
+
+ codes_in_batch += 1
+ if codes_in_batch >= BATCH_SIZE
+ batch_num += 1
+ codes_in_batch = 0
+ end
+ end
+ end
+
+ puts "Successfully saved #{all_codes.length} codes to: #{output_file}"
+rescue StandardError => e
+ puts "Error writing to file: #{e.message}"
+ exit 1
+end
+
+# Display summary
+total_time = Time.now - start_time
+avg_time = total_time / num_batches
+
+puts ''
+puts 'Summary:'
+puts "- Merchant Code: #{merchant_code}"
+puts "- Coupon OID: #{coupon_oid}"
+puts "- Total Codes Generated: #{all_codes.length}"
+puts "- Batches Processed: #{num_batches}"
+puts "- Total Time: #{total_time.round(1)}s"
+puts "- Average per batch: #{avg_time.round(1)}s"
+puts "- Output File: #{File.absolute_path(output_file)}"
diff --git a/typescript/coupon/GenerateCouponCodesBatch.ts b/typescript/coupon/GenerateCouponCodesBatch.ts
new file mode 100644
index 0000000..2059b9b
--- /dev/null
+++ b/typescript/coupon/GenerateCouponCodesBatch.ts
@@ -0,0 +1,163 @@
+import { couponApi } from '../api';
+import { CouponResponse, CouponCodesRequest, CouponCodesResponse } from 'ultracart_rest_api_v2_typescript';
+import { DateTime } from 'luxon';
+import * as fs from 'fs';
+
+/**
+ * Batch Coupon Code Generator
+ * Generates large batches of coupon codes by calling the API repeatedly
+ *
+ * Usage: NODE_TLS_REJECT_UNAUTHORIZED=0 ts-node coupon/GenerateCouponCodesBatch.ts [total_codes] [output_file]
+ * Example: NODE_TLS_REJECT_UNAUTHORIZED=0 ts-node coupon/GenerateCouponCodesBatch.ts 10OFF 10000 codes.csv
+ */
+
+export class GenerateCouponCodesBatch {
+ public static async execute(): Promise {
+ // Parse command line arguments
+ const merchantCode: string = process.argv[2];
+ const totalCodes: number = parseInt(process.argv[3] || '10000');
+ const outputFile: string = process.argv[4] || `coupon_codes_${merchantCode}_${Date.now()}.csv`;
+
+ // Validate inputs
+ if (!merchantCode) {
+ console.error('Error: Merchant code is required');
+ console.error('Usage: ts-node coupon/GenerateCouponCodesBatch.ts [total_codes] [output_file]');
+ console.error('Example: ts-node coupon/GenerateCouponCodesBatch.ts 10OFF 10000 codes.csv');
+ process.exit(1);
+ }
+
+ if (totalCodes < 1 || totalCodes > 100000) {
+ console.error(`Error: total_codes must be between 1 and 100,000 (got ${totalCodes})`);
+ process.exit(1);
+ }
+
+ // Display header
+ console.log('Batch Coupon Code Generator');
+ console.log('=============================');
+ console.log(`Merchant Code: ${merchantCode}`);
+ console.log(`Total Codes: ${totalCodes}`);
+ console.log(`Output File: ${outputFile}`);
+ console.log('');
+
+ try {
+ // Look up coupon by merchant code
+ console.log('Looking up coupon by merchant code...');
+ const couponResponse: CouponResponse = await couponApi.getCouponByMerchantCode({ merchantCode: merchantCode });
+
+ const couponOid: number = couponResponse.coupon!.coupon_oid!;
+ console.log(`Found coupon OID: ${couponOid}`);
+ console.log('');
+
+ // Calculate batching
+ const BATCH_SIZE: number = 1000;
+ const numBatches: number = Math.ceil(totalCodes / BATCH_SIZE);
+ const allCodes: string[] = [];
+
+ console.log(`Generating codes in batches of ${BATCH_SIZE}...`);
+ const startTime: number = Date.now();
+
+ // Generate codes in batches
+ for (let batchNum = 1; batchNum <= numBatches; batchNum++) {
+ // Calculate batch size
+ const batchSize: number = (batchNum === numBatches)
+ ? totalCodes - (batchNum - 1) * BATCH_SIZE
+ : BATCH_SIZE;
+
+ // Create request
+ const codesRequest: CouponCodesRequest = {
+ quantity: batchSize,
+ expiration_dts: DateTime.utc().plus({ days: 365 }).toISO()
+ };
+
+ // Call API with retry logic
+ let retryCount: number = 0;
+ let success: boolean = false;
+
+ while (retryCount < 2 && !success) {
+ try {
+ const batchResponse: CouponCodesResponse = await couponApi.generateCouponCodes({
+ couponOid: couponOid,
+ couponCodesRequest: codesRequest
+ });
+
+ const batchCodes: string[] = batchResponse.coupon_codes!;
+ allCodes.push(...batchCodes);
+ success = true;
+
+ // Display progress
+ const elapsed: number = (Date.now() - startTime) / 1000;
+ console.log(`[${batchNum}/${numBatches}] Generated ${batchSize} codes (Total: ${allCodes.length}) - Elapsed: ${elapsed.toFixed(1)}s`);
+ } catch (error: any) {
+ retryCount++;
+ if (retryCount < 2) {
+ console.log(`Warning: Batch ${batchNum} failed, retrying...`);
+ await new Promise(resolve => setTimeout(resolve, 2000)); // exponential backoff
+ } else {
+ console.error(`Error: Failed to generate batch ${batchNum} after retries`);
+ console.error(`Details: ${error.message || error}`);
+ process.exit(1);
+ }
+ }
+ }
+
+ // Rate limiting - sleep between batches (except last)
+ if (batchNum < numBatches) {
+ await new Promise(resolve => setTimeout(resolve, 750));
+ }
+ }
+
+ console.log('');
+ console.log('Writing codes to CSV file...');
+
+ // Write to CSV
+ try {
+ let csvContent: string = 'code,generated_at,batch_number\n';
+
+ let batchNum: number = 1;
+ let codesInBatch: number = 0;
+ const timestamp: string = new Date().toISOString();
+
+ for (const code of allCodes) {
+ csvContent += `${code},${timestamp},${batchNum}\n`;
+
+ codesInBatch++;
+ if (codesInBatch >= BATCH_SIZE) {
+ batchNum++;
+ codesInBatch = 0;
+ }
+ }
+
+ fs.writeFileSync(outputFile, csvContent, 'utf8');
+ console.log(`Successfully saved ${allCodes.length} codes to: ${outputFile}`);
+ } catch (error: any) {
+ console.error(`Error writing to file: ${error.message || error}`);
+ process.exit(1);
+ }
+
+ // Display summary
+ const totalTime: number = (Date.now() - startTime) / 1000;
+ const avgTime: number = totalTime / numBatches;
+
+ console.log('');
+ console.log('Summary:');
+ console.log(`- Merchant Code: ${merchantCode}`);
+ console.log(`- Coupon OID: ${couponOid}`);
+ console.log(`- Total Codes Generated: ${allCodes.length}`);
+ console.log(`- Batches Processed: ${numBatches}`);
+ console.log(`- Total Time: ${totalTime.toFixed(1)}s`);
+ console.log(`- Average per batch: ${avgTime.toFixed(1)}s`);
+ console.log(`- Output File: ${fs.realpathSync(outputFile)}`);
+
+ } catch (error: any) {
+ if (error.message && error.message.includes('not found')) {
+ console.error(`Error: Coupon with merchant code '${merchantCode}' not found`);
+ } else {
+ console.error(`Error: ${error.message || error}`);
+ }
+ if (error.status) {
+ console.error(`Status: ${error.status}`);
+ }
+ process.exit(1);
+ }
+ }
+}