Files
tilbudgivern/docs/features/MARKUP_SLIDER_SYSTEM.md
alexpolo1 4a372d2e28 clean up
2025-10-30 18:28:58 +00:00

6.5 KiB

Markup Slider System for SmartPackages

📊 Oversigt

SmartPackage systemet understøtter nu to niveauer af markup som kan justeres individuelt for hvert tilbud:

1. Material Markup Slider 💰

  • Standard: 20%
  • Justerbar: 0% - 50%
  • Placering: Ved tilføjelse af SmartPackage til tilbud
  • Anvendelse: Påføres alle materialer fra pakken
  • Gemt i: quotes.material_markup_percent

2. Final Review Markup Slider 📈

  • Standard: 2%
  • Justerbar: 0% - 10%
  • Placering: I final review trinnet
  • Anvendelse: Påføres på subtotal (materialer + arbejde)
  • Gemt i: quotes.final_review_markup_percent

🔧 Database Struktur

Nye felter i quotes tabel:

ALTER TABLE quotes 
  ADD COLUMN material_markup_percent DECIMAL(5,2) DEFAULT 20.00 
    COMMENT 'Material markup procent (standard 20%)',
  ADD COLUMN final_review_markup_percent DECIMAL(5,2) DEFAULT 2.00 
    COMMENT 'Final review markup procent (standard 2%)';

🔌 API Endpoint

POST /api/smart-packages/:id/calculate-with-geometry

Request body:

{
  "projectId": 123,              // Optional: Hent geometri og markup fra database
  "geometry": {                  // Optional: Brug custom geometri
    "length_main": 15,
    "width_main": 10,
    "total_area": 85,
    "nedløb_antal": 4
  },
  "materialMarkupPercent": 20,   // Optional: Override material markup
  "finalReviewMarkupPercent": 2  // Optional: Override final review markup
}

Response:

{
  "success": true,
  "package": {
    "id": 97,
    "name": "Tagrende med Konsoljern"
  },
  "materials": [
    {
      "varenr": "077424",
      "name": "Tagrende 3m",
      "quantity": 5,
      "base_price": 150.00,      // Indkøbspris
      "price": 180.00,           // Med markup (150 * 1.20)
      "markup_percent": 20
    }
  ],
  "markup": {
    "material_markup_percent": 20,
    "final_review_markup_percent": 2,
    "final_review_amount": 87.00
  },
  "totals": {
    "material_cost": 900.00,     // Med material markup
    "labor_cost": 4350.00,
    "subtotal": 5250.00,
    "final_review_markup": 87.00,  // 2% af subtotal
    "total_cost": 5337.00        // Alt inkluderet
  }
}

💡 Beregningseksempler

Eksempel 1: Standard (20% + 2%)

Materialer (indkøb): 750 kr
+ Material markup (20%): +150 kr
= Materialer til kunde: 900 kr

Arbejde: 4350 kr
─────────────────────────
Subtotal: 5250 kr
+ Final review markup (2%): +105 kr
═════════════════════════
TOTAL: 5355 kr

Eksempel 2: Lav margin (10% + 1%)

Materialer (indkøb): 750 kr
+ Material markup (10%): +75 kr
= Materialer til kunde: 825 kr

Arbejde: 4350 kr
─────────────────────────
Subtotal: 5175 kr
+ Final review markup (1%): +51.75 kr
═════════════════════════
TOTAL: 5226.75 kr

Eksempel 3: Høj margin (30% + 5%)

Materialer (indkøb): 750 kr
+ Material markup (30%): +225 kr
= Materialer til kunde: 975 kr

Arbejde: 4350 kr
─────────────────────────
Subtotal: 5325 kr
+ Final review markup (5%): +266.25 kr
═════════════════════════
TOTAL: 5591.25 kr

🎨 UI Implementation Guide

1. Material Markup Slider

Placering: Når bruger tilføjer SmartPackage til tilbud

<div className="markup-control">
  <label>Material Markup</label>
  <input 
    type="range" 
    min="0" 
    max="50" 
    value={materialMarkup}
    onChange={(e) => setMaterialMarkup(e.target.value)}
  />
  <span>{materialMarkup}%</span>
  <p className="help-text">
    Avance  materialer (standard: 20%)
  </p>
</div>

Når skal den vises:

  • Ved tilføjelse af SmartPackage til tilbud
  • I tilbudsredigering
  • Som standard værdi ved oprettelse af nyt tilbud

2. Final Review Markup Slider

Placering: I final review trinnet før tilbuddet sendes

<div className="final-markup-control">
  <label>Final Review Markup</label>
  <input 
    type="range" 
    min="0" 
    max="10" 
    step="0.1"
    value={finalReviewMarkup}
    onChange={(e) => setFinalReviewMarkup(e.target.value)}
  />
  <span>{finalReviewMarkup}%</span>
  <p className="help-text">
    Ekstra margin  total pris (standard: 2%)
  </p>
  
  <div className="markup-preview">
    <p>Subtotal: {formatCurrency(subtotal)}</p>
    <p>Final markup (+{finalReviewMarkup}%): {formatCurrency(finalMarkupAmount)}</p>
    <p className="total">Total: {formatCurrency(total)}</p>
  </div>
</div>

Når skal den vises:

  • I final review trinnet
  • Kun hvis brugeren vil justere den
  • Kan være skjult bag "Avancerede indstillinger"

📝 Workflow

Trin 1: Opret tilbud

// Når tilbud oprettes, sæt default markup værdier
const newQuote = {
  customer_name: "Kunde Navn",
  material_markup_percent: 20.00,  // Default
  final_review_markup_percent: 2.00 // Default
};

Trin 2: Tilføj SmartPackage

// Bruger kan justere material markup
const addPackageResponse = await axios.post(
  `/api/smart-packages/97/calculate-with-geometry`,
  {
    projectId: quoteId,
    materialMarkupPercent: 25  // Bruger satte 25%
  }
);

// Gem i quote
await axios.put(`/api/quotes/${quoteId}`, {
  material_markup_percent: 25
});

Trin 3: Final Review

// Bruger kan justere final review markup
const updateFinalMarkup = async (newMarkup) => {
  await axios.put(`/api/quotes/${quoteId}`, {
    final_review_markup_percent: newMarkup
  });
  
  // Genberegn totals
  await recalculateTotals();
};

Test

Kør test script:

node test-markup-sliders.js

Dette tester 4 scenarier:

  1. Standard (20% + 2%)
  2. Lav margin (10% + 1%)
  3. Høj margin (30% + 5%)
  4. Ingen final markup (20% + 0%)

🔄 Næste Skridt

  1. Frontend Implementation

    • Tilføj material markup slider ved package tilføjelse
    • Tilføj final review markup slider i review trin
    • Vis markup breakdown tydeligt i UI
  2. Quote Management

    • Gem markup værdier når quote opdateres
    • Hent markup værdier når quote loades
    • Vis aktuel markup i quote oversigt
  3. Material Import

    • Import Bygma materialer med korrekte indkøbspriser
    • Så markup kan beregnes på reelle priser
  4. Rapportering

    • Vis markup breakdown i PDF tilbud
    • Vis profit margin i analytics
    • Track gennemsnitlig markup per kunde/projekt