Erarbeitung eines "POS-Kassenbuchs"

Diskussionen zu Projekten

Moderator: Moderatoren

Forumsregeln
Dieses Unterforum versteht sich als Plattform zur Diskussion/Bearbeitung komplexerer Anfragen bzw. konkret verabredeter Projekte. Das können Dinge sein wie eine komplexere Calc-Datei oder auch die gemeinsame Programmierung eines größeren Makros, wichtig ist immer die Absicht ein Thema über längere Zeit (z.B. 3 Monate) fortlaufend zu besprechen.
Benutzeravatar
balu
********
Beiträge: 3810
Registriert: Fr, 24.08.2007 00:28
Wohnort: Warstein

Re: Erarbeitung eines "POS-Kassenbuchs"

Beitrag von balu »

Hallo Julia,

Du hasts gut. Du kannst deinen Akku wieder voll aufladen. Ich jedoch habe zur Zeit das Problem, das mein Akku unter dem Memory-Effekt leidet. Na ja, wird schon wieder.

Ich hatte echt Probleme, mich in die Arrays hineinzudenken.
Dabei hast du es perfekt erklärt
Danke schön.

… öhhmm… zumal ich zu meiner Schande feststellen musste, dass eine solche Rabatt-Text-Festlegung gar nicht sinnvoll ist… Leider brauchen wir das hier gar nicht, weil es im Grunde nur den Rabatt-Text „Sonstige“ geben wird.
Auch wenn mir das noch nicht so ganz verständlich ist, so ist das gezeigte Array ja nicht weggeschmissen/umsonst, da es ja immer wieder mal irgendwie gebraucht werden kann.

Denn Mitarbeiter und Chefetage, die eine ganze Flasche einer Spirituose entnehmen, ersetzen sie einfach später. Und es wäre auch fast unmöglich für Mitarbeiter, den Flaschenpreis von 50% über den Dialog herauszubekommen.
Sag das nicht, das das unmöglich ist. Es ist sehr vieles möglich, man muss es nur mal halt ausprobieren. Aber das können wir uns eventuell später noch mal vornehmen, da dies jetzt noch nicht so richtig hier rein passt.

Ich habe es jetzt trotzdem drin gelassen, weil´s so schön ist.
Das ist natürlich auch ein Argument :lol:

UND – weil ich denke, das war ein klasse Beispiel, wie Arrays funktionieren.
Bedenke aber, das dies noch nicht die letzte Art von Array war, kommen noch andere. ;-)

Ich hab ein bisschen darauf herumgedacht, ob es für den Lichtschalter auch noch andere Aggregatzustände geben kann als „an“ und „aus“. Ja, nä?
Doch gibt es, aber damit erzeugt man an einem echten Lichtschalter unter Umständen einen Kurzschluß. *grins*

Code: Alles auswählen

aUnterGrenze(4) = 150 : aOberGrenze(4) = 200 : aRabattText(4) = "Freies Gelage"
aUnterGrenze(5) = 200 : aOberGrenze(5) = 300 : aRabattText(5) = "Kater Stimmung"
Haha! Das gefällt mir!
Schön, schön!

Deshalb habe ich das hier stattdessen eingefügt, s.o. und hier:

Code: Alles auswählen

oListBox_AusserHaus.SelectItemPos((0), True) ' Listbox-Wert Voreinstellung auf "Nein"
Du musst die 0 in diesem Falle nicht in Klammern setzen, da dies jetzt eine Position ist. Deshalb steht da ja auch SelectItemPos.
Etwas anders siehts ja hierbei aus.

Code: Alles auswählen

oListBox_Preis.SelectItem(aKistenPreise(0), True)
Denn hier ist es keine Position, sondern ein ausgewählter Eintrag aus einem Array welches ja aKistenPreise heißt.


Jetzt habe ich noch eine andere Frage:
Es wurde der Wunsch geäußert, dass im Tabellenblatt immer automatisch etwas hochgescrollt wird während der Eingabe. Jetzt muss man dafür ja immer erst die Dialog schließen.
Ich hab auch vielleicht die entsprechende Anweisung dazu gefunden, jedoch krieg ich das nicht so hingebastelt, dass es funktioniert.

Code: Alles auswählen

oAktuellesBlatt.getCellRangeByName("A" & iEnd_Row).Select
Während der Eingabe hochsrollen geht nicht. Aber wenn eine Eingabe im Dialog fertig getätigt wurde, kann man anschließend den Cursor auf eine bestimmte Position setzen. Jedoch gibts da eine kleine, aber wohl unbedeutende Einschränkung. Der Cursor springt wohl die Zelle an, sie wird aber so gesehen "zentriert". Das heißt, wenn z.B. 25 Zeilen zu sehen sind, dann wird die gewünschte Zelle nicht ganz oben am Anfang stehen, sondern irgendwo in der mitte der sichtbaren Zeilen. Das ist aber immer noch besser, als wenn man zu "Fuß" zu der gewünschten Zelle gehen muss.

Ich weiß nicht wie Du auf diese Code Anweisung gekommen bist, aber ganz so einfach ist das nun wiederum doch nicht.
Das müsste dann schon wie folgt aussehen.

Code: Alles auswählen

