Leveringsadresse-velger (delivery-address-picker)¶
Gjenbrukbar, presentasjonell inline-velger for leveringsadresse på masterordre- og tilbudshodet (MO-098). Velgeren lar brukeren enten hente en adresse fra kunden (aktørens hovedadresse pluss aktørens ekstra adresserader) eller skrive en annen adresse, med et valgfritt «Lagre også på kundekortet». I tillegg til selve adressen (inkl. en 4. adresselinje) viser velgeren alltid en «Kontakt & referanser»-gruppe med ti gjenbrukbare-med-per-ordre-overstyring leveringsinstruks-felt — kontaktperson, kontakt-telefon/-e-post, merknad, referansenummer, deres ref, PO-nummer og tre valgfrie «Ekstra info»-felt (MO-098-EXT).
Komponenten er ren og skrivebeskyttet: den utleder aldri en aktør selv, den
skriver aldri til server, og den emitterer kun et resultat. Verten (host) eier
lagringen — masterordren via PUT api/SubscriptionMasterOrder/{id}/delivery-address,
tilbudet via PUT api/CrmOffer/{id}/delivery-address. Serveren avleder det tillatte
aktør-settet på nytt og validerer valget; klientens actorId er kun et display-hint.
Tatt i bruk i masterordre-detaljens «Rediger ordrehode»-skuff og i tilbudsdetaljen (se Tilbudsflyt).
Feature-tabell¶
| Komponent | Selector | Hovedfunksjon | Import |
|---|---|---|---|
| DeliveryAddressPickerComponent | app-delivery-address-picker |
Inline velger: hent adresse fra kunden (hovedadresse + wv_ActorAdr-rader) eller skriv en annen; valgfri «lagre på kundekortet» |
Standalone |
Kildefiler¶
| Del | Sti |
|---|---|
| Komponent | ui/ePortal.ui/src/app/components/shared/delivery-address-picker/delivery-address-picker.component.ts |
| Mal | ui/ePortal.ui/src/app/components/shared/delivery-address-picker/delivery-address-picker.component.html |
| Rene hjelpere/typer | ui/ePortal.ui/src/app/components/shared/delivery-address-picker/delivery-address-picker.helpers.ts |
| Tester | ui/ePortal.ui/src/app/components/shared/delivery-address-picker/delivery-address-picker.component.spec.ts, delivery-address-picker.helpers.spec.ts |
| Snapshot-type | DeliveryAddressSnapshot + DeliveryAddressSourceKind i ui/ePortal.ui/src/app/shared/models.ts |
Komponenten er standalone — importer klassen direkte i vertens imports. Den bruker
ng-select for aktør-/adressenedtrekkene og land-velgeren
(app-country-select) for Land-feltet.
Bruk¶
<app-delivery-address-picker
[actors]="derivedActors"
[actorId]="selectedActorId"
[value]="masterOrder.deliveryAddress"
[disabled]="saving"
(valueChange)="onDeliveryChange($event)">
</app-delivery-address-picker>
Verten sender inn det server-avledede aktør-settet (actors), gjeldende adresse-
snapshot (value), lytter på valueChange og bygger skrive-nyttelasten selv. Velgeren
skriver aldri direkte.
Inputs¶
| Input | Type | Standard | Beskrivelse |
|---|---|---|---|
actors |
DeliveryActorOption[] |
[] |
Det server-avledede tillatte kilde-aktør-settet (skip/kunde, fakturakunde, forvaltning). Tom liste skjuler «hent fra kunden»-modus. Velgeren utleder aldri en aktør selv. |
actorId |
string \| null |
undefined |
Gjeldende valgte kilde-aktør (et display-hint). Faller tilbake til første aktør i actors. |
value |
DeliveryAddressSnapshot \| null |
undefined |
Snapshotet velgeren seedes fra. |
disabled |
boolean |
false |
Deaktiverer alle kontroller (f.eks. mens verten lagrer). |
Outputs¶
| Output | Type | Beskrivelse |
|---|---|---|
valueChange |
EventEmitter<DeliveryAddressPickerResult> |
Emitteres ved hver endring så verten kan holde utkastet i synk. |
Modelltyper¶
// shared/models.ts
type DeliveryAddressSourceKind = 'None' | 'ActorMain' | 'ActorAddress' | 'Manual';
interface DeliveryAddressSnapshot {
name: string | null;
line1: string | null;
line2: string | null;
line3: string | null;
line4: string | null; // MO-098-EXT — 4. adresselinje, fryser ubetinget som line1-3
postalCode: string | null;
city: string | null;
countryCode: string | null; // ISO 3166-1 alpha-2
sourceKind: DeliveryAddressSourceKind;
sourceAddressId: string | null; // wv_ActorAdr.actaID — kun for ActorAddress
// MO-098-EXT: ti gjenbrukbare-med-per-ordre-overstyring leveringsinstruks-metadatafelt —
// forhåndsfylt fra den valgte wv_ActorAdr-raden, fritt overstyrbare per ordre, verdien på
// skjemaet ved lagring fryses inn (se «Oppførsel» under).
contactPerson: string | null;
contactPhone: string | null;
contactEmail: string | null;
note: string | null;
extraInfo1: string | null;
extraInfo2: string | null;
extraInfo3: string | null;
referenceNumber: string | null;
theirRef: string | null;
poNumber: string | null;
}
// delivery-address-picker.helpers.ts
interface DeliveryActorOption { actorId: string; name: string; role?: string; }
interface DeliveryAddressPickerResult {
snapshot: DeliveryAddressSnapshot;
actorId: string | null; // display-hint (null for ren manuell entry)
saveToCustomerCard: boolean;
}
Oppførsel¶
- To modus: hent fra kunden (
card) og skriv en annen adresse (manual). Uten aktører iactorsstarter velgeren i manuell modus. - Adresseoppslag: for valgt aktør leser velgeren aktørens hovedadresse (
wv_Actor) og aktørens ekstra adresserader (wv_ActorAdr) via ett CRM-lesekall (CrmCustomerService.getCustomerById). Lesing er lov mot det åpne CRM-endepunktet; kortskriving går alltid via vertens gatede ordre-/tilbudsendepunkt. - Provenance (
sourceKind): hovedadressen girActorMain(uten adresse-id), en kortrad girActorAddress(medsourceAddressId = actaID), fritekst girManual. Tom tilstand erNone. - «Fra kundekortet»-chip: vises når
sourceKind ∈ {ActorMain, ActorAddress}— ikke basert påsourceAddressId != null(hovedadressen er kort-hentet, men har ingen id). HjelperenisCardSourced()innkapsler regelen. - Lagre også på kundekortet: en avkrysning (standard AV). Flagget emitteres i resultatet; verten utfører kortskrivingen inne i den autoriserte ordre-/tilbuds- skrivingen — aldri fra velgeren.
- Sikkerhet:
actorIdi resultatet er kun et hint. Serveren avleder det tillatte aktør-settet på nytt fra den persisterte entiteten og avviser alt utenfor settet medForbidden. EtsourceAddressIdvalideres mot den avledede aktøren. - Land: Land-feltet bruker
app-country-select. Snapshotet lagrer ISO alpha-2; en kortverdi i alpha-3 (wv_ActorAdr.actaCountry char(3)) løses opp mot alpha-2, ellers faller den til tom (en gal landkode er verre enn ingen). - Adressesøk (Google, valgfritt): øverst i «skriv en annen adresse»-modus vises
app-address-autocomplete— søk på en adresse, et sted eller et firmanavn hvor som helst i verden. Et treff fyller utmanualDraft.name/line1/line2/postalCode/city/countryCode(ren field-for-field-erstatning, slik at et nytt søk ikke etterlater stale verdier fra forrige treff) og går gjennom den vanligeonManualChange()-emit-stien — snapshotet forblirManual-provenance, og «Kontakt & referanser»-metadata-gruppen røres aldri av et adressesøk.countryCodeer alpha-2 på begge sider (AutocompleteAddressog denne velgerens land-felt), så ingen alpha-3-konvertering trengs her. Komponenten skjuler seg selv når adressesøk ikke er aktivert for tenanten (fail-safe — kun ren manuell inntasting). - Adresselinje 3/4 (MO-098-EXT): «skriv en annen adresse»-modus har fire adresselinje- felt (Navn, Adresselinje 1-4, Postnummer + Sted, Land) — linje 4 fryser ubetinget som linje 1-3, uten egen gjenbruk/overstyring-historie.
- «Kontakt & referanser» (MO-098-EXT): en egen fieldset viser alle ti gjenbrukbare
leveringsinstruks-metadatafelt — kontaktperson, kontakt-telefon, kontakt-e-post, merknad,
referansenummer, deres ref og PO-nummer alltid synlige; tre generiske «Ekstra info»-felt
bak en kollapset-som-standard bryter (
showExtraInfo/toggleExtraInfo()) siden de fleste leveranser ikke trenger dem. Gruppen vises uavhengig av adressemodus (cardellermanual) — feltene er bundet tilmanualDrafts metadata-del, som komponenten alltid holder pre-fylt fra den sist plukkede kortraden (onAddressChangekallerextractMetadata()på nytt for hvert kortvalg). Verdien som står i feltet ved lagring — enten kortets opprinnelige verdi eller brukerens overstyring — er det som fryses inn i snapshotet (currentSnapshot()slår alltid sammen adresse-delen fra valgt kilde med metadata-delen framanualDraft, uansett modus). Et nytt kortvalg erstatter hele metadata-arbeidskopien med det nye kortets standing-verdier, og forkaster en eventuell tidligere overstyring for forrige kort — bytter du kort på nytt, starter overstyringen fra blanke ark igjen.
i18n¶
Alle brukerrettede tekster ligger under Subscription.delivery* i både no.json
og en.json (blokken er en-speilet). Sentrale nøkler:
"Subscription": {
"deliveryPickFromCustomer": "Velg adresse fra kunden",
"deliveryUseOtherAddress": "Bruk annen adresse",
"deliverySaveToCustomerCard": "Lagre også på kundekortet",
"deliveryFromCustomerCard": "Fra kundekortet",
"deliveryMainAddress": "Hovedadresse",
"deliveryName": "Navn / mottaker",
"deliveryLine1": "Adresselinje 1",
"deliveryLine2": "Adresselinje 2",
"deliveryLine3": "Adresselinje 3",
"deliveryLine4": "Adresselinje 4",
"deliveryPostalCode": "Postnummer",
"deliveryCity": "Sted",
"deliveryCountry": "Land",
// MO-098-EXT — «Kontakt & referanser»-fieldsettet
"deliveryContactSection": "Kontakt & referanser",
"deliveryFieldOverrideHint": "Forhåndsfylles fra adressen, kan overstyres for denne ordren. Lagres på adressen hvis «lagre på kundekortet» er på.",
"deliveryContactPerson": "Kontaktperson",
"deliveryContactPhone": "Kontakt-tlf",
"deliveryContactEmail": "Kontakt-e-post",
"deliveryNote": "Merknad",
"deliveryReferenceNumber": "Referansenummer",
"deliveryTheirRef": "Deres ref",
"deliveryPoNumber": "PO-nummer",
"deliveryExtraInfoToggleShow": "Vis ekstra info",
"deliveryExtraInfoToggleHide": "Skjul ekstra info",
"deliveryExtraInfoSection": "Ekstra info",
"deliveryExtraInfo1": "Ekstra info 1",
"deliveryExtraInfo2": "Ekstra info 2",
"deliveryExtraInfo3": "Ekstra info 3"
}
Tilgjengelighet og mobil¶
- Nedtrekkene bruker
ng-selectmedappendTo="body"— tastaturnavigasjon og søk som standard, og de klippes ikke av skuff-/modal-scrolling. - Land-feltet arver tilgjengeligheten fra
app-country-select(flagg er dekorativt, landnavnet er den tilgjengelige teksten).
Kjente fallgruver¶
| Fallgruve | Riktig mønster |
|---|---|
| La velgeren skrive til server | Den er ren/skrivebeskyttet. Verten lagrer via ordre-/tilbudsendepunktet og bygger nyttelasten fra valueChange. |
Stole på klientens actorId |
Det er kun et display-hint. Serveren avleder aktør-settet på nytt og avviser Forbidden utenfor settet. |
Vise «Fra kundekortet» ut fra sourceAddressId != null |
Bruk sourceKind ∈ {ActorMain, ActorAddress} (isCardSourced()) — hovedadressen er kort-hentet uten id. |
Sette sourceAddressId for hovedadresse/manuell |
sourceAddressId settes kun for ActorAddress. Null for ActorMain/Manual/None. |
| Sende inn hele kundens aktørliste | Send kun det server-avledede settet; velgeren skal ikke la brukeren velge en aktør utenfor det. |
| Anta at «Kontakt & referanser»-feltene bevarer en overstyring på tvers av kortvalg | De erstattes fullt ut ved hvert nytt kortvalg (onAddressChange re-pre-fyller fra det nye kortets standing-verdier) — en overstyring for forrige kort forkastes. |
Verifiseringspunkter¶
- Åpne en masterordre → «Rediger ordrehode»: seksjonen «Leveringsadresse» viser velgeren; velg hovedadressen — «Fra kundekortet»-chip vises.
- Klikk «Bruk annen adresse», skriv en adresse og lagre — snapshotet lagres på ordren uten å endre kundekortet (chip forsvinner).
- Kryss av «Lagre også på kundekortet» og lagre — adressen dukker opp som en
wv_ActorAdr-rad på kunden, og snapshotet fårActorAddress-provenance. - Velg en kortadresse, åpne «Kontakt & referanser» og bekreft at feltene forhånds- fylles fra kortraden; overstyr ett felt (f.eks. PO-nummer) og lagre — snapshotet fryser overstyringen, ikke kortets opprinnelige verdi.
- Skriv en verdi i «Ekstra info 1» bak «Vis ekstra info»-bryteren og lagre, åpne
redigeringen på nytt — verdien er der (
showExtraInfoer ren UI-tilstand og starter alltid kollapset ved en fersk åpning, uavhengig av om feltet har en verdi).