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
98 lines
3.2 KiB
Python
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()
|