Ana içeriğe atla
ActivityDefinition’lar bir aktivitenin nasıl toplanacağını ve hesaplanacağını tanımlar. Her tanım; giriş şeması, hesaplama fonksiyonu ve React UI bileşeninden oluşur ve birden fazla form/site’da yeniden kullanılabilir.

Hızlı Başlangıç

  1. Yeni ActivityDefinition oluşturun (Özelleştirme → Activity Definitions → New)
  2. Girişleri tanımlayın (manuel veya Smart CSV ile)
  3. Hesaplama kodunu yazın ({ value, metadata } döndüren async fonksiyon)
  4. UI’yi oluşturun (ActivityUIonAddActivity(values) çağırır)
  5. Test bağlamı ile önizleyin → Kaydedin
Minimal hesaplama şablonu:
async function calculate(inputValues) {
  const { electricityKwh = 0, gridRegion } = inputValues;
  const ef =
    (await $datasets.getCoefficient(
      "grid-emission-factors",
      String(gridRegion || "").toLowerCase(),
      "kgCO2ePerKWh",
      $year,
    )) ?? 0;
  return { value: electricityKwh * ef, metadata: { gridRegion, ef, year: $year } };
}
Minimal UI şablonu:
function ActivityUI({ onAddActivity }) {
  const [values, setValues] = React.useState({ electricityKwh: 0, gridRegion: "" });
  const handleAddActivity = () => onAddActivity(values);
  return (
    <div className="space-y-3">
      <NumberInput label="Elektrik (kWh)" value={values.electricityKwh}
        onChange={(v) => setValues((s) => ({ ...s, electricityKwh: Number(v ?? 0) }))} min={0} />
      <DatasetItemSelector datasetName="grid-emission-factors" value={values.gridRegion || null}
        onChange={(opt) => setValues((s) => ({ ...s, gridRegion: opt?.name ?? "" }))}
        placeholder="Bölge arayın…" />
      <Button onClick={handleAddActivity}>Aktivite Ekle</Button>
    </div>
  );
}

Neleri İçerir?

  • Giriş şeması: UI’nin toplaması gereken tipli, zorunlu/opsiyonel alanlar
  • Hesaplama kodu: sayısal bir değer ve meta veriyi üreten async JS fonksiyonu
  • UI kodu: kullanıcıların değer girdiği React bileşeni

Giriş Şeması

Aşağıdaki sade şema uygulama genelinde kullanılır (doğrulama, UI oluşturma, CSV tahmini vb.):
const inputs = [
  { name: "electricityKwh", type: "number", required: true, example: 1200 },
  { name: "gridRegion", type: "string", required: true, example: "Türkiye" },
  { name: "notes", type: "string", required: false, example: "sayaç 3" },
];
Tipler: "number" | "string". Her girişte name, type, required ve opsiyonel example bulunur.

Girdi Adlandırma Rehberi

  • camelCase kullanın (ör.: fuelType, electricityKwh).
  • Boşluk/özel karakterlerden kaçının. Smart CSV başlıkları otomatik olarak camelCase’e temizler.
  • İsimleri stabil tutun; dışa aktarımdaki sütunlar bu isimlerle gelir.
  • example değerleri tespiti ve önizlemeyi iyileştirir.

Hesaplama Kodu

Hesaplama, tam bir fonksiyon deklarasyonu olarak kaydedilir ve mutlaka { value, metadata } döndürür.
// Gerekli format:
// async function calculate(inputValues) { /* ... */ }
async function calculate(inputValues) {
  const { electricityKwh, gridRegion } = inputValues;

  if (electricityKwh == null || electricityKwh < 0) {
    throw new Error("electricityKwh sıfırdan büyük eşit olmalıdır");
  }

  // Fonksiyon içinde mevcut bağlam yardımcıları:
  // $datasets, $kpis, $sites, $year, $period (YEARLY|QUARTERLY|MONTHLY), $periodUnit, $siteId
  const factor = await $datasets.getCoefficient(
    "grid-emission-factors",
    gridRegion,
    "kgCO2ePerKWh",
    $year,
  );

  const ef = factor ?? 0;
  const value = electricityKwh * ef;

  return {
    value,
    metadata: { gridRegion, factor: ef, year: $year },
  };
}
Sunucu, value ve sayısal meta verideki NaN/Infinity değerlerini 0’a çevirir. Giriş doğrulama hatalarında anlaşılır Error mesajları fırlatın (UI bunları kullanıcıya gösterir).

