Эх сурвалжийг харах

feat: enhance pricing engine with speed coefficients, metadata snapshotting, and admin UI transparency

unknown 2 сар өмнө
parent
commit
dbceae833c

+ 17 - 6
backend/routers/orders.py

@@ -73,11 +73,20 @@ async def create_order(
             pass
 
     name_col = f"name_{lang}" if lang in ["en", "ru", "me"] else "name_en"
-    
-    mat_info = db.execute_query(f"SELECT {name_col}, price_per_cm3, price_per_hour FROM materials WHERE id = %s", (material_id,))
+    # Fetch material info including technology-specific hourly price if available
+    mat_query = """
+        SELECT m.name_en, m.name_ru, m.name_ua, m.name_me, m.price_per_cm3, 
+               COALESCE(NULLIF(m.price_per_hour, 0), s.price_per_hour, %s) as price_per_hour,
+               m.speed_coeff
+        FROM materials m
+        LEFT JOIN services s ON m.service_id = s.id
+        WHERE m.id = %s
+    """
+    mat_info = db.execute_query(mat_query, (config.DEFAULT_PRINTER_HOUR_PRICE, material_id))
     mat_name = mat_info[0][name_col] if mat_info else "Unknown"
     mat_price = mat_info[0]['price_per_cm3'] if mat_info else 0.0
-    hour_price = mat_info[0]['price_per_hour'] if mat_info and mat_info[0]['price_per_hour'] is not None else config.DEFAULT_PRINTER_HOUR_PRICE
+    hour_price = mat_info[0]['price_per_hour'] if mat_info else config.DEFAULT_PRINTER_HOUR_PRICE
+    speed_coeff = mat_info[0]['speed_coeff'] if mat_info else 1.0
 
     file_sizes = []
     if parsed_ids:
@@ -85,13 +94,15 @@ async def create_order(
         file_rows = db.execute_query(f"SELECT file_size FROM order_files WHERE id IN ({format_strings})", tuple(parsed_ids))
         file_sizes = [r['file_size'] for r in file_rows]
 
-    estimated_price, item_prices = pricing.calculate_estimated_price(material_id, file_sizes, parsed_quantities if parsed_quantities else None, return_details=True)
+    estimated_price, item_prices, pricing_metadata = pricing.calculate_estimated_price(material_id, file_sizes, parsed_quantities if parsed_quantities else None, return_details=True)
 
     # Snapshoting initial parameters
     original_params = json.dumps({
         "material_name": mat_name,
         "material_price": float(mat_price) if mat_price is not None else 0.0,
-        "printer_hour_price": float(hour_price),
+        "printer_hour_price": float(pricing_metadata['price_per_hour']),
+        "speed_coeff": float(pricing_metadata['speed_coeff']),
+        "base_fee": float(pricing_metadata['base_fee']),
         "estimated_price": float(estimated_price) if estimated_price is not None else 0.0,
         "quantity": quantity,
         "color_name": color_name,
@@ -228,7 +239,7 @@ async def get_public_reviews():
 
 @router.post("/estimate")
 async def get_price_estimate(data: schemas.EstimateRequest):
-    estimated_total, file_prices = pricing.calculate_estimated_price(
+    estimated_total, file_prices, metadata = pricing.calculate_estimated_price(
         data.material_id, 
         data.file_sizes, 
         data.file_quantities, 

+ 9 - 2
backend/services/pricing.py

@@ -9,7 +9,7 @@ def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quan
     """
     material = db.execute_query("""
         SELECT m.price_per_cm3, 
-               COALESCE(m.price_per_hour, s.price_per_hour, %s) as price_per_hour,
+               COALESCE(NULLIF(m.price_per_hour, 0), s.price_per_hour, %s) as price_per_hour,
                m.speed_coeff
         FROM materials m
         LEFT JOIN services s ON m.service_id = s.id
@@ -45,6 +45,13 @@ def calculate_estimated_price(material_id: int, file_sizes: List[int], file_quan
         file_costs.append(file_cost)
         estimated_total += file_cost * qty
     
+    metadata = {
+        "price_per_cm3": price_per_cm3,
+        "price_per_hour": price_per_hour,
+        "speed_coeff": speed_coeff,
+        "base_fee": base_fee
+    }
+
     if return_details:
-        return round(estimated_total, 2), file_costs
+        return round(estimated_total, 2), file_costs, metadata
     return round(estimated_total, 2)

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

@@ -94,6 +94,18 @@
               <span class="text-[9px] font-bold uppercase text-primary/60 tracking-widest">{{ t("admin.fields.quantity") }}</span>
               <p class="text-2xl font-black text-primary">x{{ order.quantity || 1 }}</p>
             </div>
+            <!-- Pricing breakdown metadata -->
+            <div v-if="order.original_params" class="flex flex-col text-right">
+               <span class="text-[9px] font-bold uppercase text-primary/60 tracking-widest">{{ t("admin.fields.pricingFactors") }}</span>
+               <div class="flex gap-2 items-center justify-end">
+                 <div v-if="JSON.parse(order.original_params).speed_coeff" class="px-1.5 py-0.5 bg-primary/10 rounded text-[10px] font-bold text-primary">
+                    x{{ JSON.parse(order.original_params).speed_coeff }} {{ t("admin.fields.speedCoeffShort") }}
+                 </div>
+                 <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>
+            </div>
           </div>
         </div>
 

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

@@ -282,6 +282,18 @@
       "ru": "Коэф. времени (сложность)",
       "ua": "Коеф. часу (складність)"
     },
+    "speedCoeffShort": {
+      "en": "speed",
+      "me": "brzina",
+      "ru": "скорость",
+      "ua": "швидкість"
+    },
+    "pricingFactors": {
+      "en": "Pricing Factors",
+      "me": "Faktori cijene",
+      "ru": "Факторы цены",
+      "ua": "Фактори ціни"
+    },
     "projectNotes": {
       "en": "Project Notes",
       "me": "Napomene o projektu",

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

@@ -447,6 +447,18 @@
         "ru": "Коэф. времени (сложность)",
         "ua": "Коеф. часу (складність)"
       },
+      "speedCoeffShort": {
+        "en": "speed",
+        "me": "brzina",
+        "ru": "скорость",
+        "ua": "швидкість"
+      },
+      "pricingFactors": {
+        "en": "Pricing Factors",
+        "me": "Faktori cijene",
+        "ru": "Факторы цены",
+        "ua": "Фактори ціни"
+      },
       "projectNotes": {
         "en": "Project Notes",
         "me": "Napomene o projektu",