sub SprungZurZelle
	oDok = thisComponent
	oViewController = oDok.CurrentController

	oAktSheet = oDok.sheets().getbyName(oViewController.activesheet.getName)
	aAktCursor = oAktSheet.getCellByPosition(0, 10) 'die gewünschte ZellPosition'
	
	oViewController.Select(aAktCursor) 'Der eigentliche Sprung zu der Zelle'
  
end sub
Diesen Code kannst Du so nehmen und direkt testen. Bei getCellByPosition kannst Du die 10 gegen andere Werte tauschen, und dich dadurch überzeugen das er wirklich funktioniert.

Beim Dannenhöfer gibts wohl ein anderes kleines Breispiel dazu, welches ich auch genommen und dementsprechend angepasst habe, aber es basiert auf einem fest vorgegebenen Blattindex. Guckst Du hier: 7.1.9 Wie kann man den aktuellen Cursor auf eine Zelle setzen?
Da es hier aber um wechselnde Blätter geht, also dynamisch anstatt statisch wie bei Dannenhöfer, musste ich auch erstmal etwas Knobeln bis das ich es hinbekommen habe. Und aus diesem Grunde sieht der Code jetzt etwas anders aus.

Wie, und was Du jetzt an diesem Code änder musst damit das auch mit der festgestellten "Letzten Zeile" funktioniert, das müsstest Du ja wohl alleine hinbekommen. ;-)

Was mich schon recht lange beschäftigt hat, ist folgendes:

Code: Alles auswählen

oAktuellesBlatt = thiscomponent.getcurrentcontroller.activesheet
oCellCursor = oAktuellesBlatt.createCursor()
oCellCursor.GotoEndOfUsedArea(True)
iEnd_Row = oCellCursor.getRangeAddress.EndRow
Nach einigen Tests habe ich den Eindruck, dass der Cursor, wenn er gebraucht wird, immer neu „created“ werden muss.
Jetzt habe ich, weil das so oft vorkam und so eine unschöne Verlängerung des Codes in den einzelnen Subs verursacht hat, ein Modul „Funktionen“ angelegt und das dahin verschoben.
Die Funktion wird jetzt mit ClZ aufgerufen (Cursor letzte Zeile).

Dank deiner Erläuterungen zu unserem vor Kurzem ebenfalls neu erstellten Modul „Text-Mitteilungen“ klappt der Aufruf auch.
:D
Nein wie wunderschön, das Du selber auf die Idee gekommen bist. Doch, das erfreut mich wirklich sehr. *schön-schön*

Das freche an der ganzen Sache ist aber, GENAU DAS hatte ich mir für heute schon vorbereitet gehabt. Und jetzt hast Du mir meine Arbeit einfach so mir-nix-dir-nix geklaut. Frechheit. Bild

Jetzt aber ernsthaft.
Ich wollte dir anhand genau dieser "Problematik" etwas anderes zeigen und Erklären, aber dann dachte ich mir; warum das? Das geht genau so gut auf diese einfache und funktionierende Weise, als wenn man das technisch "hochfrisieren" würde. Und ja, mein vorbereiteter Beitrag hatte wirklich deine selbst erstellten Codezeilen drin gehabt.

Das Du jetzt das ganze selber in Angriff genommen hast, zeugt doch davon das Du was gelernt hast und das auch nutzbringend anzuwenden weißt. Das ist doch gut so.


Wenn man in die von mir zuletzt eingegebene Zeile in die Spalte "Mindereinnahmen" klickt, sieht man oben in der Leiste nicht den eigentlichen, einfachen Wert „0“, sondern einen negativen, nämlich „-2,22044604925031E-016“.
Dadurch ändert sich in diesem Fall auch die Darstellung in -0,00 € statt - €.
Diesbezüglich habe ich damals das Internet tagelang durchforstet, weil ich nämlich alle Werte mit Null wegfiltern wollte und das dann deswegen nicht ging und ich es per Hand erledigen musste.

Ich wage gar nicht zu hoffen, dass du die Lösung kennst…!?
Jetzt erstmal ein klein wenig Kritik.
Es hilft mir doch schon sehr, wenn Du erklärst was Du aufrufst, was Du wo eingibst und welche Subs daran beteiligt sind. Denn so musste ich erstmal suchen welche Sub und welche Zeile innerhalb dieser Sub etwas einträgt. Aber nun gut, ich bin ja weitestgehend fündig geworden, wer was wo. Und die Problemlösung folgt anschließend.

Also es geht ab in die Sub Neuer_Artikel im Modul Artikel.

Das Problem liegt darin, das die Berechnungen dort mit Single-Variablen durchgeführt wird. Und diese Variable kann eine ganz schön lange Zahl hinterm Komma aufnehmen. Und das Makro rechet auch damit immer schön weiter. Und so kommt dann am Ende schlußendlich diese Gigantische Nachkommastelle zustande.

Beseitigung des Problemsd ist recht einfach.
Vor dem Kommentar

Code: Alles auswählen

' Sheet "Stamm" nach Artikeltext (sTxt_Art) und ListenPreis(sgEP_Art) durchsuchen
setzt Du noch eine Variablen Deklaration ein.

Code: Alles auswählen

	DIM MindEinnahme_Art AS Currency
Und schon ist auch dies Problem gelöst.


Tja, und nun kommt es ganz Dicke, leider.
Erst heute habe ich eine Sache festgestellt, wonach ich eigentlich sonst immer sehr früh und rechtzeitig nachgeschaut habe, doch diesmal leider nicht.

