Zoho CRM Systemdokumentation

Komplet teknisk dokumentation af Forbrugsforeningens Zoho CRM-opsætning, automatiseringer og integrationer.

Systemoversigt

Forbrugsforeningens Zoho CRM-system er opbygget omkring følgende kernemoduler:

ModulTypeFormål
PartnereCustomSamarbejdsaftaler med butikker/virksomheder
KæderCustomGrupper af butikker med fælles ejerskab
OrganisationerStandardFagforeninger, butikker, foreninger m.m.
KontakterStandardKontaktpersoner til organisationer og partnere
EjerskaberCustomEjerskabsforhold
ValggrupperCustomSimpelt grupperingsmodul

Nøgleintegrationer

API

CVR Integration

cvrintegration.dk

Automatisk opslag af danske CVR-data og EU VIES-validering ved oprettelse/redigering af records.

API

Loyalty Solutions

fbf-loyaltfacts-api.loyaltfacts.com

Synkronisering af partnere og kæder til Loyalty Solutions-platformen (opret, opdater, bonussats, vederlag).

API

Business Central

smartapiservice.azurewebsites.net

Synkronisering af kundeposter (Customer) til Microsoft Dynamics 365 Business Central via SMART API.

AI

OpenAI GPT

api.openai.com

Genererer brugervenlige fejlbeskeder når LS-overførsler fejler. Bruges i "Fejl i Overførelse"-workflowet.

Modulrelationer

Oversigt over lookup-felter og relationer mellem moduler.

Fra modulFeltTil modulFelttypeBeskrivelse
PartnereKædeKæderLookupHvilken kæde partneren tilhører
PartnerePrimær KontaktpersonKontakterLookupPrimær kontaktperson for partneren
PartnereFBF AnsvarligUsersBrugerIntern ansvarlig medarbejder
PartnereTilsluttet tilMulti-modulMulti-lookupMultimodul-opslag
KæderFBF AnsvarligUsersBrugerIntern ansvarlig medarbejder
KæderKæde EjerOrganisationerLookupKædens overordnede ejerorganisation
KæderTilsluttet tilMulti-modulMulti-lookupMultimodul-opslag
KontakterOrganisations NavnOrganisationerLookupTilknyttet organisation
KontakterPartner NavnPartnereLookupTilknyttet partner
KontakterKædeKæderLookupTilknyttet kæde
KontakterEjerskabEjerskaberLookupTilknyttet ejerskab
OrganisationerFædre OrganisationOrganisationerSelf-lookupOverordnet organisation
OrganisationerFusioneres Sammen MedOrganisationerSelf-lookupOrganisation der fusioneres med
OrganisationerTilsluttet tilMulti-modulMulti-lookupMultimodul-opslag
EjerskaberPrimær KontaktpersonKontakterLookupPrimær kontaktperson
EjerskaberFBF AnsvarligUsersBrugerIntern ansvarlig medarbejder
EjerskaberTilsluttet tilMulti-modulMulti-lookupMultimodul-opslag
ValggrupperTilsluttet tilMulti-modulMulti-lookupMultimodul-opslag

Integrationer i detaljer

1. CVR Integration (cvrintegration.dk)

Bruges både som client script (frontend) og Deluge workflow (backend) til automatisk opslag af virksomhedsdata.

Funktionalitet

  • Dansk CVR-opslag: Indtastes et 8-cifret CVR-nummer eller "DK"+nummer, slås stamdata op (navn, adresse, branche, finansdata, bestyrelsesmedlemmer, direktører).
  • EU VIES-validering: Indtastes et udenlandsk VAT-nummer (f.eks. SE+nummer), valideres det via VIES og basisdata hentes.
  • Automatisk kontaktoprettelse: Ved oprettelse af Partner via workflow oprettes kontakter for direktører og bestyrelsesmedlemmer automatisk.

Anvendes i moduler

ModulClient Script (frontend)Workflow (backend)
PartnereOpret, Rediger (OnChange), KlonOprettelse Regel-1, Redigering Regel-1
OrganisationerOpret, Rediger, KlonCVR-workflows (identisk logik)
EjerskaberOpret, Rediger (OnChange), KlonOprettelse + Redigering (identisk logik)
Kontakter -Oprettelse + Redigering (CVR-integration for kontakter)

Dataflow

1
Bruger indtaster CVR/VAT-nummer i feltet CVR/VAT Nr.
2
Client script (frontend) kalder CVR API og udfylder felter i realtid
3
Ved gem kører workflow (backend) som validerer og gemmer data serverside + opretter kontakter

2. Loyalty Solutions (LS)

Hovedintegration til partnerhåndtering. Synkroniserer partnere (merchants) og kæder (chains) til LS-platformen.

API Endpoints

HandlingMetodeEndpoint
Opret partnerPOST/merchants
Opdater partnerPATCH/merchants/{internalMerchantId}
Opret kædePOST/chains
Opdater kædePATCH/chains/{internalChainId}

Synkroniseringslogik

  • Ved oprettelse sendes alle felter. LS returnerer et internt ID som gemmes på CRM-recorden (Internal Merchant ID / Internal Chain ID).
  • Ved opdatering sammenlignes gammel data med aktuelle data. Kun ændrede felter sendes via PATCH.
  • Ved fejl gemmes fejlbesked i feltet Loyalty Solutions Fejlbesked og status sættes til "Afvist af LS".
  • Bonussats og vederlagssats kan planlægges til fremtidig dato via Skift Bonussats Dato / Skift Vederlagssats Dato.

Connection

Alle LS-kald benytter Zoho-forbindelsen loyalty solutions.

