Преглед на файлове

feat: implement progressive volume discount (5% per item, max 20%) with UI indicators

unknown преди 2 месеца
родител
ревизия
5a6e4b4ebc

+ 13 - 6
backend/services/pricing.py

@@ -25,10 +25,14 @@ def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quan
     if file_quantities is None or len(file_quantities) != len(file_sizes):
         file_quantities = [1] * len(file_sizes)
         
-    estimated_total = 0.0
-    file_costs = []
-    base_fee = 5.0 # Minimum setup fee per file
-    
+    # Volume discount: 5% for each next item, max 20% total
+    total_qty = sum(file_quantities)
+    discount_multiplier = 1.0
+    discount_percent = 0.0
+    if total_qty > 1:
+        discount_percent = min((total_qty - 1) * 0.05, 0.20)
+        discount_multiplier = 1.0 - discount_percent
+
     for size, qty in zip(file_sizes, file_quantities):
         total_size_mb = size / (1024 * 1024)
         # Empirical conversion: ~8cm3 per 1MB of STL (binary)
@@ -41,7 +45,8 @@ def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quan
         material_cost = estimated_volume_cm3 * price_per_cm3
         operation_cost = estimated_hours * price_per_hour
         
-        file_cost = round(base_fee + material_cost + operation_cost, 2)
+        # Apply volume discount to unit price
+        file_cost = round((base_fee + material_cost + operation_cost) * discount_multiplier, 2)
         file_costs.append(file_cost)
         estimated_total += file_cost * qty
     
@@ -49,7 +54,9 @@ def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quan
         "price_per_cm3": price_per_cm3,
         "price_per_hour": price_per_hour,
         "speed_coeff": speed_coeff,
-        "base_fee": base_fee
+        "base_fee": base_fee,
+        "discount_percent": round(discount_percent * 100, 0),
+        "total_qty": total_qty
     }
 
     if return_details:

+ 4 - 0
src/components/ModelUploadSection.vue

@@ -311,6 +311,10 @@
                 <AlertCircle class="w-3 h-3" />
                 <span class="text-[10px] font-bold uppercase">{{ t("admin.fields.speedCoeff") }}: x{{ estimateMetadata.speed_coeff }}</span>
               </div>
+              <div v-if="estimateMetadata?.discount_percent && estimateMetadata.discount_percent > 0" class="flex items-center gap-1.5 px-2 py-0.5 bg-emerald-500/10 text-emerald-500 rounded-md w-fit mb-2">
+                <Check class="w-3 h-3" />
+                <span class="text-[10px] font-bold uppercase">{{ t("admin.fields.discount") }}: -{{ estimateMetadata.discount_percent }}%</span>
+              </div>
               <p class="text-xs text-muted-foreground">{{ t("upload.priceDisclaimer") }}</p>
             </div>
             <div class="text-right">

+ 3 - 0
src/components/admin/OrderCard.vue

@@ -104,6 +104,9 @@
                  <div v-if="JSON.parse(order.original_params).printer_hour_price" class="px-1.5 py-0.5 bg-primary/10 rounded text-[10px] font-bold text-primary">
                     {{ JSON.parse(order.original_params).printer_hour_price }}€/h
                  </div>
+                 <div v-if="JSON.parse(order.original_params).discount_percent" class="px-1.5 py-0.5 bg-emerald-500/10 rounded text-[10px] font-bold text-emerald-500">
+                    -{{ JSON.parse(order.original_params).discount_percent }}% {{ t("admin.fields.discount") }}
+                 </div>
                </div>
             </div>
           </div>

+ 6 - 0
src/locales/master_admin/fields.json

@@ -120,6 +120,12 @@
       "ru": "Финальная цена",
       "ua": "Фінальна ціна"
     },
+    "discount": {
+      "en": "Volume Discount",
+      "me": "Popust na količinu",
+      "ru": "Скидка за объем",
+      "ua": "Знижка за обсяг"
+    },
     "firstName": {
       "en": "First Name",
       "me": "Ime",

+ 6 - 0
src/locales/translations.admin.json

@@ -285,6 +285,12 @@
         "ru": "Финальная цена",
         "ua": "Фінальна ціна"
       },
+      "discount": {
+        "en": "Volume Discount",
+        "me": "Popust na količinu",
+        "ru": "Скидка за объем",
+        "ua": "Знижка за обсяг"
+      },
       "firstName": {
         "en": "First Name",
         "me": "Ime",