UI Bileşeni

UI, tek prop alan ActivityUI adlı bir React bileşenidir: onAddActivity(values). Kullanıcı gönderdiğinde bu fonksiyon çağrılır.
function ActivityUI({ onAddActivity }: { onAddActivity: (values: any) => void }) {
  const [values, setValues] = React.useState({ electricityKwh: 0, gridRegion: "" });

  return (
    <div className="space-y-3">
      <NumberInput
        label="Elektrik (kWh)"
        value={values.electricityKwh}
        onChange={(v) => setValues((s) => ({ ...s, electricityKwh: Number(v ?? 0) }))}
        min={0}
      />
      <DatasetItemSelector
        datasetName="grid-emission-factors"
        value={values.gridRegion || null}
        onChange={(opt) => setValues((s) => ({ ...s, gridRegion: opt?.name ?? "" }))}
        placeholder="Bölge arayın…"
      />
      <Button onClick={() => onAddActivity(values)}>Aktivite Ekle</Button>
    </div>
  );
}
Notlar
  • Bir giriş, bilinen bir dataset’ten seçimi ifade ediyorsa DatasetItemSelector kullanın (hesaplama kodundaki dataset adıyla aynı olmalıdır).
  • UI ve hesaplama kodunu taslak/iyileştirme için AI yardımcısı mevcuttur; kodu her zaman manuel düzenleyebilirsiniz.

UI Kod Sözleşmesi

  • Snippet içinde function ActivityUI({ onAddActivity }) { ... } tanımlayın.
  • Tıklama ile gönderin: onClick={handleAddActivity}; varsayılan form submit akışını kullanmayın.
  • İçe aktarma yok; kapsamda sunulan bileşenleri kullanın (Mantine ve DatasetItemSelector).
  • Canlı çalışma zamanı için bileşeni bağımsız tutun.

Akıllı CSV Girdi Tespiti

Yeni bir tanım oluştururken CSV örneğinden girişleri hızlıca çıkartabilirsiniz:
  • Yeni Activity Definition sayfasında “Smart” sekmesine bir CSV dosyası yükleyin.
  • Sistem başlık ve örnek satırlardan alan adlarını/tiplerini ve örnek değerleri çıkarır.
  • Üretilen “AI notları” UI oluşturmayı besleyebilir. Sonrasında Manuel sekmeye geçip düzenleyebilirsiniz.
Bu akış, yukarıdaki şemayı doldurur; sadece name, type, required ve opsiyonel example alanları desteklenir.

Önizleme ve Test Bağlamı

Hesaplama ve UI sekmelerinde gerçek verilerle önizleme yapabilirsiniz:
  • Hesaplama önizlemesi, dataset/KPI/site erişimini güvenli sunucu API’leri üzerinden kullanır.
  • Test bağlamını ayarlayın: year, period (YEARLY/QUARTERLY/MONTHLY), periodUnit, siteId.
  • Hesaplamada yapılan dataset/KPI/site çağrılarında await kullanılmalıdır.

Genel/Özel Tanımlar

  • Özel (varsayılan): yalnızca organizasyonunuza görünür.
  • Genel (isCommon): tüm organizasyonlara açık. Genel tanım oluşturmak için ADMIN rolü gerekir.