3. Business Central (BC)

Opretter og synkroniserer kundedata (Customer) til Microsoft Dynamics 365 Business Central via SMART API.

API Endpoints

HandlingMetodeURL-mønster
Opret kundePOSTsmartapiservice.azurewebsites.net/SMARTapi/post/.../Customer
Hent kundeGETsmartapiservice.azurewebsites.net/SMARTapi/get/...?filter=(No.={debitor})
Opdater kundePUTsmartapiservice.azurewebsites.net/SMARTapi/put/...?filter=(No.={debitor})

Felter ved oprettelse af debitor (POST)

Når en partner eller kæde oprettes i CRM og ikke har et Debitor Nummer, genereres et nyt nummer automatisk og en BC-kunde oprettes via POST. Følgende felter sendes:

BC-feltCRM-felt (Partnere)CRM-felt (Kæder)
No.Auto-genereret debitornummer
NamePartnernavnKæde Navn
AddressAdresse 3 - Gade -> Adresse 2 - Gade -> GadeGade
CityAdresse 3 - By -> Adresse 2 - By -> ByBy
Post CodeAdresse 3 - Postnummer -> Adresse 2 - Postnummer -> PostnummerPostnummer
Country/Region CodeAdresse 3 - Land -> Adresse 2 - Land -> LandLand
Phone No.TelefonTelefon
E-MailEmailEmail
VAT Registration No.CVR/VAT Nr.CVR Nr.
Payment Terms Code"KONTANT" (fast værdi)
Customer Posting Group"DEB" (fast værdi)
Gen. Bus. Posting Group"DANMARK" (fast værdi)
VAT Bus. Posting Group"DANMARK" (fast værdi)

Bemærk: Efter oprettelse bekræftes kunden via GET, og tomme CRM-felter beriges med data fra BC (adresse, telefon, email, navn m.fl.).

Felter ved løbende synkronisering (PUT)

Når en partner eller kæde redigeres og Debitor Nummer er udfyldt, synkroniseres ændrede felter til BC via PUT. Kun felter der er ændret siden sidste sync sendes (change detection via BC Record Data).

BC-feltCRM-felt (Partnere)CRM-felt (Kæder)
NamePartnernavnKæde Navn
AddressAdresse 3 - Gade -> Adresse 2 - Gade -> GadeGade
CityAdresse 3 - By -> Adresse 2 - By -> ByBy
Post CodeAdresse 3 - Postnummer -> Adresse 2 - Postnummer -> PostnummerPostnummer
Country/Region CodeAdresse 3 - Land -> Adresse 2 - Land -> LandLand
Phone No.TelefonTelefon
E-MailEmailEmail
VAT Registration No.CVR/VAT Nr.CVR Nr.

4. OpenAI GPT (Fejlhåndtering)

Bruges i workflowet "Fejl i Overførelse af Partner" til at oversætte tekniske LS-fejlbeskeder til brugervenligt dansk.

  • Model: GPT-5
  • Trigger: Når feltet Loyalty Solutions Fejlbesked ændres til ikke-tom værdi
  • Output: Brugervenlig besked gemmes i Chat Message (maks 255 tegn)
  • Visning: Client scriptet "Vis Fejlbesked" viser beskeden som en fejl-popup på detaljesiden

Modul: Partnere

Partnere repræsenterer samarbejdsaftaler og overordnede relationer med butikker og virksomheder. Modulet adskiller sig fra Kontakter ved at fokusere på forretningsrelationen, ikke den specifikke person.

Partner Oplysninger

FeltTypeBeskrivelse
Partner NavnEnkelt linjePartnernavn / virksomhedsnavn
FBF AnsvarligBrugerIntern ansvarlig for denne partner
CVR/VAT Nr.Enkelt linjeCVR-nummer (DK) eller VAT-nummer (EU). Låses efter oprettelse.
Primær KontaktpersonLookup (Kontakter)Primær kontaktperson
KædeLookup (Kæder)Tilknyttet kæde
Partner StatusPluklisteAktiv, Lukket, Afvist af LS m.fl.
TelefonTelefonVirksomhedens telefonnummer
HjemmesideURLVirksomhedens hjemmeside
PartnernummerNummerUnikt partnernummer (sættes automatisk til record-ID)
EmailE-mailKontakt-email
Tilsluttet tilMultimodul-opslagMultimodul-reference

CVR Data

FeltTypeKilde
SelskabstypeEnkelt linjeCVR API
P-nummerEnkelt linjeCVR API
BranchekodeEnkelt linjeCVR API
BranchetekstEnkelt linjeCVR API
Virksomheds StatusEnkelt linjeCVR API
MedarbejdereNummerCVR API

Finansielle data

FeltTypeKilde
Regnskabsdata fra årNummerCVR API
BruttofortjenesteNummerCVR API
Årets resultatNummerCVR API
EgenkapitalNummerCVR API
StatusbalanceNummerCVR API
Seneste RegnskabURLCVR API (link til PDF)
BonussatsProcentManuelt / fra Kæde
VederlagssatsProcentManuelt / fra Kæde

Adresser

Partnere har op til 3 adresser:

  • Adresse 1 (CVR-registreret): Gade, Postnummer, By, Land
  • Adresse 2 (Butiks-adresse): Gade, Postnummer, By, Land
  • Adresse 3 (Faktura-adresse): Gade, Postnummer, By, Land

Systemfelter (LS-synkronisering)

