littleshop/convert-csv-variants.py
SysAdmin 91000035f5 Fix: HandleConfirmVariant now passes variant ID instead of null
Critical fix for £0 order bug:
- When users select a variant and click 'Add to Basket', the confirmvar: callback triggers HandleConfirmVariant
- This method was passing variantId: null to AddItem(), causing cart items to have no variant and price £0
- Now looks up selected variant by name, extracts its ID, and passes it to cart
- Added logging to track which variant is being used
- Also includes CSV variant conversion utility and sample fixed import file
2025-10-08 19:54:08 +01:00

98 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""
Convert LittleShop CSV from old MultiBuy format to new ProductVariant format
OLD FORMAT (MultiBuys): "28g:1:700;14g:1:360;7g:1:190"
NEW FORMAT (Variants): "28g; 700; 100|14g; 360; 100|7g; 190; 100"
Usage: python3 convert-csv-variants.py products_import.csv products_import_fixed.csv [default_stock]
"""
import csv
import sys
def convert_variations(old_format, default_stock=100):
"""
Convert from MultiBuy format to Variant format
OLD: "name:quantity:price;name:quantity:price"
NEW: "value; price; stock|value; price; stock"
"""
if not old_format or not old_format.strip():
return ""
# Check if already in new format (contains semicolons and pipes)
if ';' in old_format and '|' not in old_format and old_format.count(';') > old_format.count(':'):
# Likely already in variant format, return as-is
return old_format
# Split by semicolons (old format separator)
variants = old_format.split(';')
new_variants = []
for variant in variants:
if not variant.strip():
continue
# Split by colons: name:quantity:price
parts = variant.split(':')
if len(parts) >= 3:
variant_value = parts[0].strip() # e.g., "28g", "10"
# Skip the quantity (parts[1]) - not used in variant format
price = parts[2].strip() # e.g., "700", "30.00"
# Create new format: "value; price; stock"
new_variants.append(f"{variant_value}; {price}; {default_stock}")
# Join with pipe separator
return '|'.join(new_variants)
def main():
if len(sys.argv) < 3:
print(__doc__)
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
default_stock = int(sys.argv[3]) if len(sys.argv) > 3 else 100
print(f"Converting CSV: {input_file} -> {output_file}")
print(f"Default stock level: {default_stock}")
converted_count = 0
skipped_count = 0
with open(input_file, 'r', encoding='utf-8') as infile, \
open(output_file, 'w', encoding='utf-8', newline='') as outfile:
reader = csv.DictReader(infile)
fieldnames = reader.fieldnames
writer = csv.DictWriter(outfile, fieldnames=fieldnames)
writer.writeheader()
for row in reader:
if 'Variations' in row and row['Variations']:
old_variations = row['Variations']
new_variations = convert_variations(old_variations, default_stock)
if new_variations != old_variations:
print(f"\n{row['Name']}:")
print(f" OLD: {old_variations}")
print(f" NEW: {new_variations}")
row['Variations'] = new_variations
converted_count += 1
else:
skipped_count += 1
writer.writerow(row)
print(f"\n✅ Conversion complete!")
print(f" Converted: {converted_count} products")
print(f" Skipped: {skipped_count} products (no variations or already correct format)")
print(f"\n📁 Output file: {output_file}")
print(f"\n🚀 Next step: Import {output_file} in Admin Panel → Products → Import CSV")
if __name__ == '__main__':
main()