ECommerce

Aus OrgaMon Wiki
Zur Navigation springen Zur Suche springen

Die B2B F䨩gkeiten des OrgaMon erm?chen es Dienstleistungen des OrgaMon von aussen zu benutzten. Dazu wird im Moment, die von jedem System beherschte XML-RPC Schnittstelle benutzt. Der benutzte TCP/IP Port ist frei einstellbar.


Funktionen "Ü¢erblick"

Erstmalig werden Funktionen f?ch䦴sabl䵦e aus OrgaMon in einem
Zentralen Modul (eCommerce) gesammelt. Das Ziel ist, den ganzen Webshop
bzw. alle Webanfragen ausschlie߬ich ?as eCommerce Modul laufen zu
lassen. Dabei werden auch erstmals "r" Connections und "w" Connections
eingesetzt, was dem zuk?en raib-Server zugute kommt (Clustering).
Nun eine Liste aller eCommerce Funktionen:

Funktionsindex "XML-RPC-Verf?quot;

   abu.ArtikelSuche(SuchStr: string): array of integer; { ARTIKEL_R }
   // Suchmaschine f?ikelsuche
   abu.ArtikelPreis(AUSGABEART_R, ARTIKEL_R:integer): double;
   // liefert den Preis des Artikels in dieser Ausgabeart
   // kostenlos = 0; // 
   // cPreis_vergriffen = -1.0; // Artikel nicht mehr lieferbar.
   // cPreis_aufAnfrage = -2.0; // keine Preisinformation verf?
   abu.Land(LAND_R: integer): string;
   // liefert die Landesbezeichnung (als ISO-K?
   abu.KontoInfo(PERSON_R: integer): double;
   // liefert den Kontostand des Kunden (zu zahlen!)
   // erzeugt als Nebeneffekt die aktuelle "Mahnung.html"
   abu.BestellInfo(PERSON_R: integer): integer;
   // liefert den Lieferr?nd des Lieferanten (Erwartete Mengen!)
   // erzeugt als Nebeneffekt die aktuelle "Bestellung.html"
   abu.Bestellen(PERSON_R: integer): integer;
   // erstellt aus dem Einkaufswagen des Kunden eine tats䣨liche
   // Bestellung. Die (neue) Beleg-Nummer wird zur?eben.
   //
   abu.ArtikelVersendetag(AUSGABEART_R, ARTIKEL_R:integer): integer;
   //
   // GELBE STATI
   //  0=keine Info ?erf?eit vorhanden
   //
   // ROTE STATI:
   //  1=entg?vergriffen
   //  2=zur Zeit vergriffen, Neuauflage jedoch ungewiss
   //  3=zur Zeit vergriffen, Neuauflage jedoch sicher
   //
   //
   // GRÜŽE STATI:
   //  10=heute lieferbar  (=ist am Lager, ohne Mengenangabe)
   //  11=morgen lieferbar (=wurde z.B. mit dieser Zusage bereits bestellt und kommt morgen)
   //  12=in 2 Tagen lieferbar... (=ist z.B. in dieser Zeit zu beschaffen)
   //  13=in 3 Tagen lieferbar...
   //  14= ... usw ...
   //
   // GRÜŽE STATI:
   //  101= heute lieferbar  (=ist am Lager, Lagermenge=1)
   //  102= heute lieferbar  (=ist am Lager, Lagermenge=2)
   //  103= heute lieferbar  (=ist am Lager, Lagermenge=3)
   //  ... usw.
   //
   //  GRÜŽE STATI:
   // >20020101= Konkretes Lieferdatum (z.B. Erscheinungsdatum!)
   //  20031003= am 03.10.2003 lieferbar (da es z.B. an diesem Tag erscheint)
   //            (Vorbestellungen nat? m?ch)
   //
   abu.Verlag(VERLAG_R:integer): string;
   // Names des Verlages zu einem Verlags-RID
   // ACHTUNG: aus geschichtlichen Gr?sind VERLAG_R zumeist als PERSON_R(s)
   // zu verstehen!
   abu.Versandkosten(PERSON_R:integer): double;
   // Liefert passend zum "Kunden,Umfang des Einkaufswagen,Versandart des Kunden" die
   // passenden Versandkosten. Im Moment als dummy immer 3,33 ?.
   abu.ArtikelInfo(AUSGABEART_R, ARTIKEL_R, LAND_R, VERLAG_R) : double, string;
   // Multi-Info-Funktion f?tere Informationen zu Artikel-Daten
   // Ergebnisse: Preis, "ISO-Landeskennzeichen" "-" "Verlag"
   abu.BasePlug():array of string;
   // liefert diverse Informations-String:
   // 1) Datenbankname
   // 2) OrgaMon Versions-Nummer
   // 3) IBO Versions-Nummer
   // 4) Indy Versions-Nummer
   // 5) PDF Pfad (public)
   // 6) Musik Pfad
   // 7) HTML-Pfad (Rechnungen)
   // 8) Bild-URL
   // 9) Datenbank SYSDBA passwort
   // * Mit Hilfe des Verbindungsstrings sollte auf die entsprechende Datenbank
   //   konnektiert werden.
   // * In der Datenbank sollten nun alle weiteren Parameter, den Shop betreffend
   //   eingegeben sein!
   // f? Shop wichtige Parameter:
   //
   // MusicPath=\\Linus\user\abu\Delphi\abu\Musik\
   // PDFPath=\\Linus\user\hebu\HeBu PDF\A4PDF\
   // XMLRPCHost=BRUTUS
   // XMLRPCPort=3049
   //
   abu.ArtikelRabattPreis(AUSGABEART_R,ARTIKEL_R,PERSON_R) : array of double;
   //
   // wie Artikel-Preis, soll jedoch bei Kunden mit Rabatt-Code verwendet werden,
   // diese Funktion liefert noch die Rabatt-Zahl dazu!
   //
   abu.PersonNeu : integer; { PERSON_R }
   //
   // Eine neue Person wird angelegt. Der (neue) RID wird als Ergebnis ge-
   // liefert. Der Webshop kann nun weitere Eintragungen machen.
   //
   abu.Ort(PERSON_R) : string; { Adress-Ortsangabe }
   //
   // Zu der angegebenen Person wird die Orts-Angabe zusammengestellt.
   // Dazu wird Land, Plz, Ortsname und Ortsteil landesspeziefisch
   // kombiniert.
   abu.Rabatt(PERSON_R) : boolean;
   // Zu der angegebenen Person wird ermittelt, ob sie Rabatte bekommt.
   // Wenn ja wird true, andernfalls false zur?eben.
   abu.Preis(AUSGABEART_R,ARTIKEL_R,PERSON_R) : array of double;
   //
   // Ersetzt in Zukunft die beiden Methoden abu.ArtikelPreis und abu.ArtikelRabattPreis
   // Falls der Kunde Rabatte bekommt, was beim Login mit abu.Rabatt gepr?rd,
   // wird der Funktion der wirkliche PERSON_R ?ben, andernfalls 0.
   // R?ewerte sind der Preis und der Rabatt (in Prozent, 0 bei PERSON_R == 0).
   // 
   //  result[0] Preis in Euro
   //  result[1] Rabatt in %
   //  result[2] Netto-Flag: ("1" = JA | "0" = NEIN)
   //  result[3] Netto-wie-Brutto-Flag: ("1"= JA | "0" = NEIN)
   // 

