#include "istakip_sema.hpp" #include #include #include "fiko/istakip/istemci.hpp" #include "fiko/istakip/model.hpp" #include "istakip_servis.hpp" #include "simdjson.h" namespace fiko { namespace { namespace sj = simdjson; using istakip::IsKayit; const char* alanDeger(const IsKayit& k, const char* ad) { const char* v = istakip::alanBul(k, ad); return v ? v : ""; } std::string sStr(sj::ondemand::object& o, const char* alan, const char* vars = "") { std::string_view sv; if (o[alan].get_string().get(sv) == sj::SUCCESS) return std::string(sv); return vars; } bool sBool(sj::ondemand::object& o, const char* alan, bool vars = false) { bool b; if (o[alan].get_bool().get(b) == sj::SUCCESS) return b; return vars; } // alan_semasi JSON dizisini çöz → AlanSema listesi. Boş/bozuk JSON = boş liste // (kayıt hâlâ görünür kalır, yalnız alansız — sessiz bozulma, çökme yok). std::vector alanlarCoz(const std::string& json) { std::vector out; if (json.empty()) return out; sj::ondemand::parser parser; sj::padded_string dolu(json); sj::ondemand::document doc; if (parser.iterate(dolu).get(doc) != sj::SUCCESS) return out; sj::ondemand::array arr; if (doc.get_array().get(arr) != sj::SUCCESS) return out; for (auto val : arr) { sj::ondemand::object o; if (val.get_object().get(o) != sj::SUCCESS) continue; AlanSema a; a.ad = sStr(o, "ad"); a.etiket = sStr(o, "etiket"); a.tip = sStr(o, "tip", "metin"); a.tabloda = sBool(o, "tablo", true); if (!a.ad.empty()) out.push_back(std::move(a)); } return out; } // durum_semasi JSON dizisini çöz → string listesi. std::vector durumlarCoz(const std::string& json) { std::vector out; if (json.empty()) return out; sj::ondemand::parser parser; sj::padded_string dolu(json); sj::ondemand::document doc; if (parser.iterate(dolu).get(doc) != sj::SUCCESS) return out; sj::ondemand::array arr; if (doc.get_array().get(arr) != sj::SUCCESS) return out; for (auto val : arr) { std::string_view sv; if (val.get_string().get(sv) == sj::SUCCESS) out.emplace_back(sv); } return out; } TurSema kayitToTurSema(const IsKayit& k) { TurSema t; t.tur_id = alanDeger(k, "tur_id"); t.ikon = alanDeger(k, "ikon"); t.baslik = alanDeger(k, "baslik"); t.tekil = alanDeger(k, "tekil"); t.renk = alanDeger(k, "renk"); t.bag_tur = alanDeger(k, "bag_tur"); t.alanlar = alanlarCoz(alanDeger(k, "alan_semasi")); t.durumlar = durumlarCoz(alanDeger(k, "durum_semasi")); const char* ka = alanDeger(k, "kanban_alan"); t.kanban_alan = ka[0] ? ka : "durum"; const char* kb = alanDeger(k, "kanban_baslik"); t.kanban_baslik = kb[0] ? kb : "Durum"; const char* s = alanDeger(k, "sira"); t.sira = s[0] ? std::atoi(s) : 0; return t; } // JSON dize kaçışı — F2'de kullanıcı serbest metin yazacak, şimdiden güvenli. std::string jsonKacir(const std::string& s) { std::string o; o.reserve(s.size() + 8); for (char c : s) { switch (c) { case '"': o += "\\\""; break; case '\\': o += "\\\\"; break; case '\n': o += "\\n"; break; case '\r': o += "\\r"; break; case '\t': o += "\\t"; break; default: o += c; } } return o; } std::string alanlarSerialize(const std::vector& alanlar) { std::string j = "["; for (size_t i = 0; i < alanlar.size(); ++i) { if (i) j += ","; const auto& a = alanlar[i]; j += "{\"ad\":\"" + jsonKacir(a.ad) + "\",\"etiket\":\"" + jsonKacir(a.etiket) + "\",\"tip\":\"" + jsonKacir(a.tip) + "\",\"tablo\":" + (a.tabloda ? "true" : "false") + "}"; } j += "]"; return j; } std::string durumlarSerialize(const std::vector& durumlar) { std::string j = "["; for (size_t i = 0; i < durumlar.size(); ++i) { if (i) j += ","; j += "\"" + jsonKacir(durumlar[i]) + "\""; } j += "]"; return j; } // Varsayılan (geriye dönük uyumlu) 5 tür — eski kod-sabit turlar()'ın taşınmışı. // "_sema" kaydı hiç yokken UI bunu döner; ilkKurulumSemalariYaz bunu birebir // "_sema" kaydına yazar (yalnız kaynak değişir, tur/alan adları AYNI kalır — // mevcut musteri/teklif/siparis/is_emri kayıtları hiç bozulmaz). const std::vector& varsayilanTurler() { static const std::vector t = { {"musteri", "👥", "Müşteriler", "Müşteri", "#8892A0", "", {{"ad", "Ad / Ünvan", "metin", true}, {"telefon", "Telefon", "metin", true}, {"eposta", "E-posta", "metin", true}, {"adres", "Adres", "metin", false}, {"not", "Not", "metin", false}}, {}, 10}, {"teklif", "📄", "Teklifler", "Teklif", "#4C9BE8", "", {{"baslik", "Başlık", "metin", true}, {"musteri", "Müşteri", "metin", true}, {"tutar", "Tutar", "para", true}, {"termin", "Termin", "tarih", true}, {"not", "Not", "metin", false}}, {"taslak", "gönderildi", "onaylandı", "reddedildi"}, 20}, {"siparis", "📦", "Siparişler", "Sipariş", "#4C9BE8", "teklif", {{"baslik", "Başlık", "metin", true}, {"musteri", "Müşteri", "metin", true}, {"tutar", "Tutar", "para", true}, {"termin", "Termin", "tarih", true}, {"not", "Not", "metin", false}}, {"yeni", "üretimde", "sevkiyat", "tamamlandı"}, 30}, {"is_emri", "🛠", "İş Emirleri", "İş Emri", "#E8A34C", "siparis", {{"baslik", "Başlık", "metin", true}, {"atanan", "Atanan", "metin", true}, {"oncelik", "Öncelik", "metin", true}, {"termin", "Termin", "tarih", true}, {"dosya", "Belge", "metin", false}, {"not", "Not", "metin", false}}, {"bekliyor", "üretimde", "kalite", "tamamlandı"}, 40}, {"istemci_rol", "🔐", "Erişim", "Erişim Kaydı", "#8892A0", "", {{"no", "İstemci No", "metin", true}, {"ad", "Makine / Kullanıcı", "metin", true}, {"not", "Not", "metin", false}}, {"izleyici", "operatör"}, 999}, }; return t; } std::vector g_semaCache; uint64_t g_semaCacheSurum = ~0ull; } // namespace const std::vector& turlarOku(const istakip::IsIstemci& veri) { const auto semalar = veri.turListe("_sema"); if (semalar.empty()) return varsayilanTurler(); if (veri.sonSurum() != g_semaCacheSurum) { std::vector out; out.reserve(semalar.size()); for (const IsKayit* k : semalar) out.push_back(kayitToTurSema(*k)); std::sort(out.begin(), out.end(), [](const TurSema& a, const TurSema& b) { return a.sira < b.sira; }); g_semaCache = std::move(out); g_semaCacheSurum = veri.sonSurum(); } return g_semaCache; } void ilkKurulumSemalariYaz(IstakipServis& servis) { if (!servis.kralMi()) return; // yalnız kral yazar (çoklu istemci yarış koşulu önlenir) const istakip::IsIstemci* veri = servis.veri(); if (!veri) return; if (!veri->turListe("_sema").empty()) return; // zaten kurulu for (const TurSema& t : varsayilanTurler()) servis.yaz(semaKayitYaz(t)); } TurSema semaKayitOku(const istakip::IsKayit& kayit) { return kayitToTurSema(kayit); } istakip::IsKayit semaKayitYaz(const TurSema& t, uint64_t kimlik) { IsKayit k; k.kimlik = kimlik; k.tur = "_sema"; istakip::alanAta(k, "tur_id", t.tur_id); istakip::alanAta(k, "ikon", t.ikon); istakip::alanAta(k, "baslik", t.baslik); istakip::alanAta(k, "tekil", t.tekil); istakip::alanAta(k, "renk", t.renk); istakip::alanAta(k, "bag_tur", t.bag_tur); istakip::alanAta(k, "alan_semasi", alanlarSerialize(t.alanlar)); istakip::alanAta(k, "durum_semasi", durumlarSerialize(t.durumlar)); istakip::alanAta(k, "kanban_alan", t.kanban_alan.empty() ? "durum" : t.kanban_alan); istakip::alanAta(k, "kanban_baslik", t.kanban_baslik.empty() ? "Durum" : t.kanban_baslik); istakip::alanAta(k, "sira", std::to_string(t.sira)); return k; } } // namespace fiko