Ich habe nämlich festgestellt, das die Datei entweder auf irgendeine Art und Weise Kontakt mit Excel hatte, oder aber sie als *.xls zwischendurch mal gespeichert wurde.

Und das geht in diesem Falle aboslut überhaupt gar-nie-nie-nicht!

Die Datei darf aus Sicherheitsgründen nur noch als *.ods gespeichert werden. Alle anderen Dateiformate wie z.B. *.xls sind absolut Tabu.

Und das bedeutet jetzt für dich, mach die Datei komplett NEU. Denn nur so sind wir auf der sicheren Seite. Aus Erfahrung weiß ich das es ansonsten zu merkwürdigem Verhalten der Datei kommen kann.

Um dir aber wenigsten etwas arbeit abzunehmen, habe ich im Anhang eine fast Blanko-Datei wo nur die ganzen BASIC-Module und die Dialoge schon drin sind. Du musst jetzt nur zusehen das Du die Tabellenblätter neu erstellst.

Aber achte dringends darauf das Du aus der anderen Datei nix, aber auch absolt reine weg gar nix per "Strg + C" -> "Strg + V" reinkopierst. Denn dadurch kopierst Du dann ansonsten wieder alles aus der alten Datei darein. Und das muss ja unbedingt vermieden werden.

Wenn Du Formeln oder Zellinhalte kopieren willst/musst, dann aber nur per "Strg + C" -> "Strg + Umschalt + V" -> "Unformatierter Text".

Aber auf gar keinen Fall irgendwelche Bedingte Formastierungen, Zellformatierungen oder Formatvorlagen. All die sind einfach Tabu. Du musst die dann halt alle in der neuen Datei neu erstellen.

Eine kleine Arbeitserleichterung.
Lege in *Meine Makros* -> *Standard* ein Modul an, und kopiere folgendes kleines Makro in dies Modul rein.

Code: Alles auswählen

sub Unformatiert
dim document   as object
dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "SelectedFormat"
args2(0).Value = 1
dispatcher.executeDispatch(document, ".uno:ClipboardFormatItems", "", 0, args2())
end sub
Anschließend fügst Du der Symbolleiste einen neuen Eintrag hinzu der auf dies Makro zugreift, suchst dir ein Symbol aus, und schon kannst Du per "Knopfdruck" Unformatierten Text einfügen.

Jetzt ist aber Schluß. Will in die Heia.
Bild


Gruß
balu
Dateianhänge
TEMPORAERES-POS_0.0.ods
(23.99 KiB) 716-mal heruntergeladen
Sei öfter mal ein Faultier, sag öfter mal "Ach was!" Dann kriegst du keinen Herzinfarkt, und hast ne menge Spass.

wehr rächtschraipfähler findet khan si behalden :D
Benutzeravatar
Julia NuN
**
Beiträge: 38
Registriert: Mo, 07.11.2016 14:57

Re: Erarbeitung eines "POS-Kassenbuchs"

Beitrag von Julia NuN »

Hallo balu,
Jetzt erstmal ein klein wenig Kritik.
Es hilft mir doch schon sehr, wenn Du erklärst was Du aufrufst, was Du wo eingibst und welche Subs daran beteiligt sind. Denn so musste ich erstmal suchen welche Sub und welche Zeile innerhalb dieser Sub etwas einträgt.
Eijeijei - das tut mir Leid! Recht hast du. Ich werde mich bessern.

Code: Alles auswählen

DIM MindEinnahme_Art AS Currency
Ich habe das jetzt nicht überall eingefügt. Ich schätze mal, das Phänomen wird noch anderweitig auftauchen. Aber das mache ich dann.
Aber achte dringends darauf das Du aus der anderen Datei nix, aber auch absolt reine weg gar nix per "Strg + C" -> "Strg + V" reinkopierst. Denn dadurch kopierst Du dann ansonsten wieder alles aus der alten Datei darein. Und das muss ja unbedingt vermieden werden.

Wenn Du Formeln oder Zellinhalte kopieren willst/musst, dann aber nur per "Strg + C" -> "Strg + Umschalt + V" -> "Unformatierter Text".

Aber auf gar keinen Fall irgendwelche Bedingte Formastierungen, Zellformatierungen oder Formatvorlagen. All die sind einfach Tabu. Du musst die dann halt alle in der neuen Datei neu erstellen.

Eine kleine Arbeitserleichterung.
Lege in *Meine Makros* -> *Standard* ein Modul an, und kopiere folgendes kleines Makro in dies Modul rein.

Code: Alles auswählen

sub Unformatiert
dim document   as object
dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "SelectedFormat"
args2(0).Value = 1
dispatcher.executeDispatch(document, ".uno:ClipboardFormatItems", "", 0, args2())
end sub
Anschließend fügst Du der Symbolleiste einen neuen Eintrag hinzu der auf dies Makro zugreift, suchst dir ein Symbol aus, und schon kannst Du per "Knopfdruck" Unformatierten Text einfügen.
Das habe ich hinbekommen. Für alle, die das hier lesen und kein passendes Icon haben, lade ich hier das meinige hoch.
icon_unformatierter_text.png
icon_unformatierter_text.png (1.04 KiB) 19894 mal betrachtet
Naja, sieht ein bisschen schief aus... aber es hat die gefragten 26x26 Pixel.
Das war ein ganz schöner Ausflug in etwas, womit ich mich noch nie beschäftigt habe, obwohl ich es längst hätte müssen: Anpassen der Symbolleisten.

