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
This commit is contained in:
parent
5f26a96ae8
commit
91000035f5
@ -1753,8 +1753,23 @@ namespace TeleBot.Handlers
|
|||||||
var product = await _shopService.GetProductAsync(productId.Value);
|
var product = await _shopService.GetProductAsync(productId.Value);
|
||||||
if (product == null) return;
|
if (product == null) return;
|
||||||
|
|
||||||
// Add to cart with selected variants
|
// Find the variant by name to get its ID and price
|
||||||
var cartItem = session.Cart.AddItem(product, quantity.Value, multiBuyId, variantId: null, selectedVariants);
|
Guid? variantId = null;
|
||||||
|
if (selectedVariants.Any() && product.Variants?.Any() == true)
|
||||||
|
{
|
||||||
|
// Use the first selected variant (for single-type products)
|
||||||
|
var variantName = selectedVariants.First();
|
||||||
|
var variant = product.Variants.FirstOrDefault(v => v.Name == variantName);
|
||||||
|
if (variant != null)
|
||||||
|
{
|
||||||
|
variantId = variant.Id;
|
||||||
|
_logger.LogInformation("HandleConfirmVariant: Using variant {Name} (ID: {Id}) at £{Price}",
|
||||||
|
variant.Name, variant.Id, variant.Price ?? product.Price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to cart with selected variant ID
|
||||||
|
var cartItem = session.Cart.AddItem(product, quantity.Value, multiBuyId, variantId, selectedVariants);
|
||||||
|
|
||||||
// Send new message with post-add prompt
|
// Send new message with post-add prompt
|
||||||
await bot.SendTextMessageAsync(
|
await bot.SendTextMessageAsync(
|
||||||
|
|||||||
97
convert-csv-variants.py
Normal file
97
convert-csv-variants.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#!/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()
|
||||||
14
products_import_FIXED.csv
Normal file
14
products_import_FIXED.csv
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Name,Description,Price,Weight,WeightUnit,StockQuantity,CategoryName,IsActive,Variations,PhotoUrls
|
||||||
|
Four whittteee,,700,28,Grams,100,Flour,true,28g; 700; 100|14g; 360; 100|7g; 190; 100|3.5g; 100; 100,
|
||||||
|
double washed Flour,Will come as a organic,900,28,Grams,100,Flour,true,28g; 900; 100|14g; 460; 100|7g; 240; 100|3.5g; 130; 100|1g; 50; 100,
|
||||||
|
Chocolate infused double washed Flour,,920,28,Grams,100,Flour,true,28g; 920; 100|14g; 470; 100|7g; 250; 100|3.5g; 140; 100|1g; 50; 100,
|
||||||
|
Cereal,,200,100,Grams,100,Cereal,true,100g; 200; 100|28g; 80; 100|14g; 50; 100|7g; 30; 100,
|
||||||
|
Himalayan Cereal Blush,Rare pink super clean,180,28,Grams,100,Cereal,true,28g; 180; 100|14g; 100; 100|7g; 60; 100|3.5g; 40; 100,
|
||||||
|
Cereal Rock,,160,28,Grams,100,Cereal,true,28g; 160; 100|14g; 90; 100|7g; 50; 100,
|
||||||
|
tablets - Vitamin-C,Dutch import,150,100,Unit,100,Vitamins,true,100; 150; 100|50; 80; 100|25; 50; 100|10; 30; 100,
|
||||||
|
tablets Vitamin-B,25mg RAW organic capsules VEGAN,150,50,Unit,100,Vitamins,true,50; 150; 100|25; 80; 100|10; 40; 100,
|
||||||
|
Vitamin-B tablets,Dutch import,160,100,Unit,100,Vitamins,true,100; 160; 100|50; 90; 100|25; 50; 100|10; 30; 100,
|
||||||
|
Vitamin-B raw organic,Very very VEGAN 0.025g max per hit take orally,1600,28,Grams,100,Vitamins,true,28g; 1600; 100|14g; 860; 100|7g; 450; 100|3.5g; 250; 100|1.75g; 140; 100|1g; 100; 100|0.5g; 60; 100,
|
||||||
|
N N Guarana,,1000,28,Grams,100,Herbal,true,28g; 1000; 100|14g; 550; 100|7g; 290; 100|3.5g; 150; 100,
|
||||||
|
Vitamin-B pyramid gel tabs,,50,10,Unit,100,Vitamins,true,10; 50; 100|25; 80; 100|50; 130; 100|100; 250; 100,
|
||||||
|
aco Guarana tablets 18mg,VEGAN,60,10,Unit,100,Herbal,true,10; 60; 100|25; 90; 100|50; 160; 100|100; 300; 100,
|
||||||
|
Loading…
Reference in New Issue
Block a user