Upload 7 files
Browse files- app.py +126 -75
- search_marlin_products.py +157 -0
- test_final.py +31 -0
- test_m_turuncu.py +160 -0
- test_updated_warehouse.py +166 -0
- test_variant.py +110 -0
- test_warehouse.py +136 -0
app.py
CHANGED
@@ -60,7 +60,7 @@ else:
|
|
60 |
|
61 |
# Mağaza stok bilgilerini çekme fonksiyonu
|
62 |
def get_warehouse_stock(product_name):
|
63 |
-
"""B2B API'den mağaza stok bilgilerini çek"""
|
64 |
try:
|
65 |
import re
|
66 |
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
@@ -71,71 +71,134 @@ def get_warehouse_stock(product_name):
|
|
71 |
|
72 |
root = ET.fromstring(response.content)
|
73 |
|
74 |
-
#
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
-
|
86 |
-
|
87 |
-
import unicodedata
|
88 |
-
text = unicodedata.normalize('NFD', text)
|
89 |
-
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn') # Remove diacritics
|
90 |
|
91 |
-
#
|
92 |
-
|
93 |
-
|
94 |
-
return text
|
95 |
-
|
96 |
-
# Remove common variations for better matching
|
97 |
-
normalized_search = normalize_turkish(search_name.replace('(2026)', '').replace('(2025)', '').replace(' - ', ' ').strip())
|
98 |
-
normalized_xml = normalize_turkish(xml_product_name.replace('(2026)', '').replace('(2025)', '').replace(' - ', ' ').strip())
|
99 |
-
|
100 |
-
# Extract key product identifiers (first 2-3 meaningful words)
|
101 |
-
search_words = normalized_search.split()
|
102 |
-
xml_words = normalized_xml.split()
|
103 |
-
|
104 |
-
# Calculate similarity score based on common words
|
105 |
-
common_words = set(search_words) & set(xml_words)
|
106 |
-
|
107 |
-
# Check if we have enough common words (at least 2 key words match)
|
108 |
-
# OR if the first two words match (brand + model number usually)
|
109 |
-
search_key = ' '.join(search_words[:2]) if len(search_words) >= 2 else normalized_search
|
110 |
-
xml_key = ' '.join(xml_words[:2]) if len(xml_words) >= 2 else normalized_xml
|
111 |
-
|
112 |
-
# Match if:
|
113 |
-
# 1. First two words are the same (e.g., "marlin 6", "checkpoint sl")
|
114 |
-
# 2. OR we have at least 2 common words
|
115 |
-
# 3. OR one contains the other (for partial matches)
|
116 |
-
if (search_key == xml_key or
|
117 |
-
len(common_words) >= 2 or
|
118 |
-
search_key in normalized_xml or
|
119 |
-
xml_key in normalized_search):
|
120 |
-
warehouses = product.find('Warehouses')
|
121 |
-
if warehouses is not None:
|
122 |
-
warehouse_info = []
|
123 |
-
for warehouse in warehouses.findall('Warehouse'):
|
124 |
-
name_elem = warehouse.find('Name')
|
125 |
-
stock_elem = warehouse.find('Stock')
|
126 |
-
|
127 |
-
if name_elem is not None and stock_elem is not None:
|
128 |
-
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
129 |
-
try:
|
130 |
-
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
131 |
-
if stock_count > 0:
|
132 |
-
warehouse_info.append(f"{warehouse_name}: {stock_count} adet")
|
133 |
-
except (ValueError, TypeError):
|
134 |
-
pass
|
135 |
|
136 |
-
|
137 |
-
|
138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
|
140 |
except Exception as e:
|
141 |
print(f"Mağaza stok bilgisi çekme hatası: {e}")
|
@@ -752,8 +815,6 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
752 |
if product_result['is_product_query'] and product_result['response']:
|
753 |
# Check if user is asking about specific warehouse/store location
|
754 |
if any(keyword in user_message.lower() for keyword in ['mağaza', 'mağazada', 'nerede', 'hangi mağaza', 'şube']):
|
755 |
-
print(f"DEBUG: Mağaza sorusu algılandı: {user_message}")
|
756 |
-
|
757 |
# First, always search for products using improved search
|
758 |
# This will find products even with partial/typo names
|
759 |
warehouse_info_parts = []
|
@@ -766,7 +827,6 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
766 |
product_names = re.findall(r'\*([^*]+)\*', product_result['response'])
|
767 |
|
768 |
if product_names:
|
769 |
-
print(f"DEBUG: Response'tan {len(product_names)} ürün adı çıkarıldı")
|
770 |
for product_name in product_names[:3]: # Max 3 products
|
771 |
# Clean up the product name
|
772 |
product_name = product_name.strip()
|
@@ -779,9 +839,7 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
779 |
if product_name in ['Stokta mevcut', 'Stokta yok', 'Fiyat:', 'Kampanya:', 'İndirim:', 'Birden fazla ürün buldum:']:
|
780 |
continue
|
781 |
|
782 |
-
print(f"DEBUG: Mağaza stogu kontrol ediliyor: {product_name}")
|
783 |
warehouse_stock = get_warehouse_stock(product_name)
|
784 |
-
print(f"DEBUG: Mağaza stok sonucu: {warehouse_stock}")
|
785 |
|
786 |
if warehouse_stock and warehouse_stock != ['Ürün bulunamadı'] and warehouse_stock != ['Hiçbir mağazada stokta bulunmuyor']:
|
787 |
warehouse_info_parts.append(f"{product_name} mağaza stogu:")
|
@@ -791,12 +849,9 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
791 |
|
792 |
# If still no warehouse info, use products_found as backup
|
793 |
if not warehouse_info_parts and product_result['products_found']:
|
794 |
-
print(f"DEBUG: Response'tan bulunamadı, products_found kullanılıyor")
|
795 |
for product in product_result['products_found'][:2]:
|
796 |
product_name = product[2] # Full product name
|
797 |
-
print(f"DEBUG: Mağaza stogu kontrol ediliyor: {product_name}")
|
798 |
warehouse_stock = get_warehouse_stock(product_name)
|
799 |
-
print(f"DEBUG: Mağaza stok sonucu: {warehouse_stock}")
|
800 |
|
801 |
if warehouse_stock and warehouse_stock != ['Ürün bulunamadı'] and warehouse_stock != ['Hiçbir mağazada stokta bulunmuyor']:
|
802 |
warehouse_info_parts.append(f"{product_name} mağaza stogu:")
|
@@ -806,15 +861,12 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
806 |
|
807 |
if warehouse_info_parts:
|
808 |
warehouse_response = "\n".join(warehouse_info_parts)
|
809 |
-
print(f"DEBUG: ChatGPT'ye gönderilecek mağaza bilgisi: {warehouse_response}")
|
810 |
messages.append({
|
811 |
"role": "system",
|
812 |
"content": f"MAĞAZA STOK BİLGİSİ (BF Space):\n{warehouse_response}\n\nSADECE bu bilgileri kullanarak kullanıcıya yardımcı ol."
|
813 |
})
|
814 |
product_found_improved = True
|
815 |
logger.info("✅ BF Space: Warehouse stock info used")
|
816 |
-
else:
|
817 |
-
print("DEBUG: Hiç mağaza bilgisi bulunamadı")
|
818 |
|
819 |
if not product_found_improved:
|
820 |
# Use improved search response directly
|
@@ -824,7 +876,6 @@ def process_whatsapp_message_with_memory(user_message, phone_number):
|
|
824 |
})
|
825 |
product_found_improved = True
|
826 |
logger.info("✅ BF Space: Improved product search used")
|
827 |
-
print(f"DEBUG: Improved search found response: {product_result['response'][:100]}...")
|
828 |
except Exception as e:
|
829 |
logger.error(f"❌ BF Space: Improved search error: {e}")
|
830 |
|
|
|
60 |
|
61 |
# Mağaza stok bilgilerini çekme fonksiyonu
|
62 |
def get_warehouse_stock(product_name):
|
63 |
+
"""B2B API'den mağaza stok bilgilerini çek - İyileştirilmiş versiyon"""
|
64 |
try:
|
65 |
import re
|
66 |
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
|
|
71 |
|
72 |
root = ET.fromstring(response.content)
|
73 |
|
74 |
+
# Turkish character normalization function
|
75 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
76 |
+
|
77 |
+
def normalize_turkish(text):
|
78 |
+
import unicodedata
|
79 |
+
text = unicodedata.normalize('NFD', text)
|
80 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
81 |
+
for tr_char, en_char in turkish_map.items():
|
82 |
+
text = text.replace(tr_char, en_char)
|
83 |
+
return text
|
84 |
+
|
85 |
+
# Normalize search product name
|
86 |
+
search_name = normalize_turkish(product_name.lower().strip())
|
87 |
+
search_name = search_name.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
88 |
+
search_words = search_name.split()
|
89 |
+
|
90 |
+
best_matches = []
|
91 |
+
exact_matches = []
|
92 |
+
variant_matches = []
|
93 |
+
candidates = []
|
94 |
+
|
95 |
+
# Check if this is a size/color specific query (like "M Turuncu")
|
96 |
+
is_size_color_query = (len(search_words) <= 3 and
|
97 |
+
any(word in ['s', 'm', 'l', 'xl', 'xs', 'small', 'medium', 'large',
|
98 |
+
'turuncu', 'siyah', 'beyaz', 'mavi', 'kirmizi', 'yesil',
|
99 |
+
'orange', 'black', 'white', 'blue', 'red', 'green']
|
100 |
+
for word in search_words))
|
101 |
+
|
102 |
+
# İlk geçiş: Variant alanında beden/renk araması
|
103 |
+
if is_size_color_query:
|
104 |
+
for product in root.findall('Product'):
|
105 |
+
product_name_elem = product.find('ProductName')
|
106 |
+
variant_elem = product.find('Variant')
|
107 |
|
108 |
+
if product_name_elem is not None and product_name_elem.text:
|
109 |
+
xml_product_name = product_name_elem.text.strip()
|
|
|
|
|
|
|
110 |
|
111 |
+
# Variant field check
|
112 |
+
if variant_elem is not None and variant_elem.text:
|
113 |
+
variant_text = normalize_turkish(variant_elem.text.lower().replace('-', ' '))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
+
# Check if all search words are in variant field
|
116 |
+
if all(word in variant_text for word in search_words):
|
117 |
+
variant_matches.append((product, xml_product_name, variant_text))
|
118 |
+
|
119 |
+
if variant_matches:
|
120 |
+
candidates = variant_matches
|
121 |
+
else:
|
122 |
+
# Fallback to normal product name search
|
123 |
+
is_size_color_query = False
|
124 |
+
|
125 |
+
# İkinci geçiş: Normal ürün adı tam eşleşmeleri (variant match yoksa)
|
126 |
+
if not is_size_color_query or not candidates:
|
127 |
+
for product in root.findall('Product'):
|
128 |
+
product_name_elem = product.find('ProductName')
|
129 |
+
if product_name_elem is not None and product_name_elem.text:
|
130 |
+
xml_product_name = product_name_elem.text.strip()
|
131 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
132 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
133 |
+
xml_words = normalized_xml.split()
|
134 |
+
|
135 |
+
# Tam eşleşme kontrolü - ilk iki kelime tam aynı olmalı
|
136 |
+
if len(search_words) >= 2 and len(xml_words) >= 2:
|
137 |
+
search_key = f"{search_words[0]} {search_words[1]}"
|
138 |
+
xml_key = f"{xml_words[0]} {xml_words[1]}"
|
139 |
+
|
140 |
+
if search_key == xml_key:
|
141 |
+
exact_matches.append((product, xml_product_name, normalized_xml))
|
142 |
+
|
143 |
+
# Eğer variant match varsa onu kullan, yoksa exact matches kullan
|
144 |
+
if not candidates:
|
145 |
+
candidates = exact_matches if exact_matches else []
|
146 |
+
|
147 |
+
# Eğer hala bir match yoksa, fuzzy matching yap
|
148 |
+
if not candidates:
|
149 |
+
for product in root.findall('Product'):
|
150 |
+
product_name_elem = product.find('ProductName')
|
151 |
+
if product_name_elem is not None and product_name_elem.text:
|
152 |
+
xml_product_name = product_name_elem.text.strip()
|
153 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
154 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
155 |
+
xml_words = normalized_xml.split()
|
156 |
+
|
157 |
+
# Ortak kelime sayısını hesapla
|
158 |
+
common_words = set(search_words) & set(xml_words)
|
159 |
+
|
160 |
+
# En az 2 ortak kelime olmalı VE ilk kelime aynı olmalı (marka kontrolü)
|
161 |
+
if (len(common_words) >= 2 and
|
162 |
+
len(search_words) > 0 and len(xml_words) > 0 and
|
163 |
+
search_words[0] == xml_words[0]):
|
164 |
+
best_matches.append((product, xml_product_name, normalized_xml, len(common_words)))
|
165 |
+
|
166 |
+
# En çok ortak kelimeye sahip olanları seç
|
167 |
+
if best_matches:
|
168 |
+
max_common = max(match[3] for match in best_matches)
|
169 |
+
candidates = [(match[0], match[1], match[2]) for match in best_matches if match[3] == max_common]
|
170 |
+
|
171 |
+
# Stok bilgilerini topla ve tekrarları önle
|
172 |
+
warehouse_stock_map = {} # warehouse_name -> total_stock
|
173 |
+
|
174 |
+
for product, xml_name, _ in candidates:
|
175 |
+
warehouses = product.find('Warehouses')
|
176 |
+
if warehouses is not None:
|
177 |
+
for warehouse in warehouses.findall('Warehouse'):
|
178 |
+
name_elem = warehouse.find('Name')
|
179 |
+
stock_elem = warehouse.find('Stock')
|
180 |
+
|
181 |
+
if name_elem is not None and stock_elem is not None:
|
182 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
183 |
+
try:
|
184 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
185 |
+
if stock_count > 0:
|
186 |
+
# Aynı mağaza için stokları topla
|
187 |
+
if warehouse_name in warehouse_stock_map:
|
188 |
+
warehouse_stock_map[warehouse_name] += stock_count
|
189 |
+
else:
|
190 |
+
warehouse_stock_map[warehouse_name] = stock_count
|
191 |
+
except (ValueError, TypeError):
|
192 |
+
pass
|
193 |
+
|
194 |
+
if warehouse_stock_map:
|
195 |
+
# Mağaza stoklarını liste halinde döndür
|
196 |
+
all_warehouse_info = []
|
197 |
+
for warehouse_name, total_stock in warehouse_stock_map.items():
|
198 |
+
all_warehouse_info.append(f"{warehouse_name}: {total_stock} adet")
|
199 |
+
return all_warehouse_info
|
200 |
+
else:
|
201 |
+
return ["Hiçbir mağazada stokta bulunmuyor"]
|
202 |
|
203 |
except Exception as e:
|
204 |
print(f"Mağaza stok bilgisi çekme hatası: {e}")
|
|
|
815 |
if product_result['is_product_query'] and product_result['response']:
|
816 |
# Check if user is asking about specific warehouse/store location
|
817 |
if any(keyword in user_message.lower() for keyword in ['mağaza', 'mağazada', 'nerede', 'hangi mağaza', 'şube']):
|
|
|
|
|
818 |
# First, always search for products using improved search
|
819 |
# This will find products even with partial/typo names
|
820 |
warehouse_info_parts = []
|
|
|
827 |
product_names = re.findall(r'\*([^*]+)\*', product_result['response'])
|
828 |
|
829 |
if product_names:
|
|
|
830 |
for product_name in product_names[:3]: # Max 3 products
|
831 |
# Clean up the product name
|
832 |
product_name = product_name.strip()
|
|
|
839 |
if product_name in ['Stokta mevcut', 'Stokta yok', 'Fiyat:', 'Kampanya:', 'İndirim:', 'Birden fazla ürün buldum:']:
|
840 |
continue
|
841 |
|
|
|
842 |
warehouse_stock = get_warehouse_stock(product_name)
|
|
|
843 |
|
844 |
if warehouse_stock and warehouse_stock != ['Ürün bulunamadı'] and warehouse_stock != ['Hiçbir mağazada stokta bulunmuyor']:
|
845 |
warehouse_info_parts.append(f"{product_name} mağaza stogu:")
|
|
|
849 |
|
850 |
# If still no warehouse info, use products_found as backup
|
851 |
if not warehouse_info_parts and product_result['products_found']:
|
|
|
852 |
for product in product_result['products_found'][:2]:
|
853 |
product_name = product[2] # Full product name
|
|
|
854 |
warehouse_stock = get_warehouse_stock(product_name)
|
|
|
855 |
|
856 |
if warehouse_stock and warehouse_stock != ['Ürün bulunamadı'] and warehouse_stock != ['Hiçbir mağazada stokta bulunmuyor']:
|
857 |
warehouse_info_parts.append(f"{product_name} mağaza stogu:")
|
|
|
861 |
|
862 |
if warehouse_info_parts:
|
863 |
warehouse_response = "\n".join(warehouse_info_parts)
|
|
|
864 |
messages.append({
|
865 |
"role": "system",
|
866 |
"content": f"MAĞAZA STOK BİLGİSİ (BF Space):\n{warehouse_response}\n\nSADECE bu bilgileri kullanarak kullanıcıya yardımcı ol."
|
867 |
})
|
868 |
product_found_improved = True
|
869 |
logger.info("✅ BF Space: Warehouse stock info used")
|
|
|
|
|
870 |
|
871 |
if not product_found_improved:
|
872 |
# Use improved search response directly
|
|
|
876 |
})
|
877 |
product_found_improved = True
|
878 |
logger.info("✅ BF Space: Improved product search used")
|
|
|
879 |
except Exception as e:
|
880 |
logger.error(f"❌ BF Space: Improved search error: {e}")
|
881 |
|
search_marlin_products.py
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
import requests
|
3 |
+
import xml.etree.ElementTree as ET
|
4 |
+
|
5 |
+
def search_marlin_products():
|
6 |
+
"""B2B API'den MARLIN ürünlerini listele"""
|
7 |
+
try:
|
8 |
+
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
9 |
+
response = requests.get(warehouse_url, verify=False, timeout=15)
|
10 |
+
|
11 |
+
if response.status_code != 200:
|
12 |
+
return None
|
13 |
+
|
14 |
+
root = ET.fromstring(response.content)
|
15 |
+
|
16 |
+
# Turkish character normalization function
|
17 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
18 |
+
|
19 |
+
def normalize_turkish(text):
|
20 |
+
import unicodedata
|
21 |
+
text = unicodedata.normalize('NFD', text)
|
22 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
23 |
+
for tr_char, en_char in turkish_map.items():
|
24 |
+
text = text.replace(tr_char, en_char)
|
25 |
+
return text
|
26 |
+
|
27 |
+
marlin_products = []
|
28 |
+
|
29 |
+
# MARLIN içeren tüm ürünleri bul
|
30 |
+
for product in root.findall('Product'):
|
31 |
+
product_name_elem = product.find('ProductName')
|
32 |
+
if product_name_elem is not None and product_name_elem.text:
|
33 |
+
xml_product_name = product_name_elem.text.strip()
|
34 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
35 |
+
|
36 |
+
if 'marlin' in normalized_xml:
|
37 |
+
# Stok durumunu kontrol et
|
38 |
+
has_stock = False
|
39 |
+
stock_info = []
|
40 |
+
|
41 |
+
warehouses = product.find('Warehouses')
|
42 |
+
if warehouses is not None:
|
43 |
+
for warehouse in warehouses.findall('Warehouse'):
|
44 |
+
name_elem = warehouse.find('Name')
|
45 |
+
stock_elem = warehouse.find('Stock')
|
46 |
+
|
47 |
+
if name_elem is not None and stock_elem is not None:
|
48 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
49 |
+
try:
|
50 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
51 |
+
if stock_count > 0:
|
52 |
+
stock_info.append(f"{warehouse_name}: {stock_count}")
|
53 |
+
has_stock = True
|
54 |
+
except (ValueError, TypeError):
|
55 |
+
pass
|
56 |
+
|
57 |
+
marlin_products.append({
|
58 |
+
'name': xml_product_name,
|
59 |
+
'has_stock': has_stock,
|
60 |
+
'stock_info': stock_info
|
61 |
+
})
|
62 |
+
|
63 |
+
return marlin_products
|
64 |
+
|
65 |
+
except Exception as e:
|
66 |
+
print(f"Arama hatası: {e}")
|
67 |
+
return None
|
68 |
+
|
69 |
+
def search_turuncu_products():
|
70 |
+
"""B2B API'den TURUNCU içeren ürünleri listele"""
|
71 |
+
try:
|
72 |
+
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
73 |
+
response = requests.get(warehouse_url, verify=False, timeout=15)
|
74 |
+
|
75 |
+
if response.status_code != 200:
|
76 |
+
return None
|
77 |
+
|
78 |
+
root = ET.fromstring(response.content)
|
79 |
+
|
80 |
+
# Turkish character normalization function
|
81 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
82 |
+
|
83 |
+
def normalize_turkish(text):
|
84 |
+
import unicodedata
|
85 |
+
text = unicodedata.normalize('NFD', text)
|
86 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
87 |
+
for tr_char, en_char in turkish_map.items():
|
88 |
+
text = text.replace(tr_char, en_char)
|
89 |
+
return text
|
90 |
+
|
91 |
+
turuncu_products = []
|
92 |
+
|
93 |
+
# TURUNCU içeren tüm ürünleri bul
|
94 |
+
for product in root.findall('Product'):
|
95 |
+
product_name_elem = product.find('ProductName')
|
96 |
+
if product_name_elem is not None and product_name_elem.text:
|
97 |
+
xml_product_name = product_name_elem.text.strip()
|
98 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
99 |
+
|
100 |
+
if 'turuncu' in normalized_xml:
|
101 |
+
# Stok durumunu kontrol et
|
102 |
+
has_stock = False
|
103 |
+
stock_info = []
|
104 |
+
|
105 |
+
warehouses = product.find('Warehouses')
|
106 |
+
if warehouses is not None:
|
107 |
+
for warehouse in warehouses.findall('Warehouse'):
|
108 |
+
name_elem = warehouse.find('Name')
|
109 |
+
stock_elem = warehouse.find('Stock')
|
110 |
+
|
111 |
+
if name_elem is not None and stock_elem is not None:
|
112 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
113 |
+
try:
|
114 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
115 |
+
if stock_count > 0:
|
116 |
+
stock_info.append(f"{warehouse_name}: {stock_count}")
|
117 |
+
has_stock = True
|
118 |
+
except (ValueError, TypeError):
|
119 |
+
pass
|
120 |
+
|
121 |
+
turuncu_products.append({
|
122 |
+
'name': xml_product_name,
|
123 |
+
'has_stock': has_stock,
|
124 |
+
'stock_info': stock_info
|
125 |
+
})
|
126 |
+
|
127 |
+
return turuncu_products
|
128 |
+
|
129 |
+
except Exception as e:
|
130 |
+
print(f"Arama hatası: {e}")
|
131 |
+
return None
|
132 |
+
|
133 |
+
if __name__ == "__main__":
|
134 |
+
print("=== MARLIN ÜRÜNLERİ ===")
|
135 |
+
marlin_products = search_marlin_products()
|
136 |
+
if marlin_products:
|
137 |
+
print(f"Toplam {len(marlin_products)} MARLIN ürünü bulundu:")
|
138 |
+
for i, product in enumerate(marlin_products, 1):
|
139 |
+
print(f"{i:2}. {product['name']}")
|
140 |
+
if product['has_stock']:
|
141 |
+
print(f" STOKTA: {', '.join(product['stock_info'])}")
|
142 |
+
else:
|
143 |
+
print(f" STOKTA DEĞİL")
|
144 |
+
print()
|
145 |
+
|
146 |
+
print("\n" + "="*50)
|
147 |
+
print("=== TURUNCU ÜRÜNLERİ ===")
|
148 |
+
turuncu_products = search_turuncu_products()
|
149 |
+
if turuncu_products:
|
150 |
+
print(f"Toplam {len(turuncu_products)} TURUNCU ürünü bulundu:")
|
151 |
+
for i, product in enumerate(turuncu_products, 1):
|
152 |
+
print(f"{i:2}. {product['name']}")
|
153 |
+
if product['has_stock']:
|
154 |
+
print(f" STOKTA: {', '.join(product['stock_info'])}")
|
155 |
+
else:
|
156 |
+
print(f" STOKTA DEĞİL")
|
157 |
+
print()
|
test_final.py
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
# Final test with updated get_warehouse_stock function from app.py
|
3 |
+
|
4 |
+
import sys
|
5 |
+
import os
|
6 |
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
7 |
+
|
8 |
+
# Import the updated function from app.py
|
9 |
+
from app import get_warehouse_stock
|
10 |
+
|
11 |
+
if __name__ == "__main__":
|
12 |
+
test_cases = [
|
13 |
+
"M Turuncu",
|
14 |
+
"Marlin 6 M Turuncu",
|
15 |
+
"L Siyah",
|
16 |
+
"S Beyaz"
|
17 |
+
]
|
18 |
+
|
19 |
+
for test_case in test_cases:
|
20 |
+
print(f"\n=== Testing: {test_case} ===")
|
21 |
+
try:
|
22 |
+
result = get_warehouse_stock(test_case)
|
23 |
+
if result:
|
24 |
+
print("Sonuç:")
|
25 |
+
for item in result:
|
26 |
+
print(f" • {item}")
|
27 |
+
else:
|
28 |
+
print("Sonuç bulunamadı")
|
29 |
+
except Exception as e:
|
30 |
+
print(f"Hata: {e}")
|
31 |
+
print("-" * 50)
|
test_m_turuncu.py
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
import requests
|
3 |
+
import xml.etree.ElementTree as ET
|
4 |
+
|
5 |
+
def get_warehouse_stock(product_name):
|
6 |
+
"""B2B API'den mağaza stok bilgilerini çek - İyileştirilmiş versiyon"""
|
7 |
+
try:
|
8 |
+
import re
|
9 |
+
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
10 |
+
response = requests.get(warehouse_url, verify=False, timeout=15)
|
11 |
+
|
12 |
+
if response.status_code != 200:
|
13 |
+
return None
|
14 |
+
|
15 |
+
root = ET.fromstring(response.content)
|
16 |
+
|
17 |
+
# Turkish character normalization function
|
18 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
19 |
+
|
20 |
+
def normalize_turkish(text):
|
21 |
+
import unicodedata
|
22 |
+
text = unicodedata.normalize('NFD', text)
|
23 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
24 |
+
for tr_char, en_char in turkish_map.items():
|
25 |
+
text = text.replace(tr_char, en_char)
|
26 |
+
return text
|
27 |
+
|
28 |
+
# Normalize search product name
|
29 |
+
search_name = normalize_turkish(product_name.lower().strip())
|
30 |
+
search_name = search_name.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
31 |
+
search_words = search_name.split()
|
32 |
+
|
33 |
+
print(f"DEBUG: Aranan ürün: '{product_name}' -> normalize: '{search_name}' -> kelimeler: {search_words}")
|
34 |
+
|
35 |
+
best_matches = []
|
36 |
+
exact_matches = []
|
37 |
+
color_size_matches = [] # For size/color specific searches
|
38 |
+
|
39 |
+
# Check if this is a size/color query (like "M Turuncu")
|
40 |
+
is_size_color_query = len(search_words) <= 2 and any(word in ['s', 'm', 'l', 'xl', 'xs', 'small', 'medium', 'large', 'turuncu', 'siyah', 'beyaz', 'mavi', 'kirmizi', 'yesil'] for word in search_words)
|
41 |
+
|
42 |
+
if is_size_color_query:
|
43 |
+
print(f"DEBUG: Beden/renk araması algılandı: {search_words}")
|
44 |
+
# For size/color queries, look for products containing these terms
|
45 |
+
for product in root.findall('Product'):
|
46 |
+
product_name_elem = product.find('ProductName')
|
47 |
+
if product_name_elem is not None and product_name_elem.text:
|
48 |
+
xml_product_name = product_name_elem.text.strip()
|
49 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
50 |
+
|
51 |
+
# Check if all search words appear in the product name
|
52 |
+
if all(word in normalized_xml for word in search_words):
|
53 |
+
color_size_matches.append((product, xml_product_name, normalized_xml))
|
54 |
+
print(f"DEBUG: BEDEN/RENK EŞLEŞME: '{xml_product_name}'")
|
55 |
+
|
56 |
+
candidates = color_size_matches
|
57 |
+
else:
|
58 |
+
# Normal product search logic
|
59 |
+
# İlk geçiş: Tam eşleşmeleri bul
|
60 |
+
for product in root.findall('Product'):
|
61 |
+
product_name_elem = product.find('ProductName')
|
62 |
+
if product_name_elem is not None and product_name_elem.text:
|
63 |
+
xml_product_name = product_name_elem.text.strip()
|
64 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
65 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
66 |
+
xml_words = normalized_xml.split()
|
67 |
+
|
68 |
+
# Tam eşleşme kontrolü - ilk iki kelime tam aynı olmalı
|
69 |
+
if len(search_words) >= 2 and len(xml_words) >= 2:
|
70 |
+
search_key = f"{search_words[0]} {search_words[1]}"
|
71 |
+
xml_key = f"{xml_words[0]} {xml_words[1]}"
|
72 |
+
|
73 |
+
if search_key == xml_key:
|
74 |
+
exact_matches.append((product, xml_product_name, normalized_xml))
|
75 |
+
print(f"DEBUG: TAM EŞLEŞME: '{xml_product_name}'")
|
76 |
+
|
77 |
+
# Eğer tam eşleşme varsa, sadece onları kullan
|
78 |
+
candidates = exact_matches if exact_matches else []
|
79 |
+
|
80 |
+
# Eğer tam eşleşme yoksa, fuzzy matching yap
|
81 |
+
if not candidates:
|
82 |
+
print("DEBUG: Tam eşleşme yok, fuzzy matching yapılıyor...")
|
83 |
+
for product in root.findall('Product'):
|
84 |
+
product_name_elem = product.find('ProductName')
|
85 |
+
if product_name_elem is not None and product_name_elem.text:
|
86 |
+
xml_product_name = product_name_elem.text.strip()
|
87 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
88 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
89 |
+
xml_words = normalized_xml.split()
|
90 |
+
|
91 |
+
# Ortak kelime sayısını hesapla
|
92 |
+
common_words = set(search_words) & set(xml_words)
|
93 |
+
|
94 |
+
# En az 2 ortak kelime olmalı VE ilk kelime aynı olmalı (marka kontrolü)
|
95 |
+
if (len(common_words) >= 2 and
|
96 |
+
len(search_words) > 0 and len(xml_words) > 0 and
|
97 |
+
search_words[0] == xml_words[0]):
|
98 |
+
best_matches.append((product, xml_product_name, normalized_xml, len(common_words)))
|
99 |
+
print(f"DEBUG: FUZZY EŞLEŞME: '{xml_product_name}' (ortak: {len(common_words)})")
|
100 |
+
|
101 |
+
# En çok ortak kelimeye sahip olanları seç
|
102 |
+
if best_matches:
|
103 |
+
max_common = max(match[3] for match in best_matches)
|
104 |
+
candidates = [(match[0], match[1], match[2]) for match in best_matches if match[3] == max_common]
|
105 |
+
|
106 |
+
print(f"DEBUG: Toplam {len(candidates)} aday ürün bulundu")
|
107 |
+
|
108 |
+
# Stok bilgilerini topla ve tekrarları önle
|
109 |
+
warehouse_stock_map = {} # warehouse_name -> total_stock
|
110 |
+
|
111 |
+
for product, xml_name, _ in candidates:
|
112 |
+
warehouses = product.find('Warehouses')
|
113 |
+
if warehouses is not None:
|
114 |
+
for warehouse in warehouses.findall('Warehouse'):
|
115 |
+
name_elem = warehouse.find('Name')
|
116 |
+
stock_elem = warehouse.find('Stock')
|
117 |
+
|
118 |
+
if name_elem is not None and stock_elem is not None:
|
119 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
120 |
+
try:
|
121 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
122 |
+
if stock_count > 0:
|
123 |
+
# Aynı mağaza için stokları topla
|
124 |
+
if warehouse_name in warehouse_stock_map:
|
125 |
+
warehouse_stock_map[warehouse_name] += stock_count
|
126 |
+
else:
|
127 |
+
warehouse_stock_map[warehouse_name] = stock_count
|
128 |
+
print(f"DEBUG: STOK BULUNDU - {warehouse_name}: {stock_count} adet ({xml_name})")
|
129 |
+
except (ValueError, TypeError):
|
130 |
+
pass
|
131 |
+
|
132 |
+
if warehouse_stock_map:
|
133 |
+
# Mağaza stoklarını liste halinde döndür
|
134 |
+
all_warehouse_info = []
|
135 |
+
for warehouse_name, total_stock in warehouse_stock_map.items():
|
136 |
+
all_warehouse_info.append(f"{warehouse_name}: {total_stock} adet")
|
137 |
+
return all_warehouse_info
|
138 |
+
else:
|
139 |
+
print("DEBUG: Hiçbir mağazada stok bulunamadı")
|
140 |
+
return ["Hiçbir mağazada stokta bulunmuyor"]
|
141 |
+
|
142 |
+
except Exception as e:
|
143 |
+
print(f"Mağaza stok bilgisi çekme hatası: {e}")
|
144 |
+
return None
|
145 |
+
|
146 |
+
if __name__ == "__main__":
|
147 |
+
# Test the function with different M Turuncu variations
|
148 |
+
test_cases = [
|
149 |
+
"M Turuncu",
|
150 |
+
"m turuncu",
|
151 |
+
"M TURUNCU",
|
152 |
+
"Medium Turuncu",
|
153 |
+
"Marlin 6 M Turuncu"
|
154 |
+
]
|
155 |
+
|
156 |
+
for test_case in test_cases:
|
157 |
+
print(f"=== Testing: {test_case} ===")
|
158 |
+
result = get_warehouse_stock(test_case)
|
159 |
+
print(f"Result: {result}")
|
160 |
+
print()
|
test_updated_warehouse.py
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
import requests
|
3 |
+
import xml.etree.ElementTree as ET
|
4 |
+
|
5 |
+
def get_warehouse_stock(product_name):
|
6 |
+
"""B2B API'den mağaza stok bilgilerini çek - Final Updated Version"""
|
7 |
+
try:
|
8 |
+
import re
|
9 |
+
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
10 |
+
response = requests.get(warehouse_url, verify=False, timeout=15)
|
11 |
+
|
12 |
+
if response.status_code != 200:
|
13 |
+
return None
|
14 |
+
|
15 |
+
root = ET.fromstring(response.content)
|
16 |
+
|
17 |
+
# Turkish character normalization function
|
18 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
19 |
+
|
20 |
+
def normalize_turkish(text):
|
21 |
+
import unicodedata
|
22 |
+
text = unicodedata.normalize('NFD', text)
|
23 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
24 |
+
for tr_char, en_char in turkish_map.items():
|
25 |
+
text = text.replace(tr_char, en_char)
|
26 |
+
return text
|
27 |
+
|
28 |
+
# Normalize search product name
|
29 |
+
search_name = normalize_turkish(product_name.lower().strip())
|
30 |
+
search_name = search_name.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
31 |
+
search_words = search_name.split()
|
32 |
+
|
33 |
+
best_matches = []
|
34 |
+
exact_matches = []
|
35 |
+
variant_matches = []
|
36 |
+
candidates = []
|
37 |
+
|
38 |
+
# Check if this is a size/color specific query (like "M Turuncu")
|
39 |
+
is_size_color_query = (len(search_words) <= 3 and
|
40 |
+
any(word in ['s', 'm', 'l', 'xl', 'xs', 'small', 'medium', 'large',
|
41 |
+
'turuncu', 'siyah', 'beyaz', 'mavi', 'kirmizi', 'yesil',
|
42 |
+
'orange', 'black', 'white', 'blue', 'red', 'green']
|
43 |
+
for word in search_words))
|
44 |
+
|
45 |
+
# İlk geçiş: Variant alanında beden/renk araması
|
46 |
+
if is_size_color_query:
|
47 |
+
for product in root.findall('Product'):
|
48 |
+
product_name_elem = product.find('ProductName')
|
49 |
+
variant_elem = product.find('Variant')
|
50 |
+
|
51 |
+
if product_name_elem is not None and product_name_elem.text:
|
52 |
+
xml_product_name = product_name_elem.text.strip()
|
53 |
+
|
54 |
+
# Variant field check
|
55 |
+
if variant_elem is not None and variant_elem.text:
|
56 |
+
variant_text = normalize_turkish(variant_elem.text.lower().replace('-', ' '))
|
57 |
+
|
58 |
+
# Check if all search words are in variant field
|
59 |
+
if all(word in variant_text for word in search_words):
|
60 |
+
variant_matches.append((product, xml_product_name, variant_text))
|
61 |
+
|
62 |
+
if variant_matches:
|
63 |
+
candidates = variant_matches
|
64 |
+
else:
|
65 |
+
# Fallback to normal product name search
|
66 |
+
is_size_color_query = False
|
67 |
+
|
68 |
+
# İkinci geçiş: Normal ürün adı tam eşleşmeleri (variant match yoksa)
|
69 |
+
if not is_size_color_query or not candidates:
|
70 |
+
for product in root.findall('Product'):
|
71 |
+
product_name_elem = product.find('ProductName')
|
72 |
+
if product_name_elem is not None and product_name_elem.text:
|
73 |
+
xml_product_name = product_name_elem.text.strip()
|
74 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
75 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
76 |
+
xml_words = normalized_xml.split()
|
77 |
+
|
78 |
+
# Tam eşleşme kontrolü - ilk iki kelime tam aynı olmalı
|
79 |
+
if len(search_words) >= 2 and len(xml_words) >= 2:
|
80 |
+
search_key = f"{search_words[0]} {search_words[1]}"
|
81 |
+
xml_key = f"{xml_words[0]} {xml_words[1]}"
|
82 |
+
|
83 |
+
if search_key == xml_key:
|
84 |
+
exact_matches.append((product, xml_product_name, normalized_xml))
|
85 |
+
|
86 |
+
# Eğer variant match varsa onu kullan, yoksa exact matches kullan
|
87 |
+
if not candidates:
|
88 |
+
candidates = exact_matches if exact_matches else []
|
89 |
+
|
90 |
+
# Eğer hala bir match yoksa, fuzzy matching yap
|
91 |
+
if not candidates:
|
92 |
+
for product in root.findall('Product'):
|
93 |
+
product_name_elem = product.find('ProductName')
|
94 |
+
if product_name_elem is not None and product_name_elem.text:
|
95 |
+
xml_product_name = product_name_elem.text.strip()
|
96 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
97 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
98 |
+
xml_words = normalized_xml.split()
|
99 |
+
|
100 |
+
# Ortak kelime sayısını hesapla
|
101 |
+
common_words = set(search_words) & set(xml_words)
|
102 |
+
|
103 |
+
# En az 2 ortak kelime olmalı VE ilk kelime aynı olmalı (marka kontrolü)
|
104 |
+
if (len(common_words) >= 2 and
|
105 |
+
len(search_words) > 0 and len(xml_words) > 0 and
|
106 |
+
search_words[0] == xml_words[0]):
|
107 |
+
best_matches.append((product, xml_product_name, normalized_xml, len(common_words)))
|
108 |
+
|
109 |
+
# En çok ortak kelimeye sahip olanları seç
|
110 |
+
if best_matches:
|
111 |
+
max_common = max(match[3] for match in best_matches)
|
112 |
+
candidates = [(match[0], match[1], match[2]) for match in best_matches if match[3] == max_common]
|
113 |
+
|
114 |
+
# Stok bilgilerini topla ve tekrarları önle
|
115 |
+
warehouse_stock_map = {} # warehouse_name -> total_stock
|
116 |
+
|
117 |
+
for product, xml_name, _ in candidates:
|
118 |
+
warehouses = product.find('Warehouses')
|
119 |
+
if warehouses is not None:
|
120 |
+
for warehouse in warehouses.findall('Warehouse'):
|
121 |
+
name_elem = warehouse.find('Name')
|
122 |
+
stock_elem = warehouse.find('Stock')
|
123 |
+
|
124 |
+
if name_elem is not None and stock_elem is not None:
|
125 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
126 |
+
try:
|
127 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
128 |
+
if stock_count > 0:
|
129 |
+
# Aynı mağaza için stokları topla
|
130 |
+
if warehouse_name in warehouse_stock_map:
|
131 |
+
warehouse_stock_map[warehouse_name] += stock_count
|
132 |
+
else:
|
133 |
+
warehouse_stock_map[warehouse_name] = stock_count
|
134 |
+
except (ValueError, TypeError):
|
135 |
+
pass
|
136 |
+
|
137 |
+
if warehouse_stock_map:
|
138 |
+
# Mağaza stoklarını liste halinde döndür
|
139 |
+
all_warehouse_info = []
|
140 |
+
for warehouse_name, total_stock in warehouse_stock_map.items():
|
141 |
+
all_warehouse_info.append(f"{warehouse_name}: {total_stock} adet")
|
142 |
+
return all_warehouse_info
|
143 |
+
else:
|
144 |
+
return ["Hiçbir mağazada stokta bulunmuyor"]
|
145 |
+
|
146 |
+
except Exception as e:
|
147 |
+
print(f"Mağaza stok bilgisi çekme hatası: {e}")
|
148 |
+
return None
|
149 |
+
|
150 |
+
if __name__ == "__main__":
|
151 |
+
test_cases = [
|
152 |
+
"M Turuncu",
|
153 |
+
"Marlin 6 M Turuncu",
|
154 |
+
"L Siyah"
|
155 |
+
]
|
156 |
+
|
157 |
+
for test_case in test_cases:
|
158 |
+
print(f"\n=== Testing: {test_case} ===")
|
159 |
+
result = get_warehouse_stock(test_case)
|
160 |
+
if result:
|
161 |
+
print("Sonuç:")
|
162 |
+
for item in result:
|
163 |
+
print(f" • {item}")
|
164 |
+
else:
|
165 |
+
print("Sonuç bulunamadı")
|
166 |
+
print("-" * 50)
|
test_variant.py
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
import requests
|
3 |
+
import xml.etree.ElementTree as ET
|
4 |
+
|
5 |
+
def test_variant_search(product_name):
|
6 |
+
"""B2B API'den variant field'ı kontrol et"""
|
7 |
+
try:
|
8 |
+
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
9 |
+
response = requests.get(warehouse_url, verify=False, timeout=15)
|
10 |
+
|
11 |
+
if response.status_code != 200:
|
12 |
+
return None
|
13 |
+
|
14 |
+
root = ET.fromstring(response.content)
|
15 |
+
|
16 |
+
# Turkish character normalization function
|
17 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
18 |
+
|
19 |
+
def normalize_turkish(text):
|
20 |
+
import unicodedata
|
21 |
+
text = unicodedata.normalize('NFD', text)
|
22 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
23 |
+
for tr_char, en_char in turkish_map.items():
|
24 |
+
text = text.replace(tr_char, en_char)
|
25 |
+
return text
|
26 |
+
|
27 |
+
# Normalize search product name
|
28 |
+
search_name = normalize_turkish(product_name.lower().strip())
|
29 |
+
search_words = search_name.split()
|
30 |
+
|
31 |
+
print(f"DEBUG: Aranan: '{product_name}' -> normalize: '{search_name}' -> kelimeler: {search_words}")
|
32 |
+
|
33 |
+
variant_matches = []
|
34 |
+
|
35 |
+
# Check variant field for M-TURUNCU like patterns
|
36 |
+
for product in root.findall('Product'):
|
37 |
+
product_name_elem = product.find('ProductName')
|
38 |
+
variant_elem = product.find('Variant')
|
39 |
+
|
40 |
+
if product_name_elem is not None and product_name_elem.text:
|
41 |
+
xml_product_name = product_name_elem.text.strip()
|
42 |
+
|
43 |
+
# Check variant field
|
44 |
+
if variant_elem is not None and variant_elem.text:
|
45 |
+
variant_text = variant_elem.text.strip()
|
46 |
+
variant_normalized = normalize_turkish(variant_text.lower().replace('-', ' '))
|
47 |
+
|
48 |
+
# Check if all search words are in variant field
|
49 |
+
if all(word in variant_normalized for word in search_words):
|
50 |
+
# Check for stock
|
51 |
+
warehouses = product.find('Warehouses')
|
52 |
+
stock_info = []
|
53 |
+
if warehouses is not None:
|
54 |
+
for warehouse in warehouses.findall('Warehouse'):
|
55 |
+
name_elem = warehouse.find('Name')
|
56 |
+
stock_elem = warehouse.find('Stock')
|
57 |
+
|
58 |
+
if name_elem is not None and stock_elem is not None:
|
59 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
60 |
+
try:
|
61 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
62 |
+
if stock_count > 0:
|
63 |
+
stock_info.append(f"{warehouse_name}: {stock_count}")
|
64 |
+
except (ValueError, TypeError):
|
65 |
+
pass
|
66 |
+
|
67 |
+
variant_matches.append({
|
68 |
+
'product_name': xml_product_name,
|
69 |
+
'variant': variant_text,
|
70 |
+
'variant_normalized': variant_normalized,
|
71 |
+
'stock_info': stock_info
|
72 |
+
})
|
73 |
+
|
74 |
+
print(f"DEBUG: VARIANT MATCH - {xml_product_name}")
|
75 |
+
print(f" Variant: {variant_text} -> {variant_normalized}")
|
76 |
+
if stock_info:
|
77 |
+
print(f" Stok: {', '.join(stock_info)}")
|
78 |
+
else:
|
79 |
+
print(f" Stokta yok")
|
80 |
+
|
81 |
+
return variant_matches
|
82 |
+
|
83 |
+
except Exception as e:
|
84 |
+
print(f"Hata: {e}")
|
85 |
+
return None
|
86 |
+
|
87 |
+
if __name__ == "__main__":
|
88 |
+
# Test different cases
|
89 |
+
test_cases = [
|
90 |
+
"M Turuncu",
|
91 |
+
"m turuncu",
|
92 |
+
"L Siyah",
|
93 |
+
"S Beyaz"
|
94 |
+
]
|
95 |
+
|
96 |
+
for test_case in test_cases:
|
97 |
+
print(f"\n=== Testing: {test_case} ===")
|
98 |
+
result = test_variant_search(test_case)
|
99 |
+
|
100 |
+
if result:
|
101 |
+
print(f"Toplam {len(result)} variant match bulundu:")
|
102 |
+
for i, match in enumerate(result, 1):
|
103 |
+
print(f"{i}. {match['product_name']} - {match['variant']}")
|
104 |
+
if match['stock_info']:
|
105 |
+
print(f" Stokta: {', '.join(match['stock_info'])}")
|
106 |
+
else:
|
107 |
+
print(f" Stokta değil")
|
108 |
+
else:
|
109 |
+
print("Variant match bulunamadı")
|
110 |
+
print("-" * 50)
|
test_warehouse.py
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
import requests
|
3 |
+
import xml.etree.ElementTree as ET
|
4 |
+
|
5 |
+
def get_warehouse_stock(product_name):
|
6 |
+
"""B2B API'den mağaza stok bilgilerini çek - İyileştirilmiş versiyon"""
|
7 |
+
try:
|
8 |
+
import re
|
9 |
+
warehouse_url = 'https://video.trek-turkey.com/bizimhesap-warehouse-xml.php'
|
10 |
+
response = requests.get(warehouse_url, verify=False, timeout=15)
|
11 |
+
|
12 |
+
if response.status_code != 200:
|
13 |
+
return None
|
14 |
+
|
15 |
+
root = ET.fromstring(response.content)
|
16 |
+
|
17 |
+
# Turkish character normalization function
|
18 |
+
turkish_map = {'ı': 'i', 'ğ': 'g', 'ü': 'u', 'ş': 's', 'ö': 'o', 'ç': 'c', 'İ': 'i', 'I': 'i'}
|
19 |
+
|
20 |
+
def normalize_turkish(text):
|
21 |
+
import unicodedata
|
22 |
+
text = unicodedata.normalize('NFD', text)
|
23 |
+
text = ''.join(char for char in text if unicodedata.category(char) != 'Mn')
|
24 |
+
for tr_char, en_char in turkish_map.items():
|
25 |
+
text = text.replace(tr_char, en_char)
|
26 |
+
return text
|
27 |
+
|
28 |
+
# Normalize search product name
|
29 |
+
search_name = normalize_turkish(product_name.lower().strip())
|
30 |
+
search_name = search_name.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
31 |
+
search_words = search_name.split()
|
32 |
+
|
33 |
+
print(f"DEBUG: Aranan ürün: '{product_name}' -> normalize: '{search_name}' -> kelimeler: {search_words}")
|
34 |
+
|
35 |
+
best_matches = []
|
36 |
+
exact_matches = []
|
37 |
+
|
38 |
+
# İlk geçiş: Tam eşleşmeleri bul
|
39 |
+
for product in root.findall('Product'):
|
40 |
+
product_name_elem = product.find('ProductName')
|
41 |
+
if product_name_elem is not None and product_name_elem.text:
|
42 |
+
xml_product_name = product_name_elem.text.strip()
|
43 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
44 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
45 |
+
xml_words = normalized_xml.split()
|
46 |
+
|
47 |
+
# Tam eşleşme kontrolü - ilk iki kelime tam aynı olmalı
|
48 |
+
if len(search_words) >= 2 and len(xml_words) >= 2:
|
49 |
+
search_key = f"{search_words[0]} {search_words[1]}"
|
50 |
+
xml_key = f"{xml_words[0]} {xml_words[1]}"
|
51 |
+
|
52 |
+
if search_key == xml_key:
|
53 |
+
exact_matches.append((product, xml_product_name, normalized_xml))
|
54 |
+
print(f"DEBUG: TAM EŞLEŞME bulundu: '{xml_product_name}'")
|
55 |
+
|
56 |
+
# Eğer tam eşleşme varsa, sadece onları kullan
|
57 |
+
candidates = exact_matches if exact_matches else []
|
58 |
+
|
59 |
+
# Eğer tam eşleşme yoksa, fuzzy matching yap
|
60 |
+
if not candidates:
|
61 |
+
print("DEBUG: Tam eşleşme yok, fuzzy matching yapılıyor...")
|
62 |
+
for product in root.findall('Product'):
|
63 |
+
product_name_elem = product.find('ProductName')
|
64 |
+
if product_name_elem is not None and product_name_elem.text:
|
65 |
+
xml_product_name = product_name_elem.text.strip()
|
66 |
+
normalized_xml = normalize_turkish(xml_product_name.lower())
|
67 |
+
normalized_xml = normalized_xml.replace('(2026)', '').replace('(2025)', '').replace(' gen 3', '').replace(' gen', '').strip()
|
68 |
+
xml_words = normalized_xml.split()
|
69 |
+
|
70 |
+
# Ortak kelime sayısını hesapla
|
71 |
+
common_words = set(search_words) & set(xml_words)
|
72 |
+
|
73 |
+
# En az 2 ortak kelime olmalı VE ilk kelime aynı olmalı (marka kontrolü)
|
74 |
+
if (len(common_words) >= 2 and
|
75 |
+
len(search_words) > 0 and len(xml_words) > 0 and
|
76 |
+
search_words[0] == xml_words[0]):
|
77 |
+
best_matches.append((product, xml_product_name, normalized_xml, len(common_words)))
|
78 |
+
print(f"DEBUG: FUZZY EŞLEŞME: '{xml_product_name}' (ortak: {len(common_words)})")
|
79 |
+
|
80 |
+
# En çok ortak kelimeye sahip olanları seç
|
81 |
+
if best_matches:
|
82 |
+
max_common = max(match[3] for match in best_matches)
|
83 |
+
candidates = [(match[0], match[1], match[2]) for match in best_matches if match[3] == max_common]
|
84 |
+
|
85 |
+
print(f"DEBUG: Toplam {len(candidates)} aday ürün bulundu")
|
86 |
+
|
87 |
+
# Stok bilgilerini topla ve tekrarları önle
|
88 |
+
warehouse_stock_map = {} # warehouse_name -> total_stock
|
89 |
+
|
90 |
+
for product, xml_name, _ in candidates:
|
91 |
+
warehouses = product.find('Warehouses')
|
92 |
+
if warehouses is not None:
|
93 |
+
for warehouse in warehouses.findall('Warehouse'):
|
94 |
+
name_elem = warehouse.find('Name')
|
95 |
+
stock_elem = warehouse.find('Stock')
|
96 |
+
|
97 |
+
if name_elem is not None and stock_elem is not None:
|
98 |
+
warehouse_name = name_elem.text if name_elem.text else "Bilinmeyen"
|
99 |
+
try:
|
100 |
+
stock_count = int(stock_elem.text) if stock_elem.text else 0
|
101 |
+
if stock_count > 0:
|
102 |
+
# Aynı mağaza için stokları topla
|
103 |
+
if warehouse_name in warehouse_stock_map:
|
104 |
+
warehouse_stock_map[warehouse_name] += stock_count
|
105 |
+
else:
|
106 |
+
warehouse_stock_map[warehouse_name] = stock_count
|
107 |
+
print(f"DEBUG: STOK BULUNDU - {warehouse_name}: {stock_count} adet ({xml_name})")
|
108 |
+
except (ValueError, TypeError):
|
109 |
+
pass
|
110 |
+
|
111 |
+
if warehouse_stock_map:
|
112 |
+
# Mağaza stoklarını liste halinde döndür
|
113 |
+
all_warehouse_info = []
|
114 |
+
for warehouse_name, total_stock in warehouse_stock_map.items():
|
115 |
+
all_warehouse_info.append(f"{warehouse_name}: {total_stock} adet")
|
116 |
+
return all_warehouse_info
|
117 |
+
else:
|
118 |
+
print("DEBUG: Hiçbir mağazada stok bulunamadı")
|
119 |
+
return ["Hiçbir mağazada stokta bulunmuyor"]
|
120 |
+
|
121 |
+
except Exception as e:
|
122 |
+
print(f"Mağaza stok bilgisi çekme hatası: {e}")
|
123 |
+
return None
|
124 |
+
|
125 |
+
if __name__ == "__main__":
|
126 |
+
# Test the function with different inputs
|
127 |
+
test_cases = [
|
128 |
+
"MARLIN 6 (2026)",
|
129 |
+
"Marlin 6"
|
130 |
+
]
|
131 |
+
|
132 |
+
for test_case in test_cases:
|
133 |
+
print(f"=== Testing: {test_case} ===")
|
134 |
+
result = get_warehouse_stock(test_case)
|
135 |
+
print(f"Result: {result}")
|
136 |
+
print()
|