Und wer nicht hören will... Ich hab tatsächlich, ungeduldig wie ich war, folgenden unterstrichenen Teil überlesen:
Wenn Du Formeln oder Zellinhalte kopieren willst/musst, dann aber nur per "Strg + C" -> "Strg + Umschalt + V" -> "Unformatierter Text".
:evil:
Das habe ich dann bemerkt, als ich fertig war mit der Neuerstellung. Wobei das vllt. nicht Not getan hätte - ich hatte die Formeln aus der Eingabezeile in die Eingabezeile kopiert. Aber ich wollte dann doch auf Nummer sicher gehen und habe alles noch einmal gemacht.

Zum automatischen Scrollen:

Code: Alles auswählen

sub SprungZurZelle
	oDok = thisComponent
	oViewController = oDok.CurrentController

	oAktSheet = oDok.sheets().getbyName(oViewController.activesheet.getName)
	aAktCursor = oAktSheet.getCellByPosition(0, 10) 'die gewünschte ZellPosition'
	
	oViewController.Select(aAktCursor) 'Der eigentliche Sprung zu der Zelle'
  
end sub
Das ist wirklich gar nicht so einfach. Ich hatte das zwar auch beim Dannenhöfer gefunden, aber nicht verstanden, dass es der richtige Code war.
Ich habe ihn jetzt so angepasst:

Code: Alles auswählen

aAktCursor = oAktSheet.getCellByPosition(0, iEnd_Row+10) 'die gewünschte ZellPosition'
Das funktioniert prima. Vielen Dank!
Übrigens hast du mir ja die ganze Arbeit abgenommen! Ich hatte den Code "SprungZurZelle" in die Sub "Funktionen" hineinkopiert und dabei gar nicht gemerkt, dass du das ja schon erledigt hattest. Beim Ausführen hat er dann gemault, weil doppelt.

So, jetzt lade ich das mal hoch - wird auch Zeit.

Liebe Grüße Julia
Dateianhänge
POS_Kassenbuch_Forum_8.ods
(52.79 KiB) 756-mal heruntergeladen
Wilhelm Busch: "Ein jeder Wunsch, wenn er erfüllt, kriegt augenblicklich Junge."
... ich glaub, der wär heutzutage Programmierer und nicht Schriftsteller.
Benutzeravatar
balu
********
Beiträge: 3810
Registriert: Fr, 24.08.2007 00:28
Wohnort: Warstein

Re: Erarbeitung eines "POS-Kassenbuchs"

Beitrag von balu »

Hallo Julia,

also dann wolln ma mal wieder.

Finde ich ja echt Klasse von dir das Du ein extra Icon für die kleine Sub erstellt hast. Ich hatte in der Icon Sammlung von OO.o eins gefunden welches mir sofort zusagte. Das wird wohl anscheind in einem anderen Modul irgendwo angewendet, aber es ist mir bis jetzt noch nicht untergekommen und deshalb verwende ich dieses dafür.
Icon.jpg
Icon.jpg (1.1 KiB) 19805 mal betrachtet
Es erinnert mich irgendwie an einem Scheibenwischer von einem Auto. Per Knopfdruck wird Regen und sonstiger Schmutz einfach weggewischt. ;-)

Und wer nicht hören will...
Nun ja, jedem passieren manchmal die dollsten Fehler. Da meint man das man alles richtig gemacht hat, und "PÄNG" machts, weil man doch mal was übersehen hat. Ergeht mir doch nicht anders.

A-propo Fehler.
Du hast vergessen etwas zu deklarieren. Defeniert hattest Du es ja, aber halt nicht deklariert. Und zwar gehts um sgPreis_Fl. Also bitte nachholen.


So, und nun mal wieder zurück zum Thema Array.

"Schon wieder Array!?"

Yep! Und diesmal wirds etwas "Abstarkter".

Denn heute wollen wir eine elegantere Version für die schon von dir ersetzte SVERWEIS anwenden. Doch leider ist sie auch etwas Umfangreicher. Aber dafür hat sie auch einige Vorteile, die einem doch so einiges erleichtern kann.

Mit einer reinen Makroaktion kann man sehr vieles bedeutend schneller erledigen, als eine ständige Interaktion zwischem Makro und Tabellenblatt. Jedoch ist der Preis dafür der, das der Makrocode länger wird. Ist leider so.

Du weißt ja wie eine SVERWEIS in einem Tabellenblatt funktioniert. Und dein Ersatz im Makro ist für dich auch leicht nachvollziehbar. Auch ist das bisherige Thema Array, so wie ich es dir erklärt hatte, auch nicht so sehr schwer zu verstehen. Doch jetzt musst Du dich ein wenig zusammenreißen, weil es von der Logik her etwas schwerer wird.

Dein bisheriger SVERWEIS Ersatz arbeitet ja nach folgendem Prinzip.
Im Makro Suchbedingung nehmen. Im Tabellenblatt eine Zeile untersuchen. Wenn nix im Tabellenblatt in einer Zeile gefunden, nächste Aktion vom Makro starten, was bedeutet die nächste Zeile im Tabellenblatt untersuchen.
Und diese Spielchen wird Zeile für Zeile im Tabellenblatt durchgeführt. Und je länger eine Liste im Tabellenblatt ist, um so Länger dauert diese ganze Aktion.