Funktionsindex "intern verf?quot;

   // SQL selects, die einen Einzelnen Wert zur?en
   function e_r_sql(s: string): integer;
   function e_r_GEN(GenName: string): integer;
   function e_r_sqls(s: string): string;
   function e_r_sqll(s: string): TStringList;
   function e_r_sqlm(s: string): TIntegerList;
   function e_r_sqld(s: string): double;
   function e_r_IsRID(FieldName: string; RID: integer): boolean;
   // SQL Update, Execute Statements
   procedure e_x_sql(s: string); overload;
   procedure e_x_sql(s: TStrings); overload;
   // kleinere Tools f?ikel Selektion
   function e_r_sqlArtikelWhere(AUSGABEART_R, ARTIKEL_R: integer): string;
   //
   procedure e_r_ArtikelSortieren(const RIDS: TList);
   //
   function ResolveSQL(const VarName: ShortString): ShortString;
   //
   procedure e_x_dereference(dependencies: TStringList; fromref, toref: string);
   // alle Referenzen von einem Wert auf einen RID
   //
   // TABELLE "." FELD [","] [" where " CONDITION]
   //
   function e_r_AgentMenge(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // liefert die Menge, die im Moment zu beschaffen ist
   function e_r_UngelieferteMenge(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // liefert die Menge, die im Moment zu beschaffen ist
   function e_r_VorschlagMenge(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // liefert die Menge, die das System vorschlagen w?    function e_r_ErwarteteMenge(AUSGABEART_R, ARTIKEL_R: integer; sDetails: TStringList = nil): integer;
   // liefert die Menge, die im Moment erwartet wird!
   function e_r_Localize(RID, LAND_R: integer): string;
   //
   function e_r_Localize2(RID, LANGUAGE: integer): string;
   // Landesspezifiesche Strings
   //
   function e_w_SyncLocalTime: boolean;
   // Lokale Uhrzeit neu stellen!
   //
   function e_w_GEN(GenName: string): integer;
   // erh?den Generator um ein und liefert nun diesen Wert.
   //
   function e_r_Bearbeiter(BEARBEITER_R: integer): string;
   // Liefert das K?des Bearbeiters.
   //
   function e_r_ServerTime: TDateTime;
   // Server Uhrzeit auslesen!
   //
   function e_r_UngelieferteMengeUeberBedarf(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // liefert die ?hlige Menge die vom System erwartet wird, also ?quot;Agent" und "Mindestbestand"
   // hinaus.
   function e_r_MindestMenge(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // liefert die Mindest-Menge, die auf Lager sein sollte
   procedure e_w_BedarfsAnzeige(AUSGABEART_R, ARTIKEL_R, POSTEN_R, MENGE: integer; Motivation: eMotivation);
   // dem Agenten signalisieren, dass Bestell-Bedarf besteht
   function e_w_SetFolge(AUSGABEART_R, ARTIKEL_R: integer): integer; // Order-Posten-Anz
   // Reihenfolge der Befriediung von Erwarteten Mengen voreinstellen
   function e_w_Wareneingang(AUSGABEART_R, ARTIKEL_R, MENGE: integer): integer; // [ZUSAMMENHANG]
   // Waren im System verteilen
   function e_r_ZahlungText(ZAHLUNGTYP_R: integer; PERSON_R: integer = 0; MoreInfo: TStringList = nil): string;
   // liefert den Zahlungstext zur jeweiligen Person
   function e_r_VERLAG_R_fromVerlag(Verlag: string): integer; { RID }
   // RID eines Verlages bestimmen!
   function e_r_Lieferant(ARTIKEL_R, MENGE: integer): integer; {PERSON_R}
   // Ermittelt den Lieferanten zu diesem Artikel
   function e_w_BestellBeleg(PERSON_R: integer): integer; {BBELEG_R}
   // liefert die Nummer eines Bestellbelegs, ev. wird einer neu erzeugt
   function e_w_JoinBeleg(BELEG_R_FROM, BELEG_R_TO: integer): integer;
   // 2 Belege zusammen f?
   function e_w_JoinPerson(PERSON_R_FROM, PERSON_R_TO: integer): integer;
   // 2 Personen zusammen f? Quellperson kann gel?t werden
   function e_w_MoveBeleg(BELEG_R_FROM, PERSON_R_TO: integer): integer;
   // einen Beleg von einem Verantwortlichen zum anderen f?
   function e_w_CopyBeleg(BELEG_R_FROM, PERSON_R_TO: integer): integer;
   // Beleg neu erstellen anhand einer Vorlage
   function e_r_MengenAusgabe(MENGE, EINHEIT_R: integer; FormatStr: string = '%d'): string;
   // Menge rausbelichten
   function e_r_EinzelPreisAusgabe(PREIS: double; EINHEIT_R: integer): string;
   // Einzelpreis rausbelichten
   function e_r_PostenPreis(EinzelPreis: double; Anz, EINHEIT_R: integer): double;
   // Gesamtpreis berechnen
   function e_w_AusgabeBeleg(BELEG_R: integer; NurGeliefertes: boolean; AlsLieferschein: boolean): string;
   // Ausgabelauf f? aktuellen Beleg mit Anlage der htmls
   function e_r_Ausgabeart(AUSGABEART_R: integer): string;
   // liefert den text dieser Ausgabeart
   //
   function e_r_Menge(AUSGABEART_R, ARTIKEL_R: integer): integer; { MENGE }
   // liefert die Lagermenge dieses Artikels in der angegebenen
   // Auspr䧵ngsart
   function e_r_PreisTabelle(PREIS_R: integer): double;
   // Liest den Preiswert aus der Tabelle aus
   //
   function e_r_PreisValid(p: double): boolean;
   // Ist es auch ein echter preis, oder nur ein Tag
   //
   function e_r_Preis(AUSGABEART_R, ARTIKEL_R: integer; var Satz: double; var Netto: boolean; var NettoWieBrutto: boolean): double;
   // liefert den Preis des Artikels
   // Satz ist der Mwst-Satz
   // Netto liefert Info, ob dieser Preis ein Netto oder Brutto-Preis ist
   //
   function e_r_PreisText(AUSGABEART_R, ARTIKEL_R: integer): string;
   // liefert den Preis des Artikels, fertig als String
   // - es kann auch "auf Anfrage" geben
   function e_r_PreisBrutto(AUSGABEART_R, ARTIKEL_R: integer): double;
   // liefert den Preis des Artikels
   //
   function e_r_PreisNativ(AUSGABEART_R, ARTIKEL_R: integer): double;
   // liefert die Preisangabe f?sen Artikel
   // unabh䮧ig von netto/brutto Problematik so wie er in der
   // Datenbank steht.
   function e_r_EndPreis(PERSON_R, AUSGABEART_R, ARTIKEL_R: integer): double;
   // liefert den Preis des Artikels
   function e_r_PreisNetto(AUSGABEART_R, ARTIKEL_R: integer): double;
   // liefert den Preis des Artikels
   function e_r_PaketPreis(AUSGABEART_R, ARTIKEL_R: integer): double;
   // liefert den Preis des Artikels
   function e_r_RabattFaehig(PERSON_R: integer): boolean;
   // ist es ein Rabatt-Kunde JA/NEIN
   function e_r_Rabatt(ARTIKEL_R, PERSON_R: integer; var Netto: boolean; var NettoWieBrutto: boolean): double;
   // liefert den Rabatt, den diese Person bei diesem Artikel erh䬴
   // nebenbei:
   // wird bei dieser Person ohne MwSt-Ausweisgearbeitet (Ausl䮤er)?
   // soll dabei einfach der eigentliche Bruttopreis als Nettopreis ausgewiesen werden?
   //
   function e_r_ekRabatt(ARTIKEL_R: integer): double;
   // liefert den Rabatt, mit dem dieser Artikel eingekauft wird
   function e_r_ObtainISOfromRID(LAND_R: integer): string;
   // liefert das ISO Landeskennzeichen
   function e_r_MwSt(AUSGABEART_R, ARTIKEL_R: integer): double; overload;
   // liefert die MwSt des Artikels
   function e_r_MwSt(SORTIMENT_R: integer): double; overload;
   // liefert die MwSt wie in diesem Sortiment ?
   function e_w_EinLagern(ARTIKEL_R: integer): integer; // [LAGER_R]
   // Lagerplatz eintragen
   function e_r_LagerVorschlag(SORTIMENT_R: integer; PERSON_R: integer {VERLAG_R}): integer; // [LAGER_R]
   // Lagerplatz vorschlagen
   function e_r_LagerDiversitaet(LAGER_R: integer): integer; // [MENGE]
   // Liefert die Anzahl verschiedener Artikel auf einem Lagerplatz
   procedure e_w_LagerFreigeben;
   // gibt Lagerplä´ºe frei, bei denen 14 Tage keine Bewegung mehr ist und Menge=0
   function e_w_Menge(AUSGABEART_R, ARTIKEL_R, MENGE: integer; BELEG_R: integer = 0; POSTEN_R: integer = 0): integer; { MENGE }
   // bucht eine Lagermenge ab oder zu
   // liefert die neue Lagermenge
   function e_w_NeuerMahnlauf(ForceNew: boolean = false): boolean;
   // erzeugt neuen Nummernkreise und leert die Mahnkandidatenliste
   //
   function e_w_KontoInfo(PERSON_R: integer; Verbuchen: boolean = false; AuchMahnbescheid: boolean = false): TStringList;
   // liefert den Kontostand des Kunden (zu zahlen!)
   // erzeugt als Nebeneffekt die aktuelle "Mahnung.html"
   //
   // OFFEN=
   // VERZUG=
   // [GUTSCHRIFT=JA]
   // [DIFFERENZ=JA]
   //
   function e_r_BestellInfo(PERSON_R: integer): integer;
   // liefert den Lieferr?nd des Lieferanten (erwartete Mengen!)
   // erzeugt als Nebeneffekt die aktuelle "Bestellung.html"
   function e_w_Bestellen(PERSON_R: integer): integer;
   // setzt den Einkaufswagen in eine Bestellung um. Dabei wird der
   // Einkaufswagen geleert.
   function e_w_BudgetEinfuegen(BELEG_R: integer): integer;
   // F?berechnetes Volumen aus offenen Bugets in den angegebenen
   // Beleg ein.
   procedure e_w_BudgetAbschreiben(BELEG_R: integer; BUDGET_R: integer; Menge_Rechnung: integer);
   // Bucht ein bisher unberechnetes Volumen an einem Budget ab, und
   // setzt das Volumen auf "abgerechnet".
   procedure e_w_EinkaufswagenLeeren(PERSON_R: integer);
   // Leert den aktuellen Einkaufswagen
   function e_w_EinkaufswagenEinfuegen(BELEG_R: integer): integer;
   // F?n aktuellen Einkaufswagen in den angegebenen Beleg
   // ein.
   function e_r_Rechnung(BELEG_R: integer): integer;
   // liefert die als n䣨stes zu vergebene Rechnungsnummer
   function e_w_BelegVersand(BELEG_R: integer; Summe: double; gewicht: integer): integer;
   // Legt einen neuen Versand-Eintrag in der Versand-Tabelle an,
   // oder f?en vorbereiteten!
   function e_r_StandardVersender: integer;
   // Legt einen neuen Versand-Eintrag in der Versand-Tabelle an,
   // dadurch
   function e_r_LeerGewicht(PACKFORM_R: integer): integer;
   // Leergewicht einer bestimmten Packform
   //
   function e_r_Gewicht(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // Gewicht eines Artikels
   //
   function e_r_ArtikelVersendetag(AUSGABEART_R, ARTIKEL_R: integer): integer;
   // gibts infos ?en Versendetag aus, es werden spezielle Status Codes
   // verwendet. Siehe Doku.
   function e_r_Lieferzeit(AUSGABEART_R, ARTIKEL_R: integer): integer; // [Tage]
   // gibts infos ?en Versendetag aus, es werden spezielle Status Codes
   // verwendet. Siehe Doku.
   function e_w_ArtikelNeu(SORTIMENT_R: integer): integer; { : RID }
   // legt einen Artikel im angegebenen Sortiment an
   // liefert den neuen RID zur?    function e_w_PersonNeu: integer; { : RID }
   // legt eine neue Person (vorl䵦ig) an. ܢer sie kann der Kunde
   // vorbestellungen / vormerkungen anlegen.
   function e_r_UebergangsfachFromPerson(PERSON_R: integer): integer;
   // ܢergangsfach ermitteln
   //
   function e_r_Uebergangsfach_VERLAG_R: integer;
   // Das ܢergangsfach
   function e_r_FreiesLager_VERLAG_R: integer;
   //
   function e_r_IsUebergangsfach(LAGER_R: integer): boolean;
   //
   function e_r_LagerPlatzNameFromLAGER_R(LAGER_R: integer): string;
   // Names eines Lagerplatzes anhand des LAGER_R
   function e_w_SetStandardVersandData(qVERSAND: TIB_Query): integer;
   // Versanddatensatz vorbelegen
   function e_r_VersandKosten(AUFTRAGGEBER_R, LIEFERANSCHRIFT_R, BELEG_R: integer): integer; { : ARTIKEL_R }
   // berechnet die VersandKosten anhand der Tabelle VREGEL
   // PERSON_R: Auftraggeber, angabe freiwillig
   // LIEFERANSCHRIFT_R: an wen geht die Lieferung, angabe freiwillig
   // BELEG_R: um welchen Beleg geht es
   function e_r_IsVersandKosten(ARTIKEL_R: integer): boolean;
   // ermittelt, ob es sich bei dem Angegebenen Artikel
   // um einen Versandartikel handelt, dies sind solche, die
   // in der VREGEL genannt werden.
   function e_w_VersandKostenClear(BELEG_R: integer): integer; { : Anzahl der entfernten }
   // l?en der ungebuchten versandkosten des
   // letzten Buchungslaufes
   function e_r_ort(PERSON_R: integer): string;
   // gibt der kompletten Orts-String an
   //
   function e_r_ObtainVerlagFromPERSON_RID(PERSON_R: integer): string;
   //
   function e_r_BelegInfo(PERSON_R: integer; BELEG_R: integer): TStringList; { : diverse ermittelten Werte }
   // PERSON_R: Eigner des Einkaufswagen
   //  -- ODER ALTERNATIV --
   // BELEG_R: direkte Belegnummer
   //
   function e_w_BerechneBeleg(BELEG_R: integer; NurGeliefertes: boolean = false): TStringList; { : diverse ermittelte Werte }
   // die Auftragsmengen entsprechend auf die Mengen verteilen Daumen, es erfolgen
   // Lagerbuchungen.
   // RECHNUNGSBETRAG=
   // LIEFERGEWICHT=
   function e_w_ForderungBuchen(BELEG_R: integer; RechnungsBetrag: double): TStringList;
   //
   //
   function e_w_BucheVersand(BELEG_R: integer; LabelDatensatz: boolean): string;
   // Briefumschlag-Funktion in den Belegen, Berechnete Mengen werden auf
   // geliefert gesetzt. Budgets werden abgeschrieben.
   procedure e_w_RechnungDatumSetzen(ib_q: TIB_Query; Aufdatum: TDateTime); overload;
   // historisch !! - l?en wenn m?ch
   procedure e_w_RechnungDatumSetzen(ib_q: TIB_Query; Aufdatum: TANFiXDate); overload;
   // historisch !! - l?en wenn m?ch
   function e_w_BelegNeu(PERSON_R: integer): integer; { }
   // legt einen neuen Kunden-Beleg an
   function e_r_LohnKalkulation(Betrag: double; Datum: TANFIXDate): string;
   //
   function e_r_LadeParameter: TStringList; { }
   //
   procedure e_r_PostenInfo(IBQ: TIB_DataSet; NurGeliefertes: boolean; EinzelpreisNetto: boolean;
     var
     _Anz,
     _AnzAuftrag,
     _AnzGeliefert,
     _AnzStorniert,
     _AnzAgent: integer;
     var
     _Rabatt,
     _EinzelPreisUnrabattiert,
     _EinzelPreis,
     _MwStSatz: double
     );
   procedure e_w_BeforeDeletePosten(POSTEN_R: integer);
   procedure e_w_BeforeDeleteBPosten(BPOSTEN_R: integer);
   procedure e_w_BeforeDeleteBeleg(BELEG_R: integer);
   procedure e_w_BeforeDeleteBBeleg(BBELEG_R: integer);
   procedure e_w_BeforeDeleteArtikel(ARTIKEL_R: integer);
   function e_w_BelegStatusBuchen(qbeleg: TIB_Query): boolean;
   function e_w_BBelegStatusBuchen(bbeleg, bposten: TIB_Query): boolean;
   procedure e_w_SetPostenData(ARTIKEL_R, PERSON_R: integer; qPosten: TIB_Query);
   procedure e_w_SetPostenPreis(AUSGABEART_R, ARTIKEL_R, PERSON_R: integer; qPosten: TIB_Query);
   // vor dem setzen weiterer Felder kann hier Standardasiert ein Artikel in
   // den aktuellen Posten kopiert werden. Zentrale Funktion zum F?einer
   // Posten zeile
   procedure e_w_InvalidateCaches;
   // Q - Funktionen sind Qualitä´³sicherungs-Hilfsfunktionen
   function q_r_PersonWarnung(PERSON_R: integer): TStringList;
   // F - Sind Download und Upload Funktionen
   procedure e_f_PersonInfo(PERSON_R: integer; AusgabePfad: string);