FeltBeskrivelse
Internal Merchant IDID fra Loyalty Solutions efter oprettelse
External Chain IDEksternt kæde-ID i LS
Old Record DataSnapshot af seneste synkroniserede data (til change detection)
LS Record DataSeneste opdaterede felter sendt til LS
LS Error DataFejlrespons fra LS
Loyalty Solutions FejlbeskedRå fejlbesked fra LS
Chat MessageBrugervenlig fejlbesked genereret af GPT
Faktureres gennem"Kæde" eller "Selvstændigt"
Ny BonussatsPlanlagt ny bonussats
Skift Bonussats DatoDato for planlagt bonussats-skift
Ny VederlagssatsPlanlagt ny vederlagssats
Skift Vederlagssats DatoDato for planlagt vederlagssats-skift
BC Record DataSnapshot af seneste BC-synkronisering
Debitor NummerBC debitornummer (krav for BC-sync)

Økonomi / Faktura

FeltBeskrivelse
Visa CAIDVisa Card Acceptor ID
Visa Acquirer BINVisa Acquirer Bank ID Number
MC MIDMastercard Merchant ID

Bemærk: Visa CAID og Visa Acquirer BIN skal altid udfyldes sammen (valideret via client script). Hvis en af de tre kort-felter ændres, sendes alle tre til LS.

Modul: Kæder

Kæder består af en række butikker (partnere), som typisk har et overordnet ejerskab. En kæde kan styre bonussats og vederlagssats for alle tilknyttede partnere.

Kæde Oplysninger

FeltTypeBeskrivelse
Kæde NavnEnkelt linjeKædens navn
FBF AnsvarligBrugerIntern ansvarlig
OpkrævningsgruppeEnkelt linjeOpkrævningsgruppe
Produkt GruppeEnkelt linjeProduktgruppe
Type / StatusPluklisteAktiv, Lukket, Afvist af LS
Is ClosedCheckboxSættes automatisk til True når Type = Lukket
KategoriPluklisteLS-kategori
Benyt Kæde BonusPlukliste"Ja"/"Nej" - om kædens satser overskriver partnernes
BonussatsProcentKædens bonussats
VederlagssatsProcentKædens vederlagssats
LandEnkelt linjeLand (Danmark/Sverige)
Tilsluttet tilMultimodul-opslagMultimodul-reference

Kontakt & Faktura

FeltBeskrivelse
CVR Nr.Kædens CVR-nummer
E-mailKædens kontakt-email
TelefonKædens telefon
Faktureringstype"Leverandørservice" eller anden type
Faktura E-mailSeparat e-mail til LS-fakturering
Reg Nr.Bankregistreringsnr (ved Leverandørservice)
Bankkonto Nr.Bankkontonr (ved Leverandørservice)
Debitor NummerBC-debitornummer
Kæde EjerOverordnet ejerorganisation (lookup)

Systemfelter (LS-synkronisering)

FeltBeskrivelse
Internal Chain IDID fra LS efter oprettelse
Old Record DataSnapshot til change detection
Loyalty Solutions FejlbeskedFejlrespons fra LS
Ny BonussatsPlanlagt ny bonussats
Ny VederlagssatsPlanlagt ny vederlagssats
BC Record DataSnapshot af seneste BC-synkronisering

Modul: Organisationer

Organisationer anvendes til at registrere oplysninger om fagforeninger, butikker, foreninger m.m.

Organisation Oplysninger

FeltTypeBeskrivelse
FBF AnsvarligBrugerAnsvarlig medarbejder
CVR/VAT Nr.Enkelt linjeCVR-nummer
Organisationens NavnEnkelt linjeOfficielt navn
TelefonTelefonPrimært telefonnr
StatusTagAktiv/inaktiv/forældet
BranchePluklisteVirksomhedstype
Overordnet OrganisationLookup (self)Overordnet moderorganisation
Fusioneres sammen medLookup (self)Målorganisation for fusionering
Tilsluttet tilMultimodul-opslagMultimodul-reference

CVR Stamdata

FeltBeskrivelse
SelskabstypeJuridisk form (ApS, A/S osv.)
P-nummer10-cifret produktionsenhedsnummer
Branchekode6-cifret international branchekode
BranchetekstBeskrivelse af branche
VirksomhedsstatusAktiv, opløst, konkurs
OrganisationstypeForening, virksomhed, myndighed
MedarbejdereAntal ansatte

CVR Finansdata

FeltBeskrivelse
Regnskabsdata fra årDet år regnskabstallene stammer fra
BruttofortjenesteIndtægter før fradrag
Årets resultatResultat efter skat
StatusbalanceAktiver og passiver
EgenkapitalEjernes andel af finansieringen
Seneste regnskabLink til seneste årsrapport

Adresseinformation

FeltBeskrivelse
GadeGadenavn og nummer
PostnummerPostnummer
ByBynavn
StatRegion / stat
LandLandekode

Modul: Kontakter

Kontakter anvendes som kontaktpersoner til både organisationer og partnere.

Kontakt Oplysninger

FeltTypeBeskrivelse
FBF AnsvarligBrugerAnsvarlig medarbejder
FornavnEnkelt linjeKontaktpersonens fornavn
EfternavnEnkelt linjeKontaktpersonens efternavn
EmailE-mailE-mail adresse
Kontakt RolleTag"Partner", "Bestyrelsesmedlem" m.fl.
TitelEnkelt linjePersonens titel/rolle
TelefonTelefonTelefonnummer
MobilTelefonMobilnummer
Kundeemne KildePluklisteHvor kontakten stammer fra
FBF NumberEnkelt linjeFBF-nummer
TagsTagsKlassificering

Virksomheds Oplysninger

