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:
SysAdmin 2025-10-08 19:54:08 +01:00
parent 5f26a96ae8
commit 91000035f5
3 changed files with 128 additions and 2 deletions

View File

@ -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
View 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
View 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,
1 Name Description Price Weight WeightUnit StockQuantity CategoryName IsActive Variations PhotoUrls
2 Four whittteee 700 28 Grams 100 Flour true 28g; 700; 100|14g; 360; 100|7g; 190; 100|3.5g; 100; 100
3 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
4 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
5 Cereal 200 100 Grams 100 Cereal true 100g; 200; 100|28g; 80; 100|14g; 50; 100|7g; 30; 100
6 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
7 Cereal Rock 160 28 Grams 100 Cereal true 28g; 160; 100|14g; 90; 100|7g; 50; 100
8 tablets - Vitamin-C Dutch import 150 100 Unit 100 Vitamins true 100; 150; 100|50; 80; 100|25; 50; 100|10; 30; 100
9 tablets Vitamin-B 25mg RAW organic capsules VEGAN 150 50 Unit 100 Vitamins true 50; 150; 100|25; 80; 100|10; 40; 100
10 Vitamin-B tablets Dutch import 160 100 Unit 100 Vitamins true 100; 160; 100|50; 90; 100|25; 50; 100|10; 30; 100
11 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
12 N N Guarana 1000 28 Grams 100 Herbal true 28g; 1000; 100|14g; 550; 100|7g; 290; 100|3.5g; 150; 100
13 Vitamin-B pyramid gel tabs 50 10 Unit 100 Vitamins true 10; 50; 100|25; 80; 100|50; 130; 100|100; 250; 100
14 aco Guarana tablets 18mg VEGAN 60 10 Unit 100 Herbal true 10; 60; 100|25; 90; 100|50; 160; 100|100; 300; 100