Hesaplamada Kullanılabilen Yardımcılar

  • $datasets: getItem, getDataset, getCoefficient, getCoefficients
  • $kpis: getIndicator, getIndicatorById, getAllIndicators, getIndicatorsByTag, getIndicatorVariables
  • $sites: getSite, getSiteByName, getAllSites, getChildSites, getSitesByCity, getSitesByTag, getTotalFloorArea, getTotalEmployees
  • $year, $period, $periodUnit, $siteId
Tüm erişimler güncel organizasyon bağlamında satır düzeyi güvenlikle kısıtlanır.

Form Entegrasyonu

  • ACTIVITY form elementi ekleyip bir ActivityDefinition ile ilişkilendirin.
  • Elementin key değeri, bu tanım için aktivite ekleme/ithal/yeniden hesaplama işlemlerinde kullanılır.
  • UI kodu inline render edilir ve onAddActivity(values) çağırarak hesaplama sonrası yeni bir Activity oluşturur.
İş akışı
  • Onay gerektiren iş akışında, ilgili periyottaki gönderimler COMPLETED olur; aksi halde kayıtlar anında APPROVED durumundadır.

Ne Zaman Yeniden Hesaplamalı?

  • Hesaplama mantığını güncelledikten sonra mevcut aktiviteleri hizalamak için toplu yeniden hesaplama (activities.recalculateActivities) kullanın (site/yıl/periyot filtreleri ile).
  • Hesaplamada kullanılan dataset’ler değiştiyse ilgili periyotlar için yeniden hesaplayın.

İyi Uygulamalar

  • Girişleri erken doğrulayın ve anlaşılır hata mesajları fırlatın.
  • Her zaman { value: number, metadata: Record<string, any> } dönün.
  • Dataset adlarını UI ve hesaplama kodunda tutarlı kullanın.
  • Mümkünse meta veride sayısal değerleri tercih edin (grafik/filtrelerde kolaylık sağlar).
  • Örnek değerler (example) UI/CSV tespitini ve ön izlemeyi iyileştirir.
2. Şema Tasarımı: Giriş/çıktı veri yapılarını tanımlayın 3. Mantık Geliştirme: Hesaplama fonksiyonunu yazın ve test edin 4. UI Tasarımı: Kullanıcı deneyimini optimize edin 5. Test ve Doğrulama: Çeşitli veri setleriyle test edin 6. Dağıtım: Organizasyon genelinde kullanım için yayınlayın

Operasyonel Notlar

Tutarlılık: Aynı hesaplama mantığı tüm kullanımlarda aynı sonuçları sağlar Verimlilik: Hesaplama mantığını yeniden yazmak yerine yeniden kullanın Kalite: Anlaşılır doğrulama ve meta verilerle ölçülebilirlik Uyumluluk: Standart hesaplama yöntemlerini uygulayın Şeffaflık: Hesaplama fonksiyonu ve metadata, varsayımları görünür kılar

Sorun Giderme

  • “Function parse failed” → Tam async function calculate(inputValues) { ... } kaydettiğinizden emin olun.
  • dönmeli” → { value: number, metadata: object } döndürün.
  • “Eksik dataset öğesi” → Yedek kullanın: const ef = (await $datasets.getCoefficient(...)) ?? 0.
  • NaN/Infinity → Sayısal girdileri doğrulayın; sunucu 0’a normalleştirir fakat kök nedeni düzeltin.
  • Erişim hatası → Site erişimi/filtreleri kontrol edin.

Performans İpuçları

  • Çoklu katsayım için $datasets.getCoefficients(dataset, $year) ile tek seferde alın ve tekrar kullanın.
  • Sık döngülerde tekrar tekrar await kullanmaktan kaçının.
  • Metadata’yı kısa tutun; yalnız gerektiğinde detaylandırın.

Metadata Kuralları

  • Birimler ve kaynakları ekleyin (ör.: emissionFactorKgCO2ePerKWh, factorSource: "EPA").
  • Sayısal alanları sayısal tutun; metinleri etiket/kimlik için kullanın.