FeltTypeBeskrivelse
Organisations NavnLookup (Organisationer)Tilknyttet organisation
Partner NavnLookup (Partnere)Tilknyttet partner
KædeLookup (Kæder)Tilknyttet kæde
CVR/VAT Nr.Enkelt linjeAuto-udfyldt fra organisation/partner
EjerskabLookup (Ejerskaber)Tilknyttet ejerskab
WebstedURLAuto-udfyldt fra organisation/partner

Synkroniseringsfelter (system)

FeltBeskrivelse
Show FieldsBoolean - styrer om CVR-felter vises
Show WebsiteBoolean - styrer om website vises
Show OwnershipBoolean - styrer om ejerskab vises
UniqueMD5-hash til deduplikering af auto-oprettede kontakter

Modul: Ejerskaber

Ejerskab Oplysninger

FeltTypeBeskrivelse
Ejerskabs NavnEnkelt linjeEjerskabets navn
FBF AnsvarligBrugerAnsvarlig medarbejder
Primær KontaktpersonLookup (Kontakter)Primær kontaktperson
CVR Nr.Enkelt linje (unik)CVR-nummer - låses efter oprettelse
HjemmesideURLHjemmeside
TelefonTelefonTelefonnummer
Tilsluttet tilMultimodul-opslagMultimodul-reference

CVR Stamdata & Adresser

Identisk struktur som Partnere/Organisationer: Selskabstype, Medarbejdere, P-nummer, Branchekode, Branchetekst, Virksomheds Status, samt to adressesektioner (Adresse 1 og Adresse 2).

Modul: Valggrupper

Simpelt grupperingsmodul.

FeltTypeBeskrivelse
Valggruppe NavnEnkelt linjeGruppens navn
Valggruppe EjerBrugerAnsvarlig bruger
E-mailE-mailKontakt-email
Ændret afEnkelt linjeSidst ændret af
Oprettet afEnkelt linjeOprettet af
Tilsluttet tilMultimodul-opslagMultimodul-reference

Modul: Opgaver

Opgaver er typisk et stykke arbejde som er bundet af tid og kan bruges som en to-do liste.

FeltBeskrivelse
FBF AnsvarligAnsvarlig medarbejder
EmneEmnet for opgaven
ForfaldsdatoSeneste løsningsdato
KontaktTilknyttet kontaktperson
PartnerTilknyttet partner
StatusIkke startet, Udskudt, I gang, Udført, Venter på input
PrioritetHøj, Højeste, Lav, Laveste, Normal
GentagDagligt, ugentligt eller månedligt
PåmindelseEmail, pop-up eller begge
BeskrivelseOpgavebeskrivelse

Modul: Møder

Møder er en aktivitet som sker på et givent sted og tid.

FeltBeskrivelse
TitelMødets titel
StedLokation for mødet
Hele DagenOm mødet er hele dagen
Fra / TilStart- og sluttidspunkt
VærtAnsvarlig for mødet
Relateret tilMødets relation
DeltagereDeltagere med mulighed for email-invitationer
GentagDagligt, ugentligt, månedligt, årligt
PåmindelseSystemspåmindelser
BeskrivelseMødebeskrivelse

Modul: Opkald

Opkalds-modulet bruges til at registrere eller planlægge opkald.

FeltBeskrivelse
FBF AnsvarligAnsvarlig medarbejder
Opkald tilDropdown over kontakter
Relateret tilTilknyttet organisation
Status for udgående opkaldUdført eller Planlagt
Opkalds starttidDato og tid
OpkaldsvarighedLængde
EmneOpkaldsemne
OpkaldsformålFormålet
OpkaldsresultatInteresseret, ikke interesseret m.m.
BeskrivelseBeskrivelse af opkaldet

Client Scripts: Partnere

Frontend-scripts der kører i browseren når brugere interagerer med Partner-records.

CVR Integration Opret / Rediger (OnChange) / Klon

Trigger: Når feltet CVR/VAT Nr. ændres.
Formål: Slår virksomhedsdata op via CVR API og udfylder felter automatisk i realtid.

Logik

  1. Hvis værdien er 8 cifre eller starter med "DK": Dansk CVR-opslag med fuld data (stamdata, finans, adresse)
  2. Hvis værdien starter med 2 bogstaver (ikke DK): EU VIES-opslag med basisdata (navn, adresse)
  3. Ellers: Vis fejlbesked til brugeren

Felter der udfyldes (dansk CVR)

Telefon, Hjemmeside, Selskabstype, Branchekode, Branchetekst, Medarbejdere, P-nummer, Virksomheds Status, Gade, Postnummer, By, Land, Regnskabsdata fra år, Bruttofortjeneste, Årets resultat, Egenkapital, Statusbalance, Seneste Regnskab

// Eksempel: CVR-opslag og feltmapping
var cvr = ZDK.Apps.CRM.Connections.invoke(
    "cvrintegration",
    "http://api.cvrintegration.dk/fetchdata?query=" + value,
    "GET", 1, {}, {}
);
// Udfyld felter
phone_field.setValue(phone);
website_field.setValue(website);
company_type_field.setValue(company_type);
// ... osv.

Lås CVR Felt Rediger (OnLoad)

Trigger: Når redigeringssiden indlæses.
Formål: Gør CVR-feltet skrivebeskyttet hvis det allerede har en værdi, så det ikke kan ændres.

var cvr_field = ZDK.Page.getField("CVR_VAT_Nr");
var cvr_field_value = cvr_field.getValue();
if (cvr_field_value != null) {
    cvr_field.setReadOnly(true);
}

Lås Bonussats og Vederlagssats Rediger (OnLoad + OnChange Kæde)