Jetzt müsste es eine Möglichkeit geben die Liste aus dem Tabellenblatt blitzschnell in den Arbeitsspeicher zu laden um die Liste dort zu untersuchen.


Und diese Möglichkeit gibt es. Und das sieht wie folgt aus.

Wir befinden uns im Modul *Flaschenverkauf* in der "Sub Neuer_Flaschenverkauf".

Code: Alles auswählen

DIM oData
oData1  = oBlattStamm.getCellRangeByName("A3:D199")
oData = oData1.getDataArray()
Damit haben wir den gesamten Inhalt aus dem Datenbereich A3 bis D199 in den Arbeitsspeicher geladen. Wir haben jetzt also 4 Spalten und 197 Zeilen dort plaziert. Und in Makrosprech heißt das: Spalten 0 bis 3, und Zeilen 0 bis 196.

So, und nun wollen wir die Daten aber auch untersuchen/vergleichen und auslesen.
Dazu wird das alt bekannte Prinzip FOR...NEXT gekoppelt mit IF...THEN angewendet. Anfangen tun wir mit der Schleife. Da es sich hierbei ja um ein Array handelt, und wir schon das Grundprinzip dafür besprochen haben, dürfte die folgende Zeile nicht unverständlich sein.

Code: Alles auswählen

for iGF = LBound(oData()) to UBound(oData())
Und ab jetzt wird es im IF Teil ein wenig verwirrend.

Code: Alles auswählen

if oData(iGF)(0) = iArtikelnummer_Fl then
Bis jetzt warst Du es ja eigentlich gewohnt das bei Arrays hinter dem Arraynamen nur eine Klammer zu sehen war. Doch jetzt sind es gleich 2 Klammerpaare.

Nun, das muss ja so sein, weill wir ja eine Mehrspaltige und Mehrzeilige Liste im Arbeitsspeicher haben. Ist klar, oder?

Jetzt gibt es aber eine Besonderheit gegenüber der normal üblichen Zelladressierung per Makro die ja wie folgt aussehen kann.

Code: Alles auswählen

getCellByPosition(0, 0)
getCellRangeByName("A9")
Hier ist es selbstverständlich das erst die Spalte, und dann die Zeile benannt wird.

In diesem Array fall ist das aber anders.

Code: Alles auswählen

oData(iGF)(0)
Denn hier kommt erst die Zeile (erstes Klammerpaar), und dann die Spalte (zweites Klammerpaar). Hier heißt es also Umdenken. Aber auch nur in diesem speziellem Falle, die anderen besprochenen Arrays sind nicht davon betroffen.

Damit wäre die erste Hürde genommen, die auch für den Anfang etwas schwer zu verdauen ist. Und glaub mir, das gilt auch aktuell für mich, da ich erst seit ein paar wochen mich mal grob damit befasst habe.

Aber weiter gehts im Text, in dem IF Teil.

Code: Alles auswählen

	sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Jetzt dürfte es eigentlich nicht mehr arg so schwer zu verstehen sein, was alles rechts neben dem Gleichheitszeichen (=) steht.

Eine Besonderheit gibts da aber dennoch, und zwar wird nicht der Wert direkt aus dem Arbeitsspeicher übernommen, da er aus unerklärlichen Gründen bei mir eine Kilometerlange Zahl zurückgeben würde, und ich deshalb den Wert mit CDec umwandle. Dies mache ich aber nur bei den Spalten C und D, da in der Spalte B Text drin steht der nicht umgewandelt werden muss.


Jetzt machen wir etwas was eigentlich zu erst hätte kommen sollen, aber das ist im Prinzip ein anderes Thema, und deshalb kommts jetzt ausnahmsweise fast zum Schluß.

Du arbeitest ja intensiv mit der Ermittelung der letzten Zeile in einem aktiven Tabellenblatt. Und um den neuen SVERWEIS flexibler einzusetzen, wenn es um die Größe der Liste geht, brauchen wir auch eine Ermittelung der letzten benutzen Zeile. Diese Zeile befindet sich aber immer im gleichem Tabellenblatt, wodurch sich deine bisherige Lösung nicht anwenden lässt. Also muss etwas anderes her, was ich ja auch schon parat habe. Nur kann ich dir nicht sehr viele dazu erzählen, wie der Aufbau so ist, da sie nicht von mir stammt, sondern von unserem Stephan.

Und hier ist das was ich meine.

Code: Alles auswählen

	With oBlattStamm ' Letzte Zeile der Spalte A  im Tabellenblatt Stamm ermitteln
		x = .Columns(0).queryEmptyCells()
		iLZ = x(x.Count-1).RangeAddress.StartRow  
	End With
iLZ gibt in diesem Falle die tatsächliche Zeilennummer zurück. Und diese Variable bauen wir dann auch noch in meine vorhin besprochene Änderung ein. Doch jetzt kommt erstmal die Passage im genannten Modul und in der dementsprtechenden Sub wie sie bis jetzt war.

Code: Alles auswählen

' Sheet "Preise" nach Text, der Getränkegröße in Liter und dem ListenPreis durchsuchen
	for tt40 = 0 to 500
	if oBlattStamm.getCellByPosition(0, tt40).Value = iArtikelnummer_Fl then
	sTxt_Fl =  oBlattStamm.getCellByPosition(1, tt40).String
	sgEinheit_Fl = oBlattStamm.getCellByPosition(2, tt40).Value
	sgListenpreis_Fl = oBlattStamm.getCellByPosition(3, tt40).Value
	
