// MDM SORP — Dedup review & merge (6.7).
const { useState, useEffect, useMemo, useRef, useCallback, createContext, useContext } = React;
function DedupScreen({ navigate }) {
const { t, lang } = useI18n();
const toast = useToast();
const cands = [
{ id: "p_2002", short: "Schaeffler Middle East FZE", full: "Schaeffler Middle East FZE",
trn: "100229876500003", country: "AE", city: "Dubai (JAFZA)",
phone: "+971 4 805-1888", email: "sales.me@schaeffler.com",
created: "2024-08-14", source: "amo", conf: 0.93,
deals: 4, refs: 12, docs: 7 },
{ id: "p_2003", short: "Schaffler M.E. Trading LLC", full: "Schaffler M.E. Trading LLC",
trn: "100229876500003", country: "AE", city: "Dubai",
phone: "+971-4-805 1888", email: "trade@schaffler-me.com",
created: "2024-12-02", source: "drive", conf: 0.41,
deals: 1, refs: 3, docs: 2 },
];
const [survivor, setSurvivor] = useState("p_2002");
const [picks, setPicks] = useState({
short: "p_2002", full: "p_2002", trn: "p_2002", country: "p_2002",
city: "p_2002", phone: "p_2002", email: "both",
});
const fields = [
{ key: "short", label: lang === "ru" ? "Краткое имя" : "Short name" },
{ key: "full", label: lang === "ru" ? "Полное наименование" : "Full legal name" },
{ key: "trn", label: "TRN", mono: true, same: true },
{ key: "country", label: t("party_country") },
{ key: "city", label: t("party_address") },
{ key: "phone", label: t("party_phone"), mono: true },
{ key: "email", label: t("party_email"), special: ["both"] },
];
return (
{t("dedup_title")}
4 пары · 2 высокий приоритет
{/* Candidate pair indicator */}
Пара #1 из 4
·
Совпадение по TRN · ИИ confidence 94%
{/* Header row */}
{cands.map(c => (
{c.short}
{c.id} · создано {c.created}
Сделок{c.deals}
Связей{c.refs}
Документов{c.docs}
))}
Превью результата
Одна запись {cands.find(c => c.id === survivor)?.short}.
Перенесётся: 5 сделок · 15 связей · 9 документов.
Дубль помечается tombstone (откат 30 дней).
{/* Field-by-field rows */}
{fields.map(f => {
const v0 = cands[0][f.key] || "—";
const v1 = cands[1][f.key] || "—";
const same = v0 === v1;
return (
{f.label}
{!same && {t("dedup_conflict")}}
{same && }
{cands.map(c => (
setPicks(p => ({ ...p, [f.key]: c.id }))}>
{c[f.key] || "—"}
))}
{f.special?.includes("both") && picks[f.key] === "both"
? обе
: {cands.find(c => c.id === picks[f.key])?.[f.key] || cands.find(c => c.id === survivor)?.[f.key] || "—"}
}
{f.key === "email" && (
)}
);
})}
Что произойдёт после слияния
Сделки
Все ссылки deal.supplier и deal_item.supplier переадресуются на p_2002.
Документы
Drive-папка /Suppliers/Schaffler остаётся, индекс перемаппится.
Tombstone
p_2003 не удаляется. Запись остаётся в БД с флагом merged_into=p_2002.
Откат
30 дней через журнал · «Восстановить запись». Все связи откатываются обратно.
);
}
window.DedupScreen = DedupScreen;