Trigger: Når redigeringssiden indlæses ELLER når Kæde-feltet ændres.
Formål: Hvis den tilknyttede kæde har Benyt Kæde Bonus = "Ja", låses Bonussats og Vederlagssats så de ikke kan redigeres manuelt.

var chain_field = ZDK.Page.getField("K_de");
if (chain_field && chain_field.getValue()) {
    var lookupId = chain_field.getValue().id;
    if (lookupId) {
        var chain_record = ZDK.Apps.CRM.Chains.fetchById(lookupId);
        if (chain_record.Benyt_K_de_Bonus == "Ja") {
            ZDK.Page.getField("Bonussats").setReadOnly(true);
            ZDK.Page.getField("Vederlagssats").setReadOnly(true);
        }
    }
}

Validerings-scripts Detalje-side

validation_invoice_address.js / _city.js / _zipcode.js

Formål: Validerer at faktura-adressefelter (Adresse 3) enten er helt tomme eller helt udfyldte. Advarer brugeren hvis kun dele er udfyldt.

const street = ZDK.Page.getField("Adresse_3_Gade").getValue();
const zip    = ZDK.Page.getField("Adresse_3_Postnummer").getValue();
const city   = ZDK.Page.getField("Adresse_3_By").getValue();
const filled = [street, zip, city].filter(v => v && v.trim() !== '').length;
if (filled > 0 && filled < 3) {
    ZDK.Client.showMessage(
        'Hvis du angiver en særskilt fakturaadresse, skal gade, postnummer og by udfyldes sammen.',
        { type: 'warning' }
    );
}

validation_visa_caid.js

Formål: Validerer at Visa CAID og Visa Acquirer BIN altid udfyldes sammen.

const visaCaid = ZDK.Page.getField("Visa_CAID").getValue();
const visaBin  = ZDK.Page.getField("Visa_Acquirer_BIN").getValue();
if (Boolean(visaCaid) !== Boolean(visaBin)) {
    ZDK.Client.showMessage(
        'Begge felter: "Visa CAID" og "Visa Acquirer BIN" skal udfyldes sammen.',
        { type: 'warning' }
    );
}

Vis Fejlbesked

Formål: Viser en fejl-popup hvis feltet Chat Message indeholder en værdi (genereret af GPT efter LS-fejl).

var message = ZDK.Page.getField("Chat_Message");
if (message != null) {
    ZDK.Client.showMessage('This is an *important* warning.', {
        type: 'error'
    });
}

Client Scripts: Kæder

Deaktiverings Pop-up Detalje + Rediger

Trigger: Når bruger åbner detalje- eller redigeringssiden for en kæde med status "Lukket".
Formål: Viser en advarselsdialog om at alle partnere i kæden vil blive deaktiveret.

var chain_status_field = ZDK.Page.getField("Type");
var chain_status_value = chain_status_field ? chain_status_field.getValue() : null;

if (chain_status_value === "Lukket") {
    ZDK.Client.showConfirmation(
        "Vær opmærksom: Dette vil deaktivere alle partnere i denne kæde. " +
        "Fjern først de partnere, som ikke skal deaktiveres.",
        "Forstået", "Fortryd",
        function(confirmed) { /* ... */ }
    );
}

Pop-up Vindue (Is Closed variant) Detalje

Formål: Alternativ variant der tjekker Is Closed (boolean) i stedet for Type-feltet.

var chain_status_field = ZDK.Page.getField("Is_Closed");
if (chain_status_value === true) {
    ZDK.Client.showConfirmation(
        "Vær opmærksom: Dette vil deaktivere alle partnere...",
        "Forstået", "Fortryd", function(confirmed) { /* ... */ }
    );
}

Deaktiver Klon-knap + Forhindre Kloning Detalje + Klon

Formål: Forhindrer kloning af kæder. Klon-knappen deaktiveres på detaljesiden, og på klon-siden deaktiveres både Gem og Gem-og-ny knapperne.

// Detalje-side: Deaktiver klon-knap
var save_btn = ZDK.Page.getButton('clone');
save_btn.disable();

// Klon-side: Deaktiver gem-knapper
var save_btn = ZDK.Page.getButton('record_save');
var other_save_btn = ZDK.Page.getButton('record_save_and_new');
other_save_btn.disable();
save_btn.disable();

Client Scripts: Ejerskaber

Identisk mønster som Partnere:

ScriptSiderFormål
CVR IntegrationOpret, Klon, Rediger (OnChange)CVR/VIES-opslag. Identisk logik som Partnere, men mapper til Ejerskaber-felter (Navn, Gade, By osv.)
Lås CVRDetalje, Rediger (OnLoad)Gør CVR-feltet skrivebeskyttet så det ikke kan ændres

Client Scripts: Organisationer

Identisk mønster som Partnere/Ejerskaber:

ScriptSiderFormål
CVR IntegrationOpret, Klon, RedigerCVR/VIES-opslag. Mapper til Organisationers felter (Organisationens Navn, Gade, Postnummer osv.). Inkluderer også finansdata.
Lås CVRRedigerGør CVR-feltet skrivebeskyttet

Forskel fra Partnere: Organisationer bruger Zohos standard adressefelter (Gade, Postnummer, By) i stedet for custom adressefelter.

Workflows: Partnere

Partnere har det mest omfattende workflow-setup med 16 regler fordelt på oprettelse, redigering og oprettelse/redigering.

Ved Oprettelse (4 regler)

Oprettelse - Regel 1: CVRintegration.dk

Betingelse: CVR/VAT Nr. er IKKE TOM.
Handling: Custom Function