' Berechnung der Werte 
	sgAnzahl_Fl = sgFuellmenge_Fl/sgEinheit_Fl* iAnzahl_Fl
	Einnahme_Fl = sgPreis_Fl* iAnzahl_Fl
    EPRabatt_FL = sgPreis_Fl/sgAnzahl_Fl* iAnzahl_Fl
    sgRabatt_Fl = 100 - (EPRabatt_Fl * 100 / sgListenpreis_Fl)
    MindEinnahme_Fl = (sgListenpreis_Fl - EPRabatt_Fl)* sgAnzahl_Fl
    endif
    next tt40
Und nun die gesamte Überarbeitung.

Code: Alles auswählen

' Sheet "Preise" nach Text, der Getränkegröße in Liter und dem ListenPreis durchsuchen
	With oBlattStamm ' Letzte Zeile der Spalte A  im Tabellenblatt Stamm ermitteln
		x = .Columns(0).queryEmptyCells()
		iLZ = x(x.Count-1).RangeAddress.StartRow  
	End With
'	PRINT ILZ
	
DIM oData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   oData = oData1.getDataArray()			
	for iGF = LBound(oData()) to UBound(oData())
		if oData(iGF)(0) = iArtikelnummer_Fl then
	sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
	
' Berechnung der Werte 
	sgAnzahl_Fl = sgFuellmenge_Fl/sgEinheit_Fl* iAnzahl_Fl
	Einnahme_Fl = sgPreis_Fl* iAnzahl_Fl
	EPRabatt_FL = sgPreis_Fl/sgAnzahl_Fl* iAnzahl_Fl
	sgRabatt_Fl = 100 - (EPRabatt_Fl * 100 / sgListenpreis_Fl)
	MindEinnahme_Fl = (sgListenpreis_Fl - EPRabatt_Fl)* sgAnzahl_Fl
    endif
    next iGF

Und somit kommen wir zum heutigem Ende der Vorstellung. :lol:

Ich hoffe Du weißt wo Du jetzt im Makro was löschen und ersetzen kannst. Denke aber auch daran das Du das nicht nur in diesem einen Modul machen kannst, sondern auch noch wo anders.

Viel Glück und Spaß beim anwenden. ;-)
Bis die Tage.



Gruß
balu
Sei öfter mal ein Faultier, sag öfter mal "Ach was!" Dann kriegst du keinen Herzinfarkt, und hast ne menge Spass.

wehr rächtschraipfähler findet khan si behalden :D
Benutzeravatar
Julia NuN
**
Beiträge: 38
Registriert: Mo, 07.11.2016 14:57

Re: Erarbeitung eines "POS-Kassenbuchs"

Beitrag von Julia NuN »

Hallo balu,

hui, das war spannend!
Im Anhang befindet sich die überarbeitet Datei. An den meisten Stellen war das neue Array ja einfach nur einzufügen und anzupassen. Hab ich gemacht.

Aber dann wollte ich das auch noch bei der Korrektur einzelner Zeilen im Zusammenhang mit der ID-Suche anwenden. Man braucht ja auch ein wenig Übung, Vertiefung und eine kleine Eigenkreation… ;-)
Es hatte aber auch noch einen anderen Grund. Nämlich hatte der ursprüngliche Code das Manko, dass man nicht die zuletzt eingegebene Zeile korrigieren konnte - die hat er nicht gefunden. Die Frage, woran das liegt, war eine, die ich irgendwann mal stellen wollte (das musst du dir aber nicht im Detail ansehen, denn der Code ist jetzt schon veraltet - nur wenn du Lust hast).

Hier der alte Code aus der Sub Artikel_Korrektur. Irgendwie könnte das Problem beim iRowIndex liegen, den er nicht findet, wenn die Such-ID NrID_Korr sich in der letzten Zeile befindet:

Code: Alles auswählen

Sub Artikel_Korrektur
	oAktuellesBlatt = ThisComponent.getcurrentcontroller.activesheet

	NrID_Korr = oID_IDEingabe.value()
	ZeileID_Korr = NrID_Korr +1

For iRowIndex = 500 to 11 step -1 'rückwärts iterieren

If 	oAktuellesBlatt.getCellByPosition(0, iRowIndex).Value = ZeileID_Korr then
	Dlg_Korrektur.title = "Korrektur von ID Nr: " & NrID_Korr & ""
	Dlg_Korrektur.execute
	...
	oAktuellesBlatt.getCellRangeByName("B" & iRowIndex).String = sTxt_Korr
	oAktuellesBlatt.getCellRangeByName("F" & iRowIndex).Value = iArtikelnummer_Korr	
	oAktuellesBlatt.getCellRangeByName("G" & iRowIndex).Value = sgAnzahl_Korr
	oAktuellesBlatt.getCellRangeByName("H" & iRowIndex).Value = Einnahme_Korr
	...
Jedenfalls habe ich hier jetzt auch den neuen Code eingesetzt und das Problem ist weg:

Code: Alles auswählen

Sub Artikel_Korrektur
	oAktuellesBlatt = ThisComponent.getcurrentcontroller.activesheet
	NrID_Korr = oID_IDEingabe.value()