Funktionalitet: Serverside CVR-opslag. Henter stamdata, finansdata og opretter automatisk Kontakter for direktører og bestyrelsesmedlemmer.

void automation.CVRintegration_dk1(Int accid) {
    fetch_contacts = true;
    account = zoho.crm.getRecordById("Partnere", accid);
    cvr = account.get("CVR_VAT_Nr");

    // Dansk CVR: Hent fuld data + opret kontakter
    cvrdata = invokeurl[url: "http://api.cvrintegration.dk/fetchdata?query=" + cvr
                         type: GET  connection: "cvrintegration"];

    // Opdater partner med stamdata, finansdata, adresse
    mp.put("Phone", ifnull(account.get("Phone"), phone));
    mp.put("Selskabstype", ifnull(company_type, account.get("Selskabstype")));
    // ... flere felter ...

    // Opret kontakter for direktører
    for each direktoer in cvrdata.get("direktoer") {
        dmp.put("Kontakt_Rolle", "Partner");
        dmp.put("Partner_Navn", accid);
        zoho.crm.createRecord("Contacts", dmp);
    }
    // Opret kontakter for bestyrelsesmedlemmer
    for each bestyrelsesmedlem in cvrdata.get("bestyrelsesmedlemmer") {
        bmp.put("Kontakt_Rolle", "Bestyrelsesmedlem");
        zoho.crm.createRecord("Contacts", bmp);
    }
}

Oprettelse - Regel 2: Vælg kædefakturering

Betingelse: Kæde er IKKE TOM.
Handling: Custom Function - sætter Faktureres gennem til "Kæde".

void automation.changeInvoiceMethod(Int partner_id) {
    mp = Map();
    mp.put("Faktureres_gennem", "Kæde");
    zoho.crm.updateRecord("Partnere", partner_id, mp);
}

Oprettelse - Regel 3: Opret Partner i LS

Betingelse: Status ≠ "Aktiv", Internal Merchant ID er TOM, Kommunenummer ≠ 1 (tag).
Handlinger: Opret partner i LS + Opret kunde i BC + Sæt partnernummer (2 min. forsinkelse)

Funktionalitet: Opretter partneren i Loyalty Solutions og opretter en kunde i Business Central (POST). Ved succes gemmes Internal Merchant ID og der oprettes en påmindelsesopgave. Ved fejl gemmes fejlbesked og status sættes til "Afvist af LS".

Oprettelse - Regel 4: Vælg selvstændig fakturering

Betingelse: Kæde er TOM.
Handling: Custom Function - sætter Faktureres gennem til "Selvstændigt".

Ved Redigering (11 regler)

Redigering - Regel 1: CVRintegration.dk

Betingelse: CVR/VAT Nr. ændret til ikke-tom værdi.
Handling: Custom Function - identisk logik som ved oprettelse.

Redigering - Regel 2: Opdater Kontakt Felter

Betingelse: Harmoninr, CVR/VAT Nr., Kort Nummer eller Cpr ændres.
Handling: Custom Function

Funktionalitet: Synkroniserer CVR, Website og Ownership fra partneren til alle tilknyttede kontakter. Sætter synkroniseringsfelterne på kontakterne.

void automation.updatePartnerContactFields(Int partner_id) {
    account = zoho.crm.getRecordById("Partnere", partner_id);
    cvr = account.get("CVR_VAT_Nr");
    website = account.get("Website");
    if (website == null) { website = account.get("Kerne_Website"); }

    mp = Map();
    if (cvr != null) { mp.put("CVR_VAT_Nr", cvr); mp.put("Show_Fields", true); }
    if (website != null) { mp.put("Websted_1", website); mp.put("Show_Website", true); }

    related_contact_list = zoho.crm.getRelatedRecords("Contacts2", "Partnere", partner_id);
    for each contact in related_contact_list {
        zoho.crm.updateRecord("Contacts", contact.get("id"), mp);
    }
}

Redigering - Regel 3: Opret Partner i LS

Betingelse: Status ændret til "Aktiv", Internal Merchant ID er TOM.
Handlinger:

  • Custom Function: Opret partner i LS
  • Custom Function: Opret kunde i Business Central (POST)
  • Planlagt handling: Sæt Partnernummer (2 min. efter, sætter Partnernummer = record ID)

Redigering - Regel 4: Opdater Partner i LS

Betingelse: Status = "Aktiv", Internal Merchant ID er IKKE TOM, Kommunenummer ≠ 1 (tag).
Handling: Custom Function (Opdater Partner i LS)

Funktionalitet (change detection):

  1. Hent Old Record Data (snapshot fra sidste sync)
  2. Hent aktuelle data fra CRM-recorden
  3. Sammenlign felt for felt - kun ændrede felter sendes
  4. Særregel: Hvis Visa CAID, Visa BIN eller MC MID ændres, sendes alle tre
  5. PATCH til LS med kun ændrede felter
  6. Ved succes: Opdater Old Record Data med nye værdier
  7. Ved fejl: Gem fejlrespons i LS Error Data

Redigering - Regel 5: Fejl i Overførelse af Partner

Betingelse: Loyalty Solutions Fejlbesked ændret til ikke-tom.
Handling: Custom Function

Funktionalitet: Sender fejlbeskeden til OpenAI GPT-5 med en dansk prompt der beder om en brugervenlig oversættelse (maks 255 tegn). Resultatet gemmes i Chat Message.

Redigering - Regel 6 & 7: Faktureringsmetode

Regel 6: Kæde ændret til ikke-tom -> Faktureres gennem sættes til "Kæde"
Regel 7: Kæde ændret til tom -> Faktureres gennem sættes til "Selvstændigt"

Redigering - Regel 8: Sæt Partner til inaktiv i LS

Betingelse: Status ændret til "Lukket", Ophør(Afviklet/Opsagt) = "Opsagt".
Handling: Opretter en Opgave:

FeltVærdi
Emne"Sæt Partner til inaktiv i LS"
ForfaldsdatoUdløsningsdato + 2 dage
StatusIkke startet
PrioritetHøjeste
FBF AnsvarligForbrugsforeningen Salg

Redigering - Regel 9: Opdater BC Kunde

Betingelse: Debitor Nummer er IKKE TOM.
Handling: Custom Function (Synkroniser til BC)

Funktionalitet: Synkroniserer partnerdata til Business Central via SMART API. Mapper CRM-felter til BC Customer-felter og sender PUT-request. Adresserne hentes i prioriteret rækkefølge: Adresse 3 -> Adresse 2 -> Adresse 1.

Redigering - Regel 10: Skift Bonussats

Betingelse: Skift Bonussats Dato er IKKE NULL, Tidspunkt: på dato.
Handling: Custom Function

Funktionalitet: Henter Ny Bonussats, sender PATCH til LS med den nye sats, og rydder planlægningsfelterne.

void automation.skiftBonussats(Int partner_id) {
    partner_response = zoho.crm.getRecordById("Partnere", partner_id);
    crm_new_bonus = partner_response.get("Ny_Bonussats");
    new_bonus = crm_new_bonus.remove("%").replaceAll(",", ".");
    mp = Map();
    mp.put("rewardRate", new_bonus);
    internal_merchant_id = partner_response.get("internal_Merchant_ID");
    ls_response = invokeurl
    [
        url: "https://fbf-loyaltfacts-api.loyaltfacts.com/merchants/" + internal_merchant_id
        type: PATCH
        parameters: mp
        connection: "loyalty solutions"
    ];
    // Ryd planlægningsfelter og opdater aktuel sats:
    quick_mp = Map();
    quick_mp.put("Ny_Bonussats", null);
    quick_mp.put("Bonussats", crm_new_bonus);
    quick_mp.put("Skift_Bonussats_Dato", null);
    zoho.crm.updateRecord("Partnere", partner_id, quick_mp);
}

Redigering - Regel 11: Skift Vederlagssats

Betingelse: Skift Vederlagssats Dato er IKKE NULL, Tidspunkt: på dato.
Handling: Custom Function - identisk logik som bonussats, men med vederlagssatsen.

Ved Oprettelse ELLER Redigering (1 regel)

Opret/Rediger - Regel 1: Kopier Data fra Kæde

Betingelse: Kæde er IKKE TOM.
Handling: Custom Function (Kopier Kæde Data)

Funktionalitet: Kopierer data fra den tilknyttede kæde til partneren, men kun for felter der er tomme på partneren. Overskriver aldrig eksisterende data. Feltet Ophørelsesårsag springes altid over.

void automation.copyChainData(Int partner_id) {
    partner_response = zoho.crm.getRecordById("Partnere", partner_id);
    // Find alle tomme felter på partner
    for each key in partner_response.keys() {
        if (value == null || value == "") { partner_map.put(key, null); }
    }
    // Hent kæde-data
    chain_response = zoho.crm.getRecordById("Chains", partner_response.get("K_de").get("id"));
    // Kopier kun felter der er tomme på partner men har værdi på kæde
    for each partner_key in partner_map.keys() {
        if (chain_map.containsKey(partner_key) && partner_key != "Oph_relse_rsag") {
            update_map.put(partner_key, chain_map.get(partner_key));
        }
    }
    zoho.crm.updateRecord("Partnere", partner_id, update_map);
}

Workflows: Kæder

Kæder har 9 workflow-regler der styrer synkronisering til LS, kaskadeopdatering af partnere og BC-integration.

Ved Oprettelse (1 regel)

Oprettelse - Regel 1: Opret Kæde i LS

Betingelse: Internal Chain ID er TOM, Status ≠ "Aktiv", Kommunenummer ≠ 1 (tag).
Handlinger: Opret kæde i LS + Opret kunde i Business Central (POST)

Funktionalitet:

  1. Opretter kæden i LS med navn, kategori, land, bonussats/vederlagssats, fakturadata
  2. Gemmer Internal Chain ID fra LS-respons
  3. Opretter en kunde i Business Central via POST
  4. Markerer alle tilknyttede partnere så de opdateres mod LS
  5. Ved fejl: Sætter Type til "Afvist af LS"

Ved Redigering (8 regler)

Redigering - Regel 1: Opdater Partnere (kaskade)

Betingelse: Status ændres.
Handling: Custom Function (Opdater Partnere)

Funktionalitet: Når en kædes status ændres, kaskaderes statusændringen til alle tilknyttede partnere.

void automation.opdaterPartnere(Int chain_id) {
    chain_response = zoho.crm.getRecordById("Chains", chain_id);
    chain_status = chain_response.get("Type");
    partner_list = zoho.crm.getRelatedRecords("Partnere", "Chains", chain_id);
    mp = Map();
    mp.put("Partner_Status", chain_status);
    for each partner in partner_list {
        zoho.crm.updateRecord("Partnere", partner.get("id"), mp);
    }
}

Redigering - Regel 2: Opret Kæde i LS

Betingelse: Status ændret, Internal Chain ID er TOM, status ≠ "Lukket".
Handlinger: Identisk med oprettelses-reglen (inkl. BC POST).

Redigering - Regel 3: Opdater Kæde i LS