REM NEU******************************************************************************************		
' oAktuellesBlatt nach der Korrektur-ID durchsuchen
	With oAktuellesBlatt ' Letzte Zeile der Spalte A im Aktuellen Blatt ermitteln
		x = .Columns(0).queryEmptyCells()
		iLZ = x(x.Count-1).RangeAddress.StartRow  
	End With

   	oIDData1 = oAktuellesBlatt.getCellRangeByName("A11:A" & iLZ)
   	oIDData = oIDData1.getDataArray()			
	for iIDK = LBound(oIDData()) to UBound(oIDData())
		if oIDData(iIDK)(0) = NrID_Korr then
	iRowIndex = NrID_Korr +10
REM NEU Ende**************************************************************************************
	
	Dlg_Korrektur.title = "Korrektur von ID Nr: " & NrID_Korr & ""
	Dlg_Korrektur.execute
	...
	oAktuellesBlatt.getCellRangeByName("B" & iRowIndex).String = sTxt_Korr
	oAktuellesBlatt.getCellRangeByName("F" & iRowIndex).Value = iArtikelnummer_Korr	
	oAktuellesBlatt.getCellRangeByName("G" & iRowIndex).Value = sgAnzahl_Korr
	oAktuellesBlatt.getCellRangeByName("H" & iRowIndex).Value = Einnahme_Korr
	...
Ich hab hierzu dann noch diese Deklaration im Modul Artikel vor der Sub Dlg_Neuer_Artikel eingefügt:

Code: Alles auswählen

' Zellbereich'
Dim oCellRange_Mitarbeiter as Object, oData as Object, oData1 as Object
Dim oIDData as Object, oIDData1 as Object
Es läuft aber auch ohne das, hab´s probiert (ob ich das jemals mit der Deklaration begreifen werde, bezweifle ich...).
Und du hattest ja eine Deklaration angefangen mit deinem Code, den Du gepostet hast für die Sub Flaschenverkauf. Die Deklaration hab ich denn weggelassen... ;)

Code: Alles auswählen

...
DIM oData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   oData = oData1.getDataArray()			
	for iGF = LBound(oData()) to UBound(oData())
	...

Und jetzt ein kleiner Rückgriff, da die Schwierigkeit mit den kryptischen Zahlen, wie z.B. „-2,22044604925031E-016“ wieder aufgetaucht ist:

Code: Alles auswählen

DIM MindEinnahme_Art AS Currency
Ich habe das jetzt nicht überall eingefügt. Ich schätze mal, das Phänomen wird noch anderweitig auftauchen. Aber das mache ich dann.
Weil die Ursache hier wohl in der Verwendung der Preis-Elemente liegt, habe ich den Störenfried jetzt in der Deklaration am Schopfe gepackt und üble Auswirkungen im Keim erstickt (hoffe ich):

Code: Alles auswählen

' Preis - Elemente'
Dim oEP_PreisEingabe as Object, oPreis_Flaschen as Object, oListBox_Preis as Object
Dim cListenpreis_Fl as Currency, cPreis_Fl as Currency
Dim cEP_Korr as Currency, cEP_Ki as Currency

Und hier noch einmal ein verwandtes Thema mit Bezug zu deinem letzten Post:
Aber weiter gehts im Text, in dem IF Teil.

Code: Alles auswählen

sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Eine Besonderheit gibts da aber dennoch, und zwar wird nicht der Wert direkt aus dem Arbeitsspeicher übernommen, da er aus unerklärlichen Gründen bei mir eine Kilometerlange Zahl zurückgeben würde, und ich deshalb den Wert mit CDec umwandle. Dies mache ich aber nur bei den Spalten C und D, da in der Spalte B Text drin steht der nicht umgewandelt werden muss.
Ich hab aus Neugier bei Pitonyak CDec nachgeschaut. In der Kurzdefinition steht folgendes:
CDec :Generate a Decimal type; implemented only on Windows.
Könnten wir da vielleicht Probleme unter Ubuntu Mate bekommen?

Puuhh, also das war für mich ganz schön schwierig, die richtigen Teile hier reinzukopieren - ich brauch einen größeren Bildschirm... Oder eine Brille. 8)
... Ich hoffe, ich habe überall die richtigen Teile reinkopiert. :roll:

Bis bald, Kapitän - und gute Nacht!
LG Julia
Dateianhänge
POS_Kassenbuch_Forum_9.ods
(58.19 KiB) 746-mal heruntergeladen
Wilhelm Busch: "Ein jeder Wunsch, wenn er erfüllt, kriegt augenblicklich Junge."
... ich glaub, der wär heutzutage Programmierer und nicht Schriftsteller.
Benutzeravatar
balu
********
Beiträge: 3810
Registriert: Fr, 24.08.2007 00:28
Wohnort: Warstein

Re: Erarbeitung eines "POS-Kassenbuchs"

Beitrag von balu »

Hallo Julia,

Code: Alles auswählen

DIM oData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   oData = oData1.getDataArray()			
	for iGF = LBound(oData()) to UBound(oData())
		if oData(iGF)(0) = iArtikelnummer_Fl then
	sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Ja Upsi! Is mir da doch ein winzig kleiner Fehler unterlaufen. Ich beziehe mich aber auf den Variablennamen, und was ich bis jetzt immer so erklärt habe. Korrekter weise müsste das nämlich so aussehen.

Code: Alles auswählen

DIM aData
   oData1  = oBlattStamm.getCellRangeByName("A3:D" & iLZ)
   aData= oData1.getDataArray()			
	for iGF = LBound(aData()) to UBound(aData())
		if aData(iGF)(0) = iArtikelnummer_Fl then
	sTxt_Fl =  aData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(aData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(aData(iGF)(3)) '<- Spalte D'

Nämlich hatte der ursprüngliche Code das Manko, dass man nicht die zuletzt eingegebene Zeile korrigieren konnte - die hat er nicht gefunden.
Wenn ich das jetzt so mal auf die schnelle betrachte, dann kan ich nur folgendes dazu erklären.

Es ist ein Unterschied ob man NACH der letzten benutzen Zeile weiter etwas eintragen will. Oder ob man IN der letzten benutzen Zeile etwas eintragen/ändern möchte. Und je nachdem was man machen will, muss man entweder mit einem Korrekturwert arbeiten oder nicht.

Im ersten Falle muss ein Korrekturwert angegeben werden. Denn wenn eine dementsprechende Suchroutine erstellt wurde, egal ob die von mir gezeigte verkürzte Version oder deine, so geben sie normalerweise die letzte benutze Zeile zurück. Das heißt sie ist ja schon besetzt. Und da soll ja nix eingetragen werden, sondern eine Zeile weiter darunter. Also Korrekturwert Plus 1 (+1).

Im zweiten Falle entfällt der Korrekturwert, da die gefundene letzte Zeile ja die ist die man ändern möchte.

Lediglich der Korrekturwert muss so angepasst werden, damit er zu der Methode der Zelladressierung passt.

Code: Alles auswählen

getCellByPosition(0, 0) 
getCellRangeByName("A" +1)
Egal welche Methode man nimmt, am besten auf einfache Art und Weise vergleichen ob die richtige Zelle/Zeile gefunden wird. Dies macht man entweder mit PRINT oder MsgBox, ganz wie man will.


Julia NuN hat geschrieben: Ich hab hierzu dann noch diese Deklaration im Modul Artikel vor der Sub Dlg_Neuer_Artikel eingefügt:

Code: Alles auswählen

' Zellbereich'
Dim oCellRange_Mitarbeiter as Object, oData as Object, oData1 as Object
Dim oIDData as Object, oIDData1 as Object
Siehe hierzu auch meine oben ausgeführte Entschuldigung.
Jedoch:
oIDData1 ist korrekt deklariert, da getCellRangeByName ein Object ist.
oIDData ist aber nicht korrekt, da es es sich um ein Array handelt, getDataArray.


Es läuft aber auch ohne das, hab´s probiert
Verlass dich nicht darauf das es auch ohne läuft.

(ob ich das jemals mit der Deklaration begreifen werde, bezweifle ich...).
Kopf hoch. Wird schon werden. Ich weiss doch selber wie schwer das manchmal seien kann, und von daher bist Du ja nicht alleine damit.

Und hier noch einmal ein verwandtes Thema mit Bezug zu deinem letzten Post:
Aber weiter gehts im Text, in dem IF Teil.

Code: Alles auswählen

sTxt_Fl =  oData(iGF)(1) '<- Spalte B'
	sgEinheit_Fl = CDec(oData(iGF)(2)) '<- Spalte C'
	sgListenpreis_Fl = CDec(oData(iGF)(3)) '<- Spalte D'
Eine Besonderheit gibts da aber dennoch, und zwar wird nicht der Wert direkt aus dem Arbeitsspeicher übernommen, da er aus unerklärlichen Gründen bei mir eine Kilometerlange Zahl zurückgeben würde, und ich deshalb den Wert mit CDec umwandle. Dies mache ich aber nur bei den Spalten C und D, da in der Spalte B Text drin steht der nicht umgewandelt werden muss.
Ich hab aus Neugier bei Pitonyak CDec nachgeschaut. In der Kurzdefinition steht folgendes:
CDec :Generate a Decimal type; implemented only on Windows.
Könnten wir da vielleicht Probleme unter Ubuntu Mate bekommen?
Ob wir da Probleme bekommen, weiss ich noch nicht. Denn ich habe momentan leichte Schwierigkeiten auf meine VirtualBox zuzugreifen wo ich eine Linux-Mint installiert habe.
Aber das finde ich echt Klasse das Du bei Pitonyak nachgeschaut hast, hätte ich nicht mit gerechnet. Und ja, in der deutschen Version habe ich den gleichen Hinweis gelesen. Ich glaube da muss ich mich nochmal miteinander aussetzen.

Puuhh, also das war für mich ganz schön schwierig, die richtigen Teile hier reinzukopieren - ich brauch einen größeren Bildschirm... Oder eine Brille.
Nix Bildschirm! Nimm lieber gleich einen Beamer :lol:
Sorry, der musste sein. Auch wenn ich im Glashaus sitze, so werfe ich dennoch den ersten Stein. Ist doch nur Glas, und kein Spiegel.


Und nochmals sorry für die falsche schreibweise der Variablennamen.

Bis bald, Kapitän
Aye Aye, Smutje ;-)


Gruß
balu
Sei öfter mal ein Faultier, sag öfter mal "Ach was!" Dann kriegst du keinen Herzinfarkt, und hast ne menge Spass.

wehr rächtschraipfähler findet khan si behalden :D
Antworten