Betingelse: Status = "Aktiv", felter ændret.
Handling: Custom Function (Opdater Kæde i LS)

Funktionalitet: Identisk change-detection logik som partnere. Sammenligner Old Record Data med aktuelle værdier og sender kun ændringer via PATCH.

Redigering - Regel 4: Automatisk udfyld Is Closed

Betingelse: Type ændret til "Lukket".
Handling: Feltopdatering - sætter Is Closed til True

Redigering - Regel 5: Inaktive Kæde (opgave)

Betingelse: Status ændret til "Lukket", Ophør(Afviklet/Opsagt) = "Opsagt".
Handling: Opretter Opgave: "Sæt kæde til inaktiv i LS" med forfald = Udløsningsdato + 3 dage, prioritet Højeste.

Redigering - Regel 6: Opdater BC Kunde

Betingelse: Debitor Nummer er IKKE TOM.
Handling: Custom Function (Synkroniser Kæde til BC)

Identisk logik som Partner BC-sync, men mapper fra Kæde-felter.

Redigering - Regel 7: Skift Bonussats

Betingelse: Skift Bonussats Dato er IKKE NULL, Tidspunkt: på dato.
Handling: Custom Function - sender PATCH med ny bonussats til LS for kæden.

Redigering - Regel 8: Skift Vederlagssats

Betingelse: Skift Vederlagssats Dato er IKKE NULL, Tidspunkt: på dato.
Handling: Custom Function - sender PATCH med ny vederlagssats til LS for kæden.

Workflows: Kontakter

Kontakter har 3 workflow-regler.

Oprettelse - Regel 1: CVRintegration.dk

Betingelse: CVR/VAT Nr. er IKKE TOM.
Handling: Custom Function

Funktionalitet:

  1. Søger efter eksisterende Organisation med samme CVR
  2. Hvis fundet: Tilknytter kontakten til organisationen og kopierer adresse
  3. Hvis ikke fundet: Opretter ny Organisation via CVR-data og tilknytter kontakten
  4. Opretter også kontakter for direktører og bestyrelsesmedlemmer (ligesom Partnere)

Redigering - Regel 1: CVRintegration.dk

Betingelse: CVR/VAT Nr. ændret til ikke-tom værdi.
Handling: Identisk logik som ved oprettelse.

Opret/Rediger - Vis/Skjul Felter

Betingelse: Record oprettet eller redigeret.
Handling: Custom Function (Vis/Skjul Felter)

Funktionalitet: Henter CVR, Website og Ownership fra den tilknyttede Organisation og/eller Partner. Sætter visibility-flags (Show Fields, Show Website, Show Ownership) så relevante felter vises/skjules på kontakten.

Prioritet: Organisationsdata foretrækkes. Partnerdata bruges kun som fallback for felter der ikke findes på organisationen.

Workflows: Organisationer

Organisationer har 5 workflow-regler: 2 CVR-integrationer (identisk med Partnere) og 3 custom-regler.

CVRintegration.dk (Oprettelse + Redigering): Identisk logik som Partnere-modulets CVR-workflows. Se Workflows: Partnere.

Redigering - Aktiver Partner

Betingelse: Organisations Status ændret til "Godkendt Partner".
Handling: Custom Function (Aktiver Partner)

void automation.aktiverPartner(Int account_id) {
    account_response = zoho.crm.getRecordById("Accounts", account_id);
    partner_number = account_response.get("Partner_nummer");
    mp = Map();
    mp.put("businessId", partner_number);
}

Redigering - Opdater Kontakt Felter

Betingelse: CVR/VAT Nr. eller Harmoninr ændres.
Handling: Custom Function (Opdater Kontakt Felter)

Funktionalitet: Synkroniserer CVR og Website fra organisationen til alle tilknyttede kontakter. Sætter visibility-flags.

void automation.updateContactFields(String account_id) {
    account = zoho.crm.getRecordById("Accounts", account_id);
    cvr = account.get("CVR_VAT_Nr");
    website = account.get("Website");

    mp = Map();
    if (cvr != null) { mp.put("CVR_VAT_Nr", cvr); mp.put("Show_Fields", true); }
    if (website != null) { mp.put("Websted_1", website); mp.put("Show_Website", true); }

    contacts = zoho.crm.searchRecords("Contacts",
        "(Account_Name:equals:" + account.get("Account_Name") + ")");
    for each contact in contacts {
        zoho.crm.updateRecord("Contacts", contact.get("id"), mp);
    }
}

Redigering - Fusionering

Betingelse: Fusioneres sammen med ændret til ikke-tom værdi.
Handling: Custom Function (Organisations Fusionering)

Funktionalitet: Overfører alle kontakter fra den aktuelle organisation til målorganisationen.

void automation.organisationsFusionering(Int org_id) {
    org_response = zoho.crm.getRecordById("Accounts", org_id);
    new_org_id = org_response.get("Fusioneres_sammen_med").get("id");
    // Transfer contacts
    contact_list = zoho.crm.getRelatedRecords("Contacts", "Accounts", org_id);
    for each contact in contact_list {
        zoho.crm.updateRecord("Contacts", contact.get("id"),
            {"Account_Name": new_org_id});
    }
}

Workflows: Ejerskaber

Ejerskaber har 2 workflow-regler - begge er CVR-integration.

RegelTriggerBetingelseHandling
CVRintegration.dkOprettelseCVR/VAT Nr. er IKKE TOMCustom Function (identisk logik som Partnere)
CVRintegration.dkRedigeringCVR/VAT Nr. ændretCustom Function (identisk logik som Partnere)