586.067 aktive Mitglieder*
5.346 Besucher online*
Kostenfrei registrieren
Einloggen Registrieren

Programmierung einer Finanzbuchhaltung in C, Die Rettung der Konsole

Beitrag 20.01.2012, 00:25 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Tja, ich komme seit 1 Jahr wenig zur Zerspanung.

Private Umstände. Sehr viel Streß, Umstellung und viele Kosten im satten 5stelligen Bereich. Da leidet das Hobby ein wenig. wink.gif

ÜBer meinen Steuerberater habe ich mich geärgert. Der berechnet mir mtl. 220 Euro, um gut sortierte und vorkontierte Belege in den Datev-Kontenrahmen zu übernehmen. Daneben, wenn man sich mit diesen Vorgängen selbst intensiv beschäftigt, ist es besser, das selbst zu machen. Mehr Transparenz, alles auf Knopfdruck.

Es gibt für die Buchführung jede Menge Software, die man für kleine Münze kaufen kann.

Erstens muß man die aber kaufen,

zweitens verlangen die i.d.R. jährliche Lizenzgebühren,

drittens ist die Software, und das ist das Argument überhaupt, nicht angepaßt.

Die machen die Software als eierlegende Wollmilchsau, für jeden recht, für keinen passend. Man benötigt Stunden, um die auf seine Bedürfnisse anzupassen, und das ganze Prozedere beim Buchen kann nicht wirklich angepaßt werden. Das ist nicht so, wie man es will, sondern ein endloses Klicken auf ungewünschten Feldern, deren Sinn mehr als fraglich erscheint.

Daher kam mir die die Idee:

Kann man in C eine Finanzbuchhaltung programmieren?

Antwort: in C kann man alles programmieren, natürlich auch eine Finanzbuchhaltung. Fragt sich nur, wieviel Aufwand das ist. Und wie sieht das mit den Schnittstellen aus, wenn man die Daten am Jahresende dem Steuerberater übergeben will?

Ich hab ungefähr 3 Wochen gebraucht, um das Grundgerüst zu erstellen,, und jetzt buche ich mit dem PRogramm die Geschäftsvorfälle von meinem Kleinbetrieb nach SKR03. Alles exportierbar. Ich kann alle Daten in Excel übernehmen. Ich schätze, Datev kann auch jedes Text-File übernehmen.

Funktioniert prächtig.

Alle Daten immer präsent, individuelle Auswertungsprofile auf Knopfdruck.

Besser als alles, und ich hab einiges probiert, was man so als Plattform kriegt.

Zeitersparnis gegenüber EIERLEGENDEN WOLLMILCHSAUPROGRAMMEN mindestens ca. 500%.

Für die Buchung meiner mtl. GEschäftsvorfälle (ca. 80-120 im Monat) benötige ich jetzt kaum mehr als eine dreiviertel Stunde.

Sagen wir 1 Stunde, man kann ja nicht mehr sparen als man zuvor ausgegegeben hat.

Auf die Rechnung vom Steuerberater umgerechnet, beträgt der Stundensatz für diese Übung also einmal im Monat ca. 220 Euro.

JEDEN MONAT.

Die Philosophie der Buchführung (SKR03) ist nicht logisch. Es schwankt immer zwischen Bilanzierung und EÜR. Der Kleinunternehmer muß ja keine Bilanz machen, keine Abrgenzung. Daher sind schon Lohnverrechnungskonten und dergleichen irgendwie blödsinnig bzw. überflüssig. Sie resultieren aus der DATEV-Kontierung, eine eierlegende Wollmilchsau, die sich auch für Großunternehmen noch eignen soll. Daß die Ertragskonten die Erträge im SOLL haben und die AUfwandskonten den Aufwand im SOLL; ist Pipifax. Ob man das Soll oder Haben nennt, ist unwesentlich. SOll ist ja nicht Soll, sondern die linke Seite, und Haben nicht haben, sondern die rechte Seite des Kontos. Die Begriffe sind KOnventionen, haben keinen wirklichen Wortsinn. Aktiv- und Passivkonten sind nichts als eine Umkehr des Vorzeichens. Rechnerisch ist eine EÜR rein mathematisch und streng logisch auf + und - zu reduzieren. Das ist das interne Gerüst des Programms, das rechnerisch aufgeht. PLUS gegen MINUS, nicht SOll gegen Haben. Denn wenn die Zugänge beim Bankkonto im SOLL stehen müssen, beim Aufwand aber auch im SOLL, ist das eigentlich eine Buchung SOLL gegen SOLL. Nur die Kontenarten verschleiern die Umkehr des Vorzeichens. Intern, rein mathematisch, ist die Buchung + gegen - exakt dassselbe.

Das ist aber nicht das Thema. Ich wollte etwas über die Grazie der C-Programmierung schreiben.

Ich liebe C-Programmierung. Aber sie hat ja keine Schnittstelle zu Grafik und Windows. Brauchen wir bei Zahlen und Tabellen aber nicht wirklich.

Computer= computare = rechnen.

Um das optisch ein bißchen aufzumotzen, habe ich erstmal die Konsole angefaßt.

Konsole sieht ja so aus:

weiß auf schwarz, in der Größe nicht angepaßt, für die Augen der reine Schrecken.

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 00:37 Uhr
Angehängte Datei(en)
Angehängte Datei  konsole.gif ( 39.7KB ) Anzahl der Downloads: 76
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 00:45 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

So siehts ja nun schon viel angenehmer aus:

Erstmal ist die Größe angepaßt, zweitens schwarz auf weiß besser als umgekehrt.

Die Routinen dazu sind aus dem Internet geklaut (bei C/C++ eine leichte Übung.

Ist Minutensache.
Angehängte Datei(en)
Angehängte Datei  konsole_updated.jpg ( 112.27KB ) Anzahl der Downloads: 87
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 01:11 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Also, vor das Programmieren hat der Herrgott die Klarheit über das gesetzt, was man programmieren will.

Die Philosophie muß stimmen.

Bevor ich jetzt zur C-Programmierung komme, daher noch einige Hinweise dazu.

Thema: zusammengesetzte Buchungssätze (Schulweisheit).

Wir zahlen Miete und NEbenkosten in einem Betrag per Überweisung.

Buchungssatz:

Miete + Nebenkosten an Bank.

ALso:

Miete = 1500

NK = 350 an Bank = 1850 Euro.

Das ist dann eine Splitbuchung, wie es normal gemacht wird.

Kann man für seine Bedürfnisse in C programmieren, ist aber überflüssig.

Rechnerisch völlig gleichwertig ist:

Miete 1850 Euro an Bank 1850 Euro.

Nun buchen wir die Nebenkosten von 350 in einem zweiten Buchungssatz natürlich nicht gegen Bank, weil dann der Ertrag berührt wäre (die Kosten würden höher), sondern wir buchen:

NK 350 an Miete 350.

Die Konten sehen dann so aus:

Miete Haben = 1850 Soll= 350 Saldo = 1500

Bank: Haben = 1850

Und die Rechnung geht auf.

Intern rechnet das PRogramm bei der Bank mit -1850, bei Miete mit +1850-350=1500, bei NK mit +350, und so ist es rechnerisch richtig.

Steuerberater würde ein Verrechnungskonto dazwischenschalten, damit NK nicht direkt gegen Miete gebucht wird,

Rechnerisch aber ist

+ gegen -

Plus gegen Minus

VÖLLIG IDENTISCH,

solange wir keien Abgrenzung machen wollen, und das ist bei EÜR auch vom Gesetzgeber gar nicht vorgesehen.

Wir können also Split buchen (zusammengesetzter Buchungssatz) oder zwei Buchungssätze machen, wovon der erste erfolgswirksam, der zweite erfolgsneutral ist. Die Frage ist eher nicht diese, sondern ob wir das händisch machen wollen oder automatisieren.

Ähnlich verhält es sich mit der Vorsteuer.

Wir können buchen auf Vorsteuer sofort abziehbar, mit 2 Prozentsätzen, oder Vorsteuer aufzuteilen. Die nicht abziehbare Vorsteuer ergibt sich erst am Jahresabschluß.

Ob wir das als zusammengesetzten Buchtungssatz buchen (netto + Vorsteuer gegen Bank) oder den Bruttobetrag reinbuchen und vom Vorsteuer-Konto gegen den Bruttobetrag (natürlich nicht gegen Bank, weil ertragswirksam), ist rechnerisch Jacke wie Hose.

Also zur Philosophie:

Es muß rechnerisch aufgehen. Dann ist es in Ordnung. Egal wie man dahin kommt.

Man kann die ganze Ertragsleiter vom Bankkonto (oder Kasse) ableiten:

Wenn die Kasse einen Ertrag hat (+), muß das Gegenkonto im (-) stehen (nicht im SOll oder Haben).

Dann geht das rechnerisch auf.

Verbindlichkeiten und Kauf auf Ziel sind bei einer EÜR-REchnung wirklich nicht angesagt, da nicht vorhanden.

Daran kranken diese SOLL gegen HABEN Buchführungsprogramme, daß sie zwei Herren dienen sollen.

Die Sache ist im Prinzip viel einfacher,aber das wollen die Herren Steuerberater natürlich nicht zugestehen, daß die Buchführung für einen Kleinbetrieb in einer Stunde pro Monat erledigt ist.

Sind zwar nur 220 Euro, aber jeden Monat.

Macht in 10 Jahren 25000 Euro.

Außerdem:

C-Programmierung macht Spaß.


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 01:29 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Machen wir mal eine Bilanzverlängerung:

Wir lassen unsere Erlöse vorfinanzieren für einen Vorfinanzierungsgebühr,

Wir buchen dann:

Bank an Erlöse (aus Vorfinanzierung)

Sieht konventionell so aus: Bank im Soll (Zufluß), Erlöse (Passivkonto) im Haben.

Plusminusbuchung sieht anders aus: Bank erhöht sich im +, Erlöse sind im - (Minus). SInd ja auch gleichzeitig Verbindlichkeiten gegenüber dem Vorfinanzierer.

Nun fehlen allerdings die Kosten für Vorfinanzierung, weil diese bereits abgezogen wurden vom Vorfinanzierer.

Wir hätten dann weniger Einnahmen und weniger Kosten, die Vorfinanzierungsgebühr wäre aber nicht erfaßt.

Diese GEbühr dürfen wir natürlich nicht gegen Bank buchen, weil die Erträge dann verfälscht würden, sondern wir buchen:

Gebühr (im Plus) gegen Erlöse. (im Minus)

Dann erhöhen sich die Gebühren im Plus (Aufwand) gegen Erlöse

Erfolg ist Bilanzverlängerung, nämlich mehr Einnahmen und derselbe Betrag als zusätzliche Kosten = Ergebnisneutral.

So einfach ist es mit der EÜR.

Alle Programme wollen so ein Mittelding machen zwischen EÜR und Bilanz, es ist keine klare Philosophie.

Man kann die +- Buchung aber ableiten vom zu versteuernden Ertrag, und die Sache geht rechnerisch und steuerrechtlich völlig korrekt auf.

Soviel zur Buchführung, ich komme jetzt zu meinem eigentlichen Thema, der Programmierung eines Finanzbuchhaltungsprogramms.

Meines ist schon fertig, war eine Sache von ca. 3 Wochen jeden Abend mal 2-3 Stunden drangesetzt und fertig.


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 01:45 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Die ganze Programmierung von solchen Programmen zur Erfassung von betriebswirtschaftlichen Daten ist

NICHT

wie wir die Daten im Rechner behandeln (natürlich rechnerisch und steuerrechtlich korrekt), sondern in welcher Form die Daten gespeichert werden sollen, nämlich in

DATEIEN.

Diese Dateien benötigen wir für unsere eigenen Zwecke, und zum Nachweis gegenüber dem Finanzamt btw. dem Betriebsprüfer. Sie müssen in einer Form vorliegen, daß sie SICHER dokumentieren und mit einfachen Mitteln AUSLESBAR sind.

Da kommt die alte Konsolenprogrammierung wieder zu neuen Ehren.

Denn jede Datei, die wir im Textformat speichern, kann man mit WIndows-Standardprogrammen lesen, wie Editor, Notepad oder sonstigen Textverarbeitungsprogrammen, z. B. Open Office.

Textdateien können importiert werden von Tabellenkalkulationen.

Dazu muß das Textfile ein Zeilenende haben, und das Trennzeichen muß überlegt sein. Nimmt man als Dezimaltrennzeichen das Komma, können die Feilder nicht durch Kommata getrennt sein, man kann dann z.B. ein Semikolon nehmen.

Open Office btw. Excel importieren diese Textdateien mit der Option "Einfügen aus Textdatei".

Dann wird angegeben, welches Trennzeichen und welche Notation, z. B. für Dezimaltrennzeichen PUNKT ist die Notation Englisch, Komma ist Deutsch.

Im Anschluß müssen die Textfelder formatiert werden, z. B. FLießkommazahlen wie PRozent erscheinen zunächst als einstellige Zahlen (3.22 ist dann 3), bis die Tabellenkalkulation die korrekte Formatierung übernommen hat.

Es ist also möglich,

ALLE

im Textformat gespeicherten selbst erzeugten Dateien in andere Programme zu übernehmen.

Und auszudrucken.

Die im Textformat erzeugten Dateien können vor dem Ausdruck noch formatiert werden (damit sie etwas netter aussehen).

Soweit zu den äußeren Rahmendingungen im Windows-Zeitalter zur Konsolen-Programmierung.

Altes bewährt sich.

Computer = computare = rechnen.

Darauf kommt es an.

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 01:48 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 02:33 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Umgang mit Dateiformaten in C

WIr behandeln Daten aus einer Finanzbuchhaltung natürlich so, wie sie vorliegen, als Teil eines größeren Datenkonstrukts.

Nämlich etwa:

Konto:

Hat Betrag, Umsatzsteuer, mindestens ein Gegenkonto, einen Text,einen Umsatzsteuer-Betrag, eine Ident-Nr usw.

Das kann man eigentlich nur als strukturierten Datensatz anlegen, heißt ja auch struct

struct {
int konto_nr;
float betrag;
} Unsinnsdatensatz;

Oder besser:

typedef struct{
int konto_nr;
float betrag;
} Unsinnskontensatz;

Dann kann man mit

Unsinnskonntensatz Meinkontensatz;

darauf zugreifen, sonst würde der Compiler sich beschweren, daß Unnsinnskontensatz kein Datentyp ist.

Unsinn, weil ein Datensatz für ein Konto viel mehr Felder enthalten muß.

Daneben wäre das Wichtigere eine Datenstruktur für den Buchungssatz, der mindestens folgende Felder enthalten muß:

Konto
Gegenkonto
Umsatzsteuerkonto
Die Beträge dazu
Eine Ident-Nr für den Buchungsssatz
Datum
Text

usf. , also eine Datenstruktur in allen Formaten von Text bis Fließkomma.

Also z. B.:

typedef struct{
int konto_nr;
int gegenkonto_nr;
int umsatzstrkonto_nr;
float brutto_betrag;
float umsatzsteuer_betrag;
float umsatzsteuer_prozent;
...
und so weiter
...
char buchung_text[50]
} buchungssatz;

buchungssatz bsatz; // hier wird für den definierten Type Speicherplatz angefordert, und zwar exakt in der Größe von

sizeof(buchungssatz)

den wir dann bei der Dateienverwaltung benötigen.

Am Rechner rumspielen ist EINES,

die Daten zuverlässig speichern, ist ALLES.


Es gibt in C zwei Arten von Dateizugriffen:

1. sequentiell (eines hinter dem anderen)

2. wahlfrei (random access, Datensätze gezielt aufsuchen)

und zwei Formate, um Daten zu speichern:

1. Text

2. Binär

Im Textformat speichert man Zeichenketten, die mit einem Nullzeichen begrenzt sind (nullterminierte Strings), welche aber, um in einer Datei auslesbar zu sein, noch eine Zeilenendemarkierung benötigen.

Der Nullterminator ist '\0' und wird von einigen, aber nicht von allen Standardfunktionen automatisch ans Stringende gesetzt (strncat tut das z. B. nicht, was katastrophale Programmabstürze zur Folge hat, wenn man es nicht berücksichtigt)

Der Zeilenterminator ist '\n' = NEW LINE, also Zeilenumbruch, und in Textdateien wesentlich, weil sonst der Filepointer im stream drüber hinwegliest und es Datensalat gibt. Jede Zeile muß mit NEW LINE abgeschlossen werden, sonst geht gar nichts.

Wie bekommen wir nun Zahlen in eine Textzeile, und vor allem: wie wollen wir aus der Textzeile im Anschluß unsere Zahlen wieder herauslesen?

Das ist, mit einem Wort, möglich, aber NICHT ZU EMPFEHLEN.

Jede kleinste Änderung bei der Formatierung der Strings kann dann sehr schwer einzugrenzende Seiteneffekte zu Folge haben, je nachdem, wie unstruktuiert die Zugriffe auf diese Strings im Programm verteilt sind, ist der Fehler sehr schwer einzugrenzen.

Es ist ja überhaupt die Hauptaufgabe bei der C-Programmierung, Speicher-Überläufe zu verhindern, da muß man sich freiwillig nicht noch welche aufhalsen.

Für eine Finanzbuchhaltung, also ein Programm, was Schnittstellen nach außen haben muß, ist meine Philosophie: Man muß Textdateien bereitstellen für den Export, aber man sollte mit ihnen nicht arbeiten.

Denn sehr viel effizienter sind die BINÄR-Dateien.

Diese werden Zeichen für ZEichen eingelesen und gespeichert und entsprechend ausgelesen.

Der Vorteil ist einerseits, daß SOnderzeichen, welche im Textformat unvorhersehbare Seiteneffekte auslösen können

->>>>>>>>>>>>>>>< habt ihr euch mal gefragt, warum online-Banking keine Sonderzeichen zuläßt???

->>>>>>>>>>>>>>> das ist die Antwort!

andererseits, daß sie einen sehr komfortablen Datenzugriff zulassen.

Nämlich wir müssen unsere Zahlen gar nicht in Text verwandeln und wieder vom Textformat in Zahlen(da gibt es unendlich viele denkbare Fehlerquellen), sondern wir speichern sie im orignären Format und können sie auch als solche ohne Umwandlung auslesen.

Wie das technisch geht, programmiertechnisch, dazu demnächst.

Grundsätzlich aber bietet das binäre Dateieformat eine sehr komfortable und auch zeitsparende Methode, um Daten zu speichern und auszulesen.

Nur daß sie ohne weiteres kein anderer lesen kann.

Ich hab mir daher überlegt, für meine FIBU, daß ich intern mit Binärdateien arbeite, und parallel dazu jede Binär-Datei als TExtformat kopiere.

An jedes Textformat kommt man mit jedem Texteditor heran, diese Dateien sind also

SICHERE DOKUMENTATIONEN,

falls bei einer Betriebsprüfung oder aus sonstigen Gründen mal Nachfrage aufkommt.

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 02:45 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 03:01 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Was ist der Vorteil, wenn man eine Finanzbuchhaltung selbst programmiert?

Das hängt natürlich auch mit den Vorlieben desjenigen zusammen, der es macht.

Der unbedingte Vorteil ist, daß eine solche PRogrammierung auf den Leib geschneidert ist (Maßanzug).

Der Nachteil ist keiner, sie ist nicht unbedingt übertragbar auf andere, denn der Maßanzug soll ja gar nicht übertragbar sein.

Andererseits ist es aber so, wenn ein PRogramm gut strukturiert ist, also aus Bausteinen besteht, die relativ abstrakt gehalten sind, daß man diese Bausteine reicht einfach anders komponieren und auf ähnliche Problemstellungen relativ mühelos übertragen kann.

Kommen wir mal zu der BWA, wie man sowas theoretisch programmiert.

Wir haben unsere KOnten, für die wir mit einer Schleifenanweisung mit wenigen Zeilen einen Abschluß erzeugen können.

Nun gibt es Erlöskonten, Aufwandskonten und ertragsunwirksame Konten, und dsa muß fßr die Gewinnermittlung berücksichtigt werden.

Es ist sehr einfach, das zu tun.

Wir sammeln die für die BWA ertragswirksamen Konten in Gruppen von Erträgen und Aufwand, wir versammeln also die einzelnen Konten nach einem Schema für die steuerliche Würdigung, machen den Saldo und fertig.

Das ist fast schneller gemacht als man es hier schreibt.

Am Ende des Jahres steht dann die Auflösung der Verrechnungskonten für den Jahresabschluß, z. B. aufzuteilende Vorsteuer läßt sich während des Jahres eben nicht auflösen und wird beim Jahresabschluß saldiert in nicht abziehbare und abziehbre Vorsteuer.

Man könnte solche einfachen Aufgaben im Prinzip auch mit EXCEL erledigen, nur daß die Fehlerquote bei solchen Tabellenkalkulationen natürlich endlos ist.

Excel ist das Maximum an Fehlern, die man machen könnte.

Eine strukturierte PRogrammierung ist dsa genaue GEgenteil davon.

Man kann jede Eingabe sofort und auch nachträglich logisch prüfen, genau das ist ja der Vorteil der Programmierung gegenüber solchen Programmen, wo jeder alles eintippen kann.

Wie gesagt, für meine FIbu hab ich ungefähr 3 Wochen jeden Abend ca. 2-3 Stunden drangesessen und jetzt ist die Version soweit, daß schon alle GEschäftsvorfälle im Jan 2012 erfaßt sind.

Es macht Spaß, spart 220 Euro im Monat und natürlich werd ich das PRogramm bis Jahresende noch verfeinern.

Demnächst mal zu den Feinheiten der Programmierung in C.

Dazu ließe sich viel sagen. Bin bisher noch nicht dazu gekommen.


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 15:25 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Nochmal was zur Buchführung. Wir haben

einfache Buchungssätze Konto1 gegen Konto2

zusammengesetzte Buchungssätze (mehr als 2 Konten berührt)

-Typ 1: Anteile der anderen Konten sind bekannt, kann automatisch gebucht werden (Z. B. alle Vorfälle mit festen Umsatzsteuersätzen)

-Typ 2: Art und Zusammensetzung verschieden, aber bekannt weil periodische Wiederholung (Z. B. Abbuchung von mehreren Leasingverträgen in einer Summe)

-Typ 3: Art und Zusammensetzung verschieden, aber unbekannt. (Z. B. eine Provisionszahlung in einer Summe, die mehrere Mitarbeiter betrifft, die dazugehörige Abrechnung ist aber noch nicht erstellt).

Den Typ 1 kann man völlig automatisieren, indem man für jede USt-Option ein Umsatzsteuerkonto festlegt, also 19% abziehbar, 19% abzuführen, 7% aufzuteilen usf. Der Anwender muß dann nur noch die Umsatz-Steuer-Option angeben (1...n)

Den Typ 2 kann man mit Buchungsstapeln automatisieren. Das empfiehlt sich, wenn die Geschäftsvorfälle komplex sind, z. B. 5 verschiedene Leasingverträge mit unterschiedlichen USt-Optionen in einer Summe abgebucht werden. Der Nachteil ist, wenn sich die Beträge im laufenden Geschädftsjahr ändern, daß man den Stapel zwar anpassen kann, aber rückwirkende Buchungen mit diesem Stapel dann zu Fehlern führen können.

Für den Typ2 bietet sich an, was man beim Typ3 sinnvollerweise sowieso macht, daß man

(1) zunächst mal den Gesamtbetrag auf ein Sammelkonto bucht (=Geschäftsvorfall ertragswirksam erfaßt)

(2..n) dann Zug um Zug alle betroffenen Konten gegen den Sammler ausbucht. Am Ende muß das Sammelkonto einen Saldo von exakt 0.0 haben, sonst sind die Buchungen nicht vollständig.

Programmiertechnisch ist das ziemlicher Kinderkram.

Das große Problem bei der Programmierung von Anwendungen ist die Schnittstelle mit dem Anwender.

SCHNITTSTELLE ANWENDER

Diese muß einigen Voraussetzungen genügen, nämlich:

- soll den Anwender über den laufenden Vorgang ausreichend informieren (ist bei vielen Branchenlösungen nicht der Fall)

-soll technisch falsche Eingaben vermeiden (z. B. Vertipper oder ungültige Zahleneingaben)

-soll logisch falsche EIngaben abfangen (z.B. verkehrt herum gebucht etc.)

Je mehr man das Programm auf solche Weise "maßschneidert", umso weniger portabel ist es natürlich.

Die Schnittstelle hat aber von der Konsolenprogrammierung her gesehen noch ganz andere PRobleme, nämlich eine grafisch/optisch vernünftige Bedieneroberfläche zu schaffen und dafür die VOraussetzungen.

Nichts davon bringt die Programmiersprache C von sich aus mit.

Wie man sieht, hab ich die Konsole erstmal verbreitert, damit mehr als 80 Textzeichen untergebracht werden können, sowie Hintergrund und Textfarbe geändert. Auf einem Monitor mit ca. 1900 Pixeln Breite kann man so problemlos ca. 160-200 Zeichen in der Breite unterbringen, und ca. 50 Zeilen in der Höhe, ohne daß das Fenster über den Rand hinausschreibt, also mit der Maus wieder zurechtgesetzt werden muß.

Dieser Bereich entspricht ungefähr dem, was man hätte, wenn man ein A4 Blatt quer bedrucken will, und ist mehr als ausreichend für die Aufgabe, Zahlen in Tabellenform zu erfassen und formatiert auszugeben.

Wichtig ist nun, daß man die Zeichen nicht zeilenweise ausgibt, sondern die Position des Cursors wahlfrei festlegt, nämlich Spalte/Zeile.

Dazu gibt es aus guten alten DOS Zeiten die Funktion gotoxy(spalte, zeile), die in C nicht existiert.

Zweitens benötigt man eine Funktion, um den Bildschirm zu löschen.

Beides kann man sich leicht selbst programmieren:

void gotoxy ( short x, short y )
{
COORD coord = {x, y};
SetConsoleCursorPosition ( GetStdHandle ( STD_OUTPUT_HANDLE ), coord );
}

setzt den Cursor an die gewünschte Position. Die Syntax ist ein Windows-Systemaufruf

Den Bildschirm zu löschen ist ebenfalls ein Systemaufruf:

void clrscr(){system("cls");}

Hier ist die Routine, um den Bildschirm auf die gewünschte Breite und Höhe zu justieren:

void ResizeConsole(short x, short y)
{
HANDLE hStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

CONSOLE_SCREEN_BUFFER_INFO Info;
SMALL_RECT rcWindow;

// Aktuelle Fenster- und Buffergröße
GetConsoleScreenBufferInfo(hStdout, &Info);

// Neue Fenstergröße
rcWindow = Info.srWindow;
rcWindow.Right = x;
rcWindow.Bottom = y;

// Neue Buffergröße, wenn nötig
COORD size = Info.dwSize;
if (size.X < x) size.X = x+1;
if (size.Y < y) size.Y = y+1;

SetConsoleScreenBufferSize(hStdout, size);
SetConsoleWindowInfo( hStdout, TRUE, &rcWindow);
}

... mit der dazugehörigen Funktion, welche das aufruft:


void konsole_anpassen()
{
ResizeConsole(KON_BREITE,KON_HOEHE);
}

Wir können uns damit den Konsolen-Bildschirm so zurechtmachen, wie es paßt.

Um Teilbereiche des Bildschirms zu löschen, geht man so vor, daß man in die entsprechende Zeile springt und einen Leerstring ausgibt, also eine Reihe von Leerzeichen, welche dann die bisherigen Zeichen überschreiben=löschen.

Die Länge dieser Leerstrings muß natürlich passen, sonst überlappt das in andere Bildschirmbereiche.

Dazu kann man sich den Bildschirm von vornherein aufteilen in Funktionsbereiche, sagen wir mal das Hauptprogramm soll oben links Zeile 0 bis Zeile 40 und Spalte 0 bis Spalte 79 laufen. Rechts davon der Bereich ist vorgesehen für Tabellen und sonstige Hilfefunktionen. Darunter der Bereich ist vorgesehen für Meldungen und Abfragen.

Wir hätten dann den Bildschirm in 3 nebeneinanderliegende Fenster aufgeteilt, die separat verwaltet werden.

Abbildung zeigt einen screenshot aus dem laufenden Programm, wo man das schön erkennen kann.

Wir haben hier den linken Bildschirmbereich für den Dialog, den rechten für das Hilfemenu.

Und sehen eine KONTEXTSENSITIVE Hilfestellung, die sich also automatisch aktiviert (besser als alles, was mit Fenster anklicken zu tun hat, weil ergonomischer)

Das Problem beim Buchen ist ja: auf welches Konto? Also will man die verfügbaren Konten nachschlagen.

Das Programm macht nun folgendes:

Sobald der Anwender die erste Ziffer der vierstelligen Kontonummer eingibt, zeigt es rechts die gesamte Kontenklasse mit allen Unterkonten.

Gibt der Anwender die zweite Ziffer ein, sagen wir Nr.1 = 4, Kontenklasse 4, 2. Ziffer =2, zeigt das PRogramm alle Unterkonten mit der Ziffernfolge 42xx

Das macht es, ohne daß man umständlich irgendein Fenster hätte öffnen, resizen, verschieben und schließen hätte müssen.

KONSOLE ist für solche Anwendungen meiner Meinung nach SEHR VIEL BESSER als bunte Windows-Anwendungen.

Was man nicht sieht, der untere Bereich (die letzten 5 Zeilen) bildet den Ort für Meldungen, Warnungen und Abfragen.

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 15:25 Uhr
Angehängte Datei(en)
Angehängte Datei  screenshot1.jpg ( 294.47KB ) Anzahl der Downloads: 30
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 15:36 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Die Screenshots zeigen das sehr schön.

Geht man im zweiten Schritt auf Ziffer 2, werden nur noch die Konten 42xx angezeigt. (Abb scr2.jpg)

Die Eingabe der 3. Ziffer reduziert die Anzeige auf ein einziges Konto, welches übrig bleibt. (Abb scr3.jpg)

Wenn man nun nicht zufrieden ist, kann man mit der BACKSPACE Taste zurück zur ersten Position und sieht wieder die gesamte Kontenklasse (hier KK 4), Abb scr4.jpg

Das geht ohne jede Zeitverzögerung, ohne Klicken und Verschieben oder Scrollen, viel schneller, als das Windows-Anwendungen mit vielen Fenstern können.

Man ist mindestens um den Faktor 500% schneller als mit jeder Windows-Anwendung, die ich bisher gesehen habe.
Angehängte Datei(en)
Angehängte Datei  scr2.jpg ( 127.62KB ) Anzahl der Downloads: 20
Angehängte Datei  scr3.jpg ( 111.05KB ) Anzahl der Downloads: 16
Angehängte Datei  scr4.jpg ( 299.9KB ) Anzahl der Downloads: 22
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 16:18 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Wie man sowas programmiert, ist eigentlich klar.

Die Frage hier ist, wie programmiert man das in C? Eine Sprache, die sehr sparsam mit Standardfunktionen ist und den Programmierer nötigt, fast alles zu Fuß zu erledigen.

Nun, hat man die Daten erstmal erfaßt, geht also in die eigentliche Datenverarbeitung über, bietet C mehr als man braucht.

Das PRoblem ist die Anwenderschnittstelle.

ALLE STANDARDFUNKTIONEN von C sind, im Dialog mit der Konsole, extrem UNSICHER.

Das Hauptproblem ist der BUFFER_OVERFLOW, das Beschreiben von Bereichen, die dafür nicht vorgesehen sind. Das kann man absichtlich erzwingen, oder auch durch nachlässige Programmierung unabsichtlich zulassen.

Im günstigen Falle stürzt das Programm sofort ab.

Im ungünstigen Falle verhält es sich gelegentlich, aber nicht immer, etwas seltsam.

Fehlerursache in C ist fast immer das Beschreiben von nicht reservierten Bereichen. Index-Überlauf, Pointer nicht initialisiert, Buffer-Größe zu klein, falscher Datentyp übergeben etc. etc..

Daher kann man dem Anwender nicht wirklich eine scanf() oder vergleichbare Funktion zur EIngabe vorsetzen. Nur ´ne Frage der Zeit, bis da was schief läuft.

Sichere Eingaben erzielt man, indem man die Tastatur zeichenweise ausliest und die benötigten Datentypen selbst kreiert.

Eine solche "sichere" Funktion ist getch(), welches ein Zeichen von der Tastatur liest. Damit kann man niemals einen Überlauf provozieren.

Um so vorzugehen, benötigt man für verschiedene Datentypen verschiedene Funktionen. Dies sind mindestens:

1. Einlesen von Ganzzahlen mit n Stellen (nur positiv oder auch negativ)

2. Einlesen von Fließkommazahlen mit n Stellen bzw. im Rechnungswesen mit exakt 2 Nachkommastellen, bei Zinsberechnungen 3-4 Nachkommastellen

3. Einlesen von Textzeichen

4. Einlesen von Datumsangaben

5. Verwaltung von Sondertasten (ESCAPE, ENTER, DELETE, F1..F10 usf.)

Das hört sich alles ganz schrecklich an, ist aber weniger schlimm als man meinen mag.

Das Grundprinzip ist das folgende:

a) Es wird positiv festgelegt, welche Art von Tasten erlaubt sind. Also die Menge der erlaubten Zeichen wird beschrieben, nicht die der unerlaubten. Für eine Ganzzahl (wie z. B. Konto-Nr) sind nur die Zeichen 0..9 erlaubt, sonst nichts außer den Sondertasten ENTER für Eingabe abschließen bzw. vielleicht ESCAPE für Abbruch.

b) Diese Eingaben (eine Kette von char, also Zeichen) werden zu einem Zeichenstring zusammengefaßt.

c) Dieser String wird den Aufgaben entsprechend formatiert, in andere Datentypen umgewandelt oder sonstwie weiterbearbeitet.

Der Vorteil dieser etwas umständlichen Vorgehensweise ist, daß der Anwender an der Konsole keinen Mist eingeben oder das PRogramm zum Absturz bringen kann.

Um diese Zeichen zu handeln, benötigt man die ASCII Tabelle.

Bei Sonderzeichen ist es so, daß getch() zunächst den Wert 0 liefert ('\0'), und danach den ASCII-Wert des Sonderzeichens, als da wären ESCPAPE==27, ENTER == 13 etc. etc.

Man kann so die gesamte Tastatur so auslesen, wie der Anwender darauf herumspielt, und hat die Konsoleneingabe damit sicher in der Hand.

Um die Finanzbuchhaltung (EÜR) mal in ihre wesentlichen Bestandteile zu zerlegen:

1. Der Algorithmus

Der hat mit der EDV eigentlich nichts zu tun, es geht darum, wie was gebucht wird, wie man die Buchungen anschließend erfolgswirksam auswertet. Den würden wir auch brauchen, wenn wir mit Tinte und Papier "Buch" führen würden. Ich habe dazu in einem Forum in einem ganz anderen Zusammenhang den sehr zutreffenden Spruch gelesen:

Vermeide doppelte Erfassung.

Nimm jeden Vorgang nur einmal auf und greife besser mit verschiedenen Auswertungsfunktionen auf denselben Datenbestand zu.

Dem ist nichts hinzuzufügen, das kann man so wie es steht unterschreiben.

2. Die Anwenderschnittstelle

Wie schon beschrieben, verlangt dies einigen Programmieraufwand. Bei Datumsangaben z. B. (Spaß wink.gif ) kommt der alte Papst Gregor ins Spiel, der die Säkularjahre 1700, 1800, 1900 als Schaltjahre verboten hat, obwohl sie durch 4 ohne Rest teilbar sind. Demnach war das Jahr 2000 das erste säkulare Schaltjahr nach 400 Jahren. Schon gewußt? wink.gif

3. Die Datenbank

Man muß die Daten ja speichern und in Dateien verwalten. So weit so gut. Nur muß man dem Anwender ja auch erlauben, gespeicherte Daten zu editieren, zu löschen usf. Soweit so ungut, bedeutet wieder Aufwand.

4. Exportschnittstellen

Wie schon beschrieben, überhaupt kein Problem.

Im weiteren möchte ich erstmal, bevor ich beschreibe, wie man sichere Eingaben vom Anwender realisiert, auf die Dateienverwaltung eingehen. Das ist das A und O, ohne ordentliche Dokumentation wird kein Betriebsprüfer sowas akzeptieren. Der eigene Steuerberater wird ohnehin nicht glücklich sein, daß der die 2500 Euro im Jahr drangeben muß für seine eigene Datenerfassung und sich mit fremden Datenformaten beschäftigen muß.

Aber 2500 Euro im Jahr sind in zehn Jahren 25.000 Euro.

Reicht fast für´n ziemlich gebrauchten Porsche. wink.gif

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 16:22 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 16:53 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Wenn wir uns mal betrachten, wie unsere Daten sinnvollerweise strukturiert sind:


typedef struct {
int lfd_nr;
int konto_nr;
int loeschen;
double netto;
int gkonto_nr;
double gk_betrag;
double ust_proz;
double brutto;
double ust_betrag;
int ust_konto;
datstring datum;
char text[KON_VIERTEL];
int index;
int index_dat;
int lief_nr; // Der Lieferant
int steuerschluessel;
} strc_bsatz;
strc_bsatz bsatz;

Wir haben hier eine STruktur, die aus verschiedenen Datentypen zusammengesetzt ist.

Wenn wir das in einen Zeichenstring überführen wollen, wird es sehr umständlich.

Und sehr fehleranfällig!

Weil nämlich jede kleinste Änderung bei der Programmentwicklung dazu führt, daß der Dateizeiger das Flattern kriegt und Datenmüll produziert.

Man kann solche Datenstrukturen eigentlich im Textformat NICHT sinnvoll verwalten.

Die Horror-ROutine, um diese Struktur in einen Text-Datensatz zu übersetzen, sieht entsprechend schrecklich aus:


sprintf(buffer,"%6i;%4i;%10.2f;%4i;%10.2f;%5.1f;%10.2f;%10.2f;%4i;%10s;%6i;%6i;%4i;%1i;",
bsatz.lfd_nr,
bsatz. konto_nr,
bsatz. netto,
bsatz. gkonto_nr,
bsatz. gk_betrag,
bsatz. ust_proz,
bsatz. brutto,
bsatz. ust_betrag,
bsatz. ust_konto,
bsatz.datum,
bsatz. index,
bsatz. index_dat,
bsatz.lief_nr,
bsatz.steuerschluessel);
strncat(buffer,bsatz.text,KON_VIERTEL);
strncat(buffer," ",1);
buffer[strlen(buffer)-1]=ENDOFLINE;
buffer[strlen(buffer)]=ENDOFSTRING;


Wird im Format nur eine Ziffer geändert, oder spricht eine andere Funktion den Datensatz an, ohne daß das Format angepaßt wurde, gibt es Datenmüll.

Dazu kommt die Besonderheit von C, daß bei sprintf() und printf() keine Stellvertreter zugelassen sind, sondern die Zahlen so wie sie sind eingegeben werden müssen.

Wenn wir also ein 10stelliges Format mit zwei Nachkomma haben wollen, müssen wir sagen:

sprintf("%10.2f

Wir können die 10 nicht durch eine Variable ersetzen. Ändern wir das, müssen wir händisch jede 10 im Programm daraufhin überprüfen, ob sie was mit der Änderung zu tun hat.

DER REINSTE HORROR!

Das Binär-Formal hat natürlich auch so seine Tücken, ,die ich hier aber erstmal nicht erwähnen möchte, weil sie vom Thema wegführen.

Gegenüber dem text-Format hat das Binär-Format eigentlich zu 99,9% nur sehr dicke Vorteile.

Das wird im Laufe des Beitrags vielleicht noch deutlich werden.


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 17:36 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Die Dateibehandlung in C ist sehr schön, wie die ganze Sprache sehr schön ist, nämlich kurz und knapp und ohne Schnickschnack und slim&fast (kurzer Code und hohe Rechengeschwindigkeit).

Man sieht, um einen zusammengesetzten Datentypen als Text zu speichern, welcher Aufwand dahintersteht.

Im Binär-Format ist das nicht der Fall. Wir können unesere Struktur so wie sie ist, Zeichen für Zeichen, speichern und wieder auslesen, müssen nichts umwandeln und zurückumwandeln und haben daher auch nicht das PRoblem, nach seltsamen Fehlern im Zuge der Umwandlung suchen zu müssen.

Die Verwaltung von Binärdateien ist wie folgt:

Datei öffnen mit fopen()

Daten schreiben oder lesen mit fwrite() oder fread()

Datei schließen mit fclose()

Auf dem File liegen mehrere Dateizeiger.

Einer steht am Anfang, einer auf der aktuellen Position, einer am Ende. Die beiden anderen sind möglicherweise nur simuliert, PSEUDO, weil sie die Anzahl der Datensätze mit den Bytes hochrechnen, was aber im ENdeffekt egal ist. Man spricht sie an, als wenn es so wäre:

SEEK_SET = Anfang der Datei
SEEK_CUR= wo der aktuelle Dateizeiger steht
SEEK_END=Dateiende.

Wenn wir im Binärformat speichern, ist es völlig egal, was wir speichern. Ob wir eine Textzeile speichern oder ein Zeichen oder einen strukturierten Datensatz, die Funktionen benötigen nur einen Wert, nämlich die Größe des zu speichernden Objekts. Dieses wird dann Zeichen für Zeichen ein- oder ausgelesen. Wenn die Größenangabe nicht stimmt, gibt es Datenmüll.

Das wäre, um auf eine Tücke der Binärdateien zu sprechen zu kommen, natürlich dann der Fall, wenn sich der Datentyp nach dem Speichern der Datei geändert hat, wenn wir also mit neuen Datentypen alte Dateien auslesen wollen, gibt es Müll. Dazu reicht es, wenn die Länge eines Textfeldes im Datensatz geändert oder ein neues Feld hinzugefügt wurde. Will man das, und die alten Datenbestände weiterverwenden, muß man den alten Datentyp umbenennen und eine Routine schreiben, die die alten Daten in das neue Format überführt.

Die fread() und fwrite() Funktionen sind Funktionen CALL BY REFERENCE

In C ist eigentlich der übliche Zugriff CALL BY VALUE.

CALL BY VALUE erhält eine eine Kopie der Daten und liefert die Änderung der Kopie zurück, das Original bleibt unverändert.

CALL BY REFERENCE hingegen verändert das Original.

Man kann sich das so vorstellen, daß bei CALL BY VALUE die Originalurkunde im Tresor liegt und man eine Fotokopie zur Bearbeitung herausrückt und die Jungs darin herumschmieren, in der Kopie.

CALL BY REFERENCE hingegen ist so, daß die Jungs den Tresor öffnen und im Original herumschmieren.

Danach ist es je nachdem ruiniert.

Die Reference-Aufrufe erfordern also eine gewisse Aufmerksamkeit.

Nicht nur, daß die Original-Daten zerstört werden können, hier wie fast immer kann natürlich ein Buffer-Overflow stattfinden, eine fehlerhafte Funktion überschreibt Bereiche, die dafür nicht reserviert wurden.

Bei solchen Aufrufen CALL BY REFERENCE sollte man in C ganz hellwach sein.

Soviel zur Abschreckung wink.gif

Wenn es aber so einfach wäre, würde es ja keinen Spaß machen.

In Wahrheit sind die Sachen auch halb so wild ... man muß eben nur wissen, was man macht.


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 18:09 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Konkret ist der Umgang mit binär-Dateien so:

int speichere_bsatz_bin()
{
FILE *bdp;

bdp=fopen(dn_buchungen_bin,"ab");
if (bdp==NULL) return NOTOK;

fwrite(&bsatz,sizeof(strc_bsatz),1,bdp);

fclose(bdp);


return OK;
}

Hier soll also ein Buchungssatz gespeichert werden.

Dazu wird erstmal ein Dateizeiger definiert:

FILE *bdp; //bdp =BinärDateiPointer

den könnten wir natürlich auch

FILE *werner;

nennen, wäre dasselbe, aber nicht sinnstiftend.

Danach wird gesucht, ob die datei mit dem Namen dn_buchungen_bin vorhanden ist. dn_buchungen_bin ist eine Konstante, die weiter oben im Programm festgelegt wurde:
char const dn_buchungen_bin[STRLEN_MAX]="primanota2012.bin";

Sie heißt also "primanota2012.bin", und das könnten wir auch so schreiben, nur wenn wir den Dateinamen ändern, gibt es Datenmüll. Daher Definition über Konstante.


bdp=fopen(dn_buchungen_bin,"ab");

Die Option ab bedeutet, wir suchen eine Datei mit dem Namen und wollen "a"=append, also einen Datensatz anhängen, und zwar im Binärmodus, daher "ab"

Die Datei wird dabei nicht zerstört, und wenn sie nicht vorhanden ist, neu angelegt(was bei "rb" nicht der Fall wäre).

Eine Fehlermeldung hier im "a" Modus könnte z. B. darauf zurückzuführen sein, daß das Zielverzeichnes ein Wechseldatenträger ist, der zwischenzeitlich entfernt wurde. Dann kann die Datei weder gelesen noch neu angelegt werden.

if (bdp==NULL) return NOTOK;

Eine Fehlerbehandlung erfolgt hier nicht, die Routine bricht ab und gibt NOTOK zurück, was das aufrufende Programm damit macht, ist seine Sache und hier nicht erkennbar.

Wenn aber alles soweit in Ordnung ist, geschieht folgendes:

fwrite(&bsatz,sizeof(strc_bsatz),1,bdp);

Wir sehen hier den Operator &

Der bedeutet, daß nicht VALUE übergeben wurde, sondern eine Adresse, nämlich der SPeicherbereich von bsatz, von der ganzen Struktur.

Diese wird nun zeichenweise kopiert in die Datei, es erfolgt auf den Bereich nur ein Lesezugriff, logisch, der Schreibzugriff ist ja auf der Festplatte.

Es werden soviele Zeichen gelesen, wie

sizeof(strc_bsatz) angibt,

das können vielleicht 70 oder 90 oder 102 Zeichen sein, der Datensatz hat ja einiges Format.

Die Daten werden also in den stream geschrieben, das ist ein Speicherbereich, und von da auf die Festplatte des PC.

Wirklich sicher sein können wir damit nur, wenn wir

fflush(bdp) aufrufen würden, was das Schreiben aller Zeichen aus dem stream auf die Festplatte erzwingt.

Das brauchen wir aber gar nicht, weil die Funktion


fclose(bdp);

das ohnehin erledigt. Vorsicht wäre hier angesagt, wenn man mit hunderten von Datensätzen im Rechner arbeitet. Dann macht fflush() Sinn, denn stürzt der Rechner ab, sind die Daten verloren. Sowas sollte man ohnehin nicht machen.

Damit sind die Daten des Buchungssatzes in der Datei gespeichert, und zwar binär.

Der nächste Schritt wäre dann, diese Zeichen wieder auszulesen.

Und damit haben wir den nächsten Vorteil des binären Datenformats.

Wir müssen nämlich nicht, wie bei Textdateien, die Dateien vom ersten Datensatz an durchblättern, sondern können mit fseek() direkt irgendwo hinspringen.

Z. B. an den Dateianfang, an das Ende oder an einen Datensatz Nr. xy dazwischen.

Das eine (Textdatei) nennt man sequentiell, das andere random access, wahlfreier Zugriff.

Sequentiell ist IMMMER Mist, random access ist IMMER vorzuziehen, weil der Umgang mit der Datei nicht nur schneller, sondern auch einfacher und übersichtlicher wird.


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 21:12 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Es wird in 1000 Jahren nicht anders sein als heute.

Die Verwaltung eines Datenbestandes besteht aus 3 Hauptfunktionen:

1.) Neues Element einfügen

2.) Vorhandenes Element suchen

3.) Vorhandenes Element bearbeiten/löschen

Bei der Neuanlage von Elementen in C gilt die GOLDENE REGEL:

Der Datensatz muß komplett ausgenullt werden. Das heißt, alle Felder eines Datensatzes müssen VOR DER BEARBEITUNG einen definierten Wert haben.

TUT MAN DAS NICHT SIND KATASTROPHALE (gut so) ODER RÄTSELHAFTE (schlimm) FEHLER IM PROGRAMM KEINE FRAGE DER ZEIT SONDERN DAS PROGRAMM IST EINE ZEITBOMBE. wink.gif

Hat man es mit einfachen Datentypen zu tun, ist es einfach eine Zuweisung mit dem Zuweisungsoperator =

Wir sagen, zahl=0

oder zahl[i]=0 bei einem Array.

Hat man es mit zusammengesetzten Datentypen unterschiedlichen Typs zu tun, muß man eine Funktion schreiben, um alle Member einer Struktur zu initialisieren. Und wenn man das PRogramm ändert, muß man daran denken, daß diese Initialisierung auf den neuesten Stand gebracht wird.

Für Float und andere einfache Datentypen ist der Zuweisungsoperator erlaubt.

Für Zeichenketten ist er bei der Initialisierung erlaubt:

char text[50]="irgendwas";

Im laufenden Programm aber nicht. SOndern etwa:

sprintf(text,"%s","");

wäre zulässig, text="" ist nicht zulässig.

Für Formatstrings wie Datum empfiehlt es sich, einen formatierten Nullstring zu übergeben, also etwa

sprintf(datum,"%10s","01.01.2012"),

weil wir nicht wissen (wollen), ob die Editierung auch die Punkte erfaßt. Das muß sie ja eigentlich nicht.

Nachdem so jedes Element des Datensatzes einen DEFINIERTEN WERT erhalten hat, kann der Anwender seine Eingaben machen

(denke an Papst Gregor und die Schaltjahre wg. 29. Februar wink.gif )

Und der Datensatz kann im "a" = APPEND Modus, d.h. anhängen an vorhandene Datei, gespeichert werden.

Wenn es dabei bliebe, wäre es eigentlich einfach.

Die Datei, in die diese Buchungen hineingeschrieben werden, wurde früher Primanota genannt und man durfte da nichts löschen oder ändern, sondern nur stornieren, damit das Storno bzw. der Versuch der Änderung auch nachträglich noch erkennbar war.

In dieselbe Richtung zielt das Verbot (der ordentlichen Buchführung), mit Bleistift zu arbeiten.

Die Kaufleute früherer Zeiten dachten natürlich daran, daß ihre Mitarbeiter "kreativ" buchen, und das Finanzamt denkt heute noch so. wink.gif

Wenn wir selbst programmieren, läßt uns das kalt, und 5 Storno-Buchungen, von denen 3 falsch herum waren und wiederum re-storniert wurden, sehen auch nicht schöner aus als wenn man den Datensatz gleich aus dem Datenbestand entfernt.

Schließlich ist Storno wg. falscher EIngabe kein Geschäftsvorfall.

Um einen vorhandenen Datensatz zu ändern oder zu löschen, muß man ihn erstmal finden.

Dazu muß man in der Datei primanota wühlen, blättern oder suchen.

Sofern das wenige Datensätze sind, kein Problem, darin zu blättern. Sind es viele Datensätze, muß man Suchfunktionen schreiben, etwa nach Text oder Datum oder Konto-Nr. oder Lieferant suchen.

Um zum Bsp. auch festzustellen, im Dezember, was im Jan. des lfd. Jahres an einen bestimmten Lieferanten gezahlt wurde.

Wir haben also bei der Neueingabe eine sehr einfache PRogrammierung.

Muß der Datensatz editiert werden, müssen wir ihn in der Datei auffinden und zur Editierung in den Rechner schaufeln.

Und danach wieder abspeichern.

Das geht in C nicht im Textmodus, sondern nur im Binär-Modus.

Für den Dateizeiger SEEK_CUR, also die aktuelle Position, gilt folgendes:

Haben wir das Element der Datei gefunden und mit fread() ausgelesen, also in den Rechenspeicher geschaffft, steht der Dateizeiger nicht am Anfang des Elements, sondern 1 Bit hinter dem Ende des Elements, sprich entweder am Ende der Datei oder am Anfang des nächsten Datensatzes.

Würden wir nun das Element mit fwrite() in die Datei zurückschreiben wollen, hätten wir eine Fehlfunktion. Denn entweder würde der Nachfolger überschrieben, oder, wenn der Dateizeiger auf EOF(End of FILE) steht, würde gar nichts geschehen.

Wäre er im Modus "r+b" geöffnet, also Lesen und Schreiben binär, kann er nicht anhängen.

Könnte er aber anhängen, hätten wir den Datensatz verdoppelt = ebenfalls Fehler.

Um den ausgelesenen und neu bearbeiteten Datensatz wieder in die Datei zurückzuschreiben, müssen wir VORHER den Dateizeiger um 1 Element zurücksetzen.

Hier ist eine funktionsfähige Anweisung, um einen editierten Datensatz nach dem Editieren in die Datei zurückzuspeichern:

1 case ENTER: // ENTER heißt, jetzt mach mal fertig
2 if (bsatz_eingabe()==OK) // logisch und formal richtige Eingabe
3 {
4 bsatz_anzeigen(); // zeige das Ergebnis der Änderung nochmal an
5 fseek(bdp,(long) -1*sizeof(strc_bsatz),SEEK_CUR); // 1 zurück
6 fwrite(&bsatz,sizeof(strc_bsatz),1,bdp);
7 meldung("Datensatz wurde gespeichert");
8 fclose(bdp);
9 return;

Zeile 5 zeigt, wie der Dateizeiger zurückgesetzt wird.

Im Binärmodus ist (long) -1 das Zurücksetzen um ein Byte. Ist der Datensatz größer, muß das Byte multipliziert werden mit der Größe des Datensatzes, also -1*sizeof(datensatz), damit der Dateizeiger byteweise soweit zurückläuft, daß der Datensatz genügend Platz hat.

Die Funktion fwrite(... überschreibt dann,

WENN die Datei im Modus fopen(dateiname,"r+b", also r+ = Lesen UND SCHREIBEN geöffnet wurde, sonst nicht. Wenn falsch geöffnet mit "rb", gibt es keine Fehlermeldung, sondern der Vorgang findet gar nicht statt.

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 21:20 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 21:38 Uhr
MiBü
MiBü
Klugscheisser
*******
Gruppe: Mitglied
Mitglied seit: 18.05.2005
Beiträge: 2.402

Servus,

habs mir nicht alles durchgelesen, aber dachte das dich vielleicht auch ein "opensource" Projekt interessieren würde: compiere -> www.sourceforge.net

Viel Spass noch


--------------------
Gruß

Michael
TOP    
Beitrag 20.01.2012, 21:44 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Kommen wir zum Löschen eines Datensatzes.

Dafür gibt es keine abrufbaren Funktionen,

Der Grund ist: die Datei ist, ob wahlfrei oder nicht, auf dem Datenträger (Festplatte oder sonstwas) sequentiell gespeichert, also eins hinter dem anderen.

Man kann da kein Element herauslöschen, ohne die ganze Datei zu zerstören.

Im Prinzip gibt es zwei Möglichkeiten:

Wir kopieren die gesamte Datei in den Rechenspeicher, schreiben dann nur die Datensätze zurück, die nicht gelöscht werden sollen.

War früher in DOS eine Horrorvorstellung, der Platz im Rechenspeicher reichte niemals für irgendwas und da mußte man sich verbiegen mit dynamischer Speicherverwaltung.

Wäre heute nicht mehr nötig, ist aber trotzdem nicht elegant.

Elegant ist es, eine Kopie der Datei anzulegen auf dem SPeichermedium (Festplatte oder sonstwas), ganz gewiß aber nicht im Rechenspeicher.

Nehmen wir an, die Datei hätte 1002 Datensätze, von denen 2 gelöscht werden sollen (zur Löschung vorgemerkt).

Dann würden wir eine Kopie anlegen mit 1000 Datensätzen, welche die fraglichen 2 nicht mehr enthält.

Im zweiten Schritt nun kopieren wir diese Datei zurück, indem wir die Originaldatei überschreiben.

Ergebnis dann, es sind 1000 Datensätze drin, die beiden zur Löschung vorgemerkten sind nicht mehr vorhanden.

Fertig.

REAL sieht es dann vielleicht so aus (funktionsfähiger Code):


int kopieren_loeschen()
{
// Kopiert werden alle Datensätze außer den zur Loeschung vorgesehenen.
// Danach wird ins Originalfile zurückkopiert


FILE *FP_original;
FILE *FP_kopie;

strc_bsatz buffer;

char dn_kopie[KON_VIERTEL]="kopie.bin";

FP_kopie=fopen(dn_kopie,"wb");
if (FP_kopie==NULL)return NOTOK;

FP_original=fopen(dn_buchungen_bin,"rb");
if (FP_original==NULL)return NOTOK;

while ( fread(&buffer,sizeof(strc_bsatz),1,FP_original)==1)
if (buffer.loeschen!=JA) fwrite(&buffer,sizeof(strc_bsatz),1,FP_kopie); // es gibt ein Feld int, welches entweder sagt Löschen oder nicht
//Mit dieser einen Zeile wir die ganze Datei kopiert
fclose(FP_original); // und geschlossen
fclose(FP_kopie);
FP_original=fopen(dn_buchungen_bin,"wb"); // zum Übersdchreiben neu öffnen, d.i. löschen
FP_kopie=fopen(dn_kopie,"rb");
if(FP_original==NULL || FP_kopie==NULL) return NOTOK;

while ( fread(&buffer,sizeof(strc_bsatz),1,FP_kopie)==1)
fwrite(&buffer,sizeof(strc_bsatz),1,FP_original); // ins Original per Überschreiben zurückkopieren
fclose(FP_original);
fclose(FP_kopie);

return OK;

} // fu

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 21:49 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 20.01.2012, 22:02 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

QUOTE (MiBü @ 20.01.2012, 21:38 Uhr) *
Servus,

habs mir nicht alles durchgelesen, aber dachte das dich vielleicht auch ein "opensource" Projekt interessieren würde: compiere -> www.sourceforge.net

Viel Spass noch



Danke für den Hinweis. Ich bin aber ja eher ein Einzelgänger und habe ungefähr ein halbes Dutzend verfügbarer SOftware vorher getestet, alles billig und alles Windows bevor ich mich entschlossen habe,

SOLCHE EINFACHEN DINGE BESSER SELBST ZU PROGRAMMIEREN,

Bin mit meinem Programm sehr gut zufrieden, es macht alles was ich brauche und wie ich es am liebsten hätte (Maßanzug).



Gruß Sharky

Der Beitrag wurde von sharky bearbeitet: 20.01.2012, 22:03 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 08:04 Uhr
DerDenDuNichtKennst
DerDenDuNichtKen...
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 16.12.2004
Beiträge: 1.084

Hallo Sharky,

habe mir jetzt auch nicht alles durchgesesen aber erst ein mal wieder hallo zurück im Forum smile.gif
Nur eine Frage zum Projekt wie sieht aus mit dem Steuerrechtichen und der Gesetzgebung?
Ich denke ja das die Software bestimmte rechtliche Grundlagen erfüllen und zudem auch abgenommen werden muss .
Also ich würd mich da echt mal Informieren wies da rechtlich ausschaut denn es geht ja ums Geld von Vater Staat.
Und der ist da ja bei uns kleinen bekanntlich streng weil er bei den großen blind sein darf (geldscheinwink)

Schöne Grüße

ABER trotzdem viel Spaß beim Proggn


--------------------
Der Vorteil der Klugheit besteht darin, daß man sich dumm stellen kann.
Das Gegenteil ist schon schwieriger.
Kurt Tucholsky


GRUß

Christian Maier
TOP    
Beitrag 21.01.2012, 15:26 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

QUOTE (DerDenDuNichtKennst @ 21.01.2012, 08:04 Uhr) *
Hallo Sharky,

habe mir jetzt auch nicht alles durchgesesen aber erst ein mal wieder hallo zurück im Forum smile.gif
Nur eine Frage zum Projekt wie sieht aus mit dem Steuerrechtichen und der Gesetzgebung?
Ich denke ja das die Software bestimmte rechtliche Grundlagen erfüllen und zudem auch abgenommen werden muss .
Also ich würd mich da echt mal Informieren wies da rechtlich ausschaut denn es geht ja ums Geld von Vater Staat.
Und der ist da ja bei uns kleinen bekanntlich streng weil er bei den großen blind sein darf (geldscheinwink)

Schöne Grüße

ABER trotzdem viel Spaß beim Proggn



Ja danke für den Einwand.

Nun, ich bin nicht erst seit gestern selbstständig und kenne mich mit den steuerrechtlichen Grundlagen ziemlich gut aus.

Man muß es trennen:

Die Erfassung von Geschäftsvorfällen ist steuerrechtlich so geregelt (siehe unten), daß sie lückenlos sein muß und in Schriftform zu erfolgen hat. Wie man das macht, ist steuerrechtlich nicht geregelt. Im Prinzip kannst du alles auf eine Rolle Klopapier schreiben = Primanota.

Der Moment, wo das Steuerrecht greift, ist die Steuererklärung.

Was da steht, ist verbindlich. Muß ja auch unterschrieben werden!

Derzeit denke ich, daß ich die Steuererklärung weiter durch den Steuerberater machen lasse.

Der Grund ist, z. B. der Umgang mit Abschreibungen und was zulässig ist oder vom Finanzamt voraussichtlich akzeptiert oder nicht akzeptiert wird, das weiß ich weniger gut als der Fachmann.

Anders gesagt: der weiß, was gehen könnte, und was man besser nicht versucht, der kennt sich einfach besser aus. Mit einer Sonderabschreibung (auf die ich im Leben nicht gekommen wäre) hat mir mein STB vor einigen Jahren einmal sehr viel Geld gespart.

Um die Frage zu beantworten:

Nein, eine Finanzbuchhaltung muß nicht lizensiert werden. Es ist dem Steuerpflichtigen freigestellt, in welcher Form er seine Geschäftsvorfälle dokumentiert (siehe Klopapier). Die Dokumentation muß lückenlos sein, sie muß in Schriftform erfolgen (Dateien zählen nicht, erst der Ausdruck der Dateien ist Schriftform), und sie muß den Grundsätzen der ordentlichen Buchführung genügen, die rechtlich nicht exakt fixiert ist, aber deren oberster Grundsatz lautet:

Alle Geschäftsvorfälle sind so zu dokumentieren, daß ein sachkundiger Dritter diese lückenlos nachvollziehen kann.


Der Sinn dieses Programms liegt in folgendem:

1. Ich will eine Plattform, wo ich weitgehend automatisiert und maßgeschneidert meine Geschäftsvorfälle erfassen kann, damit ich diese

2. mit minimalem Zeitaufwand korrekt erledige.

Wie gesagt, ich hab mir ein halbes Dutzend verfügbarer Windows-Progs als Probeversion geladen und war mit denen nicht zufrieden, weil:

Zu umständlich, zu unhandlich, zu zeitaufwendig, Bedienerführung unlogisch oder hakelig oder unklar.

Der Vorteil natürlich, wenn man selbst die Buchführung durchführt, ist nicht zu übersehen:

Du bist zu jeder Zeit des Jahres auf KNOPFDRUCK über den Zustand deiner Finanzen informiert und kannst rechtzeitig erkennen, wo was schief läuft oder was zu bessern ist.

Oder wenn der Erfolg größer ist als erwartet, kannst du rechtzeitig steuerliche Gegenmaßnahmen einleiten.

Diese Momente sind für einen kleinen Selbstständigen nicht zu unterschätzen.

Die Alternative sieht nämlich so aus, wenn man sich um nichts kümmert und alles an den Steuerberater delegiert, daß man am Anfang des Folgejahres von der Entwicklung völlig überrascht ist.

Oder nochmal anders:

Wenn man sich um die Finanzbuchhaltung selbst kümmert, ist man drin in den Dingen und hat den Betrieb besser in der Hand.

Gruß Sharky

Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 15:34 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 15:56 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Wie gesagt, in 1000 Jahren ist eine Datenbank nichts anderes als heute:

Daten neuj erfassen und hinzufügen

Daten sichten

Daten editieren oder löschen.

Um die erfaßten Geschäftsvorfälle zu sichten, muß man die Datei öffnen, in der sie gespeichert sind, und auf dem Bildschirm ausgeben.

In Bild 1 sieht man 2 Geschäftsvorfälle.

Der erste Datensatz betrifft allgemeine Betriebsausgaben (Konto 4900) an Bank.

Dabei ist die Vorsteuer-Option 19% sofort abziehbar, so daß auch das zugehörige Vorsteuer-Konto berührt ist (Konto 1576)

Man sieht, es bleibt bei diesem einen Satz. Man könnte händisch einen zweiten hinzufügen, nämlich Vorsteuer 1576 gegen Aufwand 4900, und wir hätten einen Buchungssatz mehr.

Getreu dem Motto:

VERMEIDE DOPPELERFASSUNGEN, greife lieber mit mehreren Auswertungen auf denselben Datenbestand zu,

unterbleibt das hier.

Würden wir das zum zweiten Male buchen, könnten Tippfehler oder Buchung verkehrt herum oder auf falsches Umsatsteuerkonto erfolgen, sowas wollen wir nicht und daher ist das AUTOMATISIERT.

Der zweite Buchungssatz betrifft eine umsatzsteuerfreie Einnahme BANK 1200 gegen ERLÖSE 8210

Beim SKR 03 sind die Konten der Kontenklasse 8000 die Erlöskonten. Erlöskonten sind Passiv-Konten, Erlöse stehen im Haben. Dementsprechend steht der Zufluß der Erlöse im Gegenkonto 1200 BANK im SOLL.

Bei meiner PLUSMINUS Buchführung ist es aber anders. Bank steht im + (Kontostand steigt ja), Erlöse im -.

Man muß sich aber keinen Kopf machen.

Egal wie man bucht, man muß es nur konsequent durchziehen. Rechnerisch stimmt das PRogramm.

Nun wollen wir der Bank (die noch etwas Geld von uns zu bekommen hat und daher wissen will, wie die Dinge stehen) eine Auswertung zukommen lassen.

Nach meiner +- Buchung wären die Vorgänge vertauscht, nämlich Bank würde im + stehen (Haben) und Erlöse im - (Soll)

Das könnte den Sachbearbeiter irritieren. wink.gif

Daher lassen wir intern die Dinge wie sie sind, drehen sie nur für die Außendarstellung um.

Um das zu zeigen, lasse ich das Vorzeichen stehen (-). Man kann das natürlich auch unterdrücken.

Die Auswertung (Abbildung 2) zeigt uns die Bebuchten Konten (nicht bebuchte werden unterdrückt). Wenn die gesamte Kontenklasse nicht bebucht ist, erscheint aber zumindest der Titel der Kontenklasse.

Wir sehen die Betriebseinnahmen im Haben des Erlöskontos (was richtig ist, Erlöskonto = Passivkonto, Gegenkonto Bank wäre dann im SOLL).

Was den Sachbearbeiter der Bank höchstens irritieren könnte, wäre das Minuszeichen. Werde das rechtzeitig rausnehmen oder mit TIPP-EX ÜBERSTREICHEN wink.gif

Wir sehen, nach der Umkehrung, ebenfalls korrekt den Aufwand im SOLL.

Ebenso die aufzuteilende Umsatzsteuer im SOLL, gehört zum Aufwand.

Dieses Konto aufzuteilende Umsatzsteuer kann man im laufenden Geschäftsjahr nur als AUfwand laufen lassen, es wird aber beim Jahresabschluß aufgelöst auf nicht abziehbare Vorsteuer und abziehbare Vorsteuer, vor dem Jahresabschluß allerdings muß es so laufen wie dargestellt.

Mach ich das Minuszeichen noch weg, ist meine Auswertung genau identisch mit dem, was eine DATEV-BWA anzeigen würde, obwohl das Programm intern ganz anders rechnet, nämlich + gegen -.

Dementsprechend ist intern:

SALDO = SOLL + HABEN [ SIC! ]

was rechnerisch korrekt ist und die Kontenvertauschung Aufwands- und Ertragskonten und Aktiv- und Passivkonten überflüssig macht. Sie sind überflüssig! Man muß ja immer mal bedenken, die SOLL/HABEN Buchung stammt aus dem mittelalterlichen Venedig und wurde zu ganz anderen Zwecken entwickelt als denen, dem Finanzamt als Kleinbetrieb Mitteilung zu machen.

Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 16:03 Uhr
Angehängte Datei(en)
Angehängte Datei  anzeige.jpg ( 116.21KB ) Anzahl der Downloads: 8
Angehängte Datei  ausw.jpg ( 190.75KB ) Anzahl der Downloads: 13
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 16:37 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Wir fügen 2 Buchungen hinzu:

Miete 1850 Euro

in welcher 250 Euro NK enthalten sind.

Die buchen wir dann nicht automatisch, weil das ja noch recht übersichtlich ist und sich die NK kürzlich auch geändert haben, sondern als weiteren Buchungssatz.

Dazu kommt dann eine NK-Nachzahlung (wie sie mich jedes Jahr im Jan. erwischt) über Euro 1345.11

Die Buchungssätze sehen wir im Anhang Anzeige2

Und finden sie in der Auswertung Anhang ausw2 wieder.

Das Ergebnis ist allerdings nicht korrekt, es handelt sich um eine Fehlbuchung.

Wo liegt der Fehler?

Natürlich nicht im Programm (ist ja von mir geschrieben) wink.gif

Sondern es wurde falsch gebucht (logisch falsche Buchung).

Da die Nebenkosten 250 Euro in der Mietzahlung gegen Bank enthalten sind, darf man die natürlich nicht wieder gegen Bank buchen, weil man damit eine erfolgswirksame Buchung erzeugt, anstelle, was richtig wäre, eine erfolgsneutrale.

Wir dürfen daher die enthaltenen NK nicht gegen Bank buchen, sondern müssen sie gegen Miete buchen. Damit verringert sich die Miete im Saldo (was korrekt ist), und die NK erhöhen sich,

ABER das ERgebnis bliebe gleich (was ebenfalls korrekt wäre);

Wäre, aber nicht ist. Durch die Fehlbuchung haben wir Kosten ausgewiesen, die um den Betrag 250 Euro zu hoch sind. Der Betriebsprüfer würde dann nach den 250 Euro suchen und feststellen, daß diese auf den Kontoauszügen gar nicht ausgewiesen sind.

KÖnnen sie ja auch nicht.

Womit wir zu der Frage kommen, wie man solche Fehlbuchungen korrigiert.

Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 16:47 Uhr
Angehängte Datei(en)
Angehängte Datei  anzeige2.png ( 107.87KB ) Anzahl der Downloads: 3
Angehängte Datei  ausw2.jpg ( 211.49KB ) Anzahl der Downloads: 7
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 17:25 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Tja, etwas verschwinden lassen.

Das wünschen sich manchmal viele.

Alles hinterläßt Spuren.

Auch unsere Fehlbuchung wäre nun so eine Spur.

Ich hab den Verdacht, daß Buchhaltungsprogramme, welche die Löschung eines Datensatzes nicht zulassen, von faulen Programmierern geschrieben wurden, unter dem Vorwand, dies sei rechtlich nicht zulässig (LACH MICH TOT), denn die Löschung eines Datensatzes ist programmiertechnisch eigentlich gar nicht möglich.

Was mich zu der kleinen Programmierer-Abschweifung ermuntert:

Wenn wir eine dynamische Liste haben, nämlich

vorheriges < ELEMENT > nächstes

und diese verknüpfen, dann haben wir die Möglichkeit.

Denn:

vorheriges < ELEMENT 1 > nächstes
vorheriges < ELEMENT 2 > nächstes
vorheriges < ELEMENT 3> nächstes

wir könnten dann sagen: vorheriges von 3 ist 1 und nachfolgendes von 1 ist 3, Ergebnis: 2 ist unsichtbar und damit vernichtet.

Wenn wir die ganze Datei in den Speicher schaufeln als dynamische Liste und die Elemente löschen und den Rest zurückschreiben in eine neue Datei, wäre das so eine Möglichkeit. Ein DOS Programmierer von 1980, dem würden allerdings die Haare zu Berge stehen aufgrund der zu bewältigenden Datenmengen (bei, wollen wir nicht vergessen, damals nicht 4GB Speicher sondern 600 KB, wovon das Programm noch 450 belegt wink.gif ). Die heutigen Speicher würden das schaffen, es ist aber trotzdem UNELEGANT. SPeicher ist Speicher und Festplatte ist Festplatte, das eine kann nicht den Job vom anderen übernehmen.

Nun ist allerdings eine Datei auf der Festplatte keine dynamische Liste, sondern eine sequentielle (eins folgt dem anderen) Struktur. Und würden wir einen Datensatz irgendwo aus der Mitte rauslöschen, wäre der nachfolgende Anteil der Datei unbrauchbar.

So geht es also nicht! (soviel zu faulen Programmierern wink.gif )

Es ist schon einiger Aufwand damit verbunden.

Wir hätten zunächst die Möglichkeit, den Datensatz zu editieren, also drin zu lassen und nachzubessern.

Das geht dann so:

Wir suchen den Datensatz. Dateizeiger steht dann auf Anfang Datensatz.

Wir kopieren den Datensatz in den Speicher zum Editieren.

ACHTUNG: nach dem Einlesen mit fread() steht der Dateizeiger HINTER dem Datensatz. Ein Zurückkopieren mit fwrite() würde den Datensatz unverändert lassen und den Nachfolger überschreiben oder Fehlermeldung weil EOF (Dateiende).

Wir müssen daher den Dateizeiger um (sizeof(Datensatz)) vor dem Zurückschreiben zurücksetzen.

Das wär das eine.

Wollen wir den aber wirklich löschen, können wir das nicht direkt aus den beschriebenen Gründen. Wir können den Datensatz zur Löschung vormerken. Z. B. mit einem Indexfeld int loeschen=NEIN, welches dann auf loechen=JA gesetzt wird.

Um den Datensatz aus der Datei auf der Festplatte (Speichermedium) zu entfernen, sind nun 2 Schritte nötig:

1.) Kopiere die gesamte Datei in eine andere Datei, wobei die zur Löschung vorgesehenen Datensätze nicht kopiert werden.

2.) Kopiere die Kopie zurück in die alte Datei, im Modus "w", womit die alte Datei zerstört wird, und schreibe alle Datensätze wieder zurück.

Dann haben wir eine neue alte Datei ohne die gelöschten Datensätze.

Das hat weniger mit C zu tun als mit der Logik der Dateiverwaltung. Wäre in anderen Programmiersprachen auch nicht anders.

Ich hab in dem Programm dafür beide Möglichkeiten vorgesehen.

Abb. 1 Korrektur zeigt (spartanisch) unten in der Zeile die Optionen:

gotoxy(5,KON_INFO-1);
printf("Optionen: Blaettern mit den Pfeiltasten OBEN / UNTEN Editieren = ENTER Abbruch = ESCAPE Datensatz loeschen = DEL/DEL");

Mit ENTER wird editiert (Datensatz ändern und zurückschreiben), mit DEL wird Löschvorgang eingeleitet.

Drückt man nun DEL, wird der Datensatz in veränderter Form angezeigt (abb loeschen.jpg)

Wir sehen, daß alles auf 0.0 zurückgesetzt wurde und das Textfeld auf ******************************************* geändert wurde.

Intuitive Benutzerführung wink.gif

Damit ist die Sache erledigt.

Es ist unelegant, im laufenden Programm für jeden einzelnen Datensatz die gesamte Datei hin- und herzukopieren.

Mein Programm erledigt das beim Programmende.

Dann werden alle zur Löschung vorgesehenen Datensätze entfernt, indem man, wie beschrieben, eine Kopie ohne diese Kandidaten anlegt und das wieder zurückkopiert.

Der Code ist eigentlich selbsterklärend. Wir haben zwei Dateien, Original und KOpie, und schaufeln die Daten auf die beschriebene Weise hin und her.

Obwohl der Vorgang ja nicht ganz banal ist, in C mit wenigen Zeilen abgetan.

Ist C nicht eine schöne Sprache? wink.gif


int kopieren_loeschen()
{
// Kopiert werden alle Datensätze außer den zur Loeschung vorgesehenen.
// Danach wird ins Originalfile zurückkopiert


FILE *FP_original;
FILE *FP_kopie;

strc_bsatz buffer;

char dn_kopie[KON_VIERTEL]="kopie.bin";

FP_kopie=fopen(dn_kopie,"wb");
if (FP_kopie==NULL)return NOTOK;

FP_original=fopen(dn_buchungen_bin,"rb");
if (FP_original==NULL)return NOTOK;

while ( fread(&buffer,sizeof(strc_bsatz),1,FP_original)==1)
if (buffer.loeschen!=JA) fwrite(&buffer,sizeof(strc_bsatz),1,FP_kopie);
fclose(FP_original);
fclose(FP_kopie);
FP_original=fopen(dn_buchungen_bin,"wb"); // zum Übersdchreiben neu öffnen, d.i. löschen
FP_kopie=fopen(dn_kopie,"rb");
if(FP_original==NULL || FP_kopie==NULL) return NOTOK;

while ( fread(&buffer,sizeof(strc_bsatz),1,FP_kopie)==1)
fwrite(&buffer,sizeof(strc_bsatz),1,FP_original); // ins Original per Überschreiben zurückkopieren
fclose(FP_original);
fclose(FP_kopie);

return OK;

Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 17:31 Uhr
Angehängte Datei(en)
Angehängte Datei  korrektur.jpg ( 146.45KB ) Anzahl der Downloads: 4
Angehängte Datei  loeschen.jpg ( 162.85KB ) Anzahl der Downloads: 5
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 18:17 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Nachdem ich mich nun für die komplette Löschung des Datensatzes entschieden habe (wie gesagt, Programm beenden, neu starten),

wird der Datensatz neu gebucht (den anderen, NK-Nachzahlung, hab ich versehendtlich auch gelöscht und gleich neu eingegeben).

Tja, das ist eben der Vorteil von einem MASSANZUG, daß man mit wenigen Klicks dahin kommt, wohin man will.

Bei den aufgemotzten Windows-Anwendungen kann man davon nur träumen.

Oder: die Wahrheit liegt in der Konsole. wink.gif

Mal im ERnst:

Für die Bearbeitung von einfachen zeilen/Spalten ist so eine Windows-Umgebung eher lästig. Überflüssiger Schnickschnack.

Sage ich als alter DOS-Programmierer.

Bringt keinen Mehrwert, stört nur das Auge. wink.gif

ALso: abb. korrektur2

Wir haben jetzt richtig gebucht, nämlich erfolgsneutral gegen Miete. 4230 gegen 4210 anstelle von (falsch) 4230 gegen 1200 (Bank).

Jetzt sehen wir mal auf die Auswertung (abb. ausw3)

Da sehen wir, daß die Miete im Saldo geschrumpft ist von 1850 Euro auf 1600 Euro, was ja richtig ist, weil die 250 Nebenkosten keine Miete sind.

Wir haben also hier nicht zusammgesetzt gebucht, nämlich Miete 1600 und NK 250 an Bank, sondern zwei Buchungssätze erzeugt, nämlich:

Miete 1850 Euro an Bank und

NK 250 Euro an Miete (rechnerisch gleichbedeutend, Frage was man will, Stilfrage). Und weil das eine Stilfrage ist, und das Ergebnis in beiden Fällen rechnerisch richtig, muß das der Anwender entscheiden und das Programm muß ihm beide Möglichkeiten offen halten, darf sich also nicht einmischen.

Schließlich: der Anwender ist der Boss (sagte die Sekretärin, als sie sich die Bluse wieder anzog ... wink.gif )

Und wir sehen vor allem den Unterschied zwischen einer erfolgswirksamen und einer erfolgsneutralen Buchung:

Das Ergebnis SOLL/HABEN unten ist nun 1749.89 anstelle wie nach der Fehlbuchung 1499,89.

Der Unterschied sind eben besagte 250 Euro, umsatzsteuerfrei.

Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 18:30 Uhr
Angehängte Datei(en)
Angehängte Datei  korr2.jpg ( 181.63KB ) Anzahl der Downloads: 3
Angehängte Datei  ausw3.jpg ( 218.8KB ) Anzahl der Downloads: 4
 


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 18:47 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Da die Logik der Buchungen eigentlich klar ist, mal hier zwischendurch etwas zur Programmierung.

Anschließend erkläre ich, wie man die Binär-Dateien (von außen unlesbar) in portable Formate überträgt, so daß der Steuerberater sie mit seinen DATEV-TOOLS einlesen kann.

Wenn der das so nicht rafft (bzw. seine Sekretärin, die davon keinen Plan hat), dann muß der eben die Ertragszahlen HÄNDISCH in die DATEV übernehmen, ist auch kein Thema.

Also, wir wollen eine Float-Zahl einlesen, 10 Stellen lang und zwei Nachkomma, und dazu wollen wir

NICHT die scanf() Funktion benutzen oder irgendwas in der Art, weil EXTREM UNSICHER, BUFFER_OVERFLOW,

sondern nur zeichenweise einlesen mit GETCH() und die Eingaben selbst verwalten.

Die Funktion hier ist nicht gerade die SPitze der C-Programmierung, man könnte das auf ein Drittel der Zeilen komprimieren, aber dann wär es nicht mehr lesbar.

Also, was macht die Funktion?

Sie liest Ziffern ein und . oder , , wobei das , (Komma) in . (Punkt) zurückverwandelt wird (wegen dem Dateien-Export), achtet darauf, daß das Komma nicht doppelt gesetzt wird oder an der falschen Stelle.

Wenn das Dezimaltrennzeichen kommt (Punkt oder Komma), wird der Rest der Eingabe abgeschnitten und neu berechnet.

Die Auswertung der in einen STRING geschriebenenen Ziffern erfolgt mit Standardfunktionen.

Eigentlich nix Großartiges, Pippifax, und man muß es auch nur einmal schreiben und kann es danach als selbstständigen Baustein für alle aufrufenden Funktionen, die eine Fließkommazahl benuten, verwenden.

Der Aufruf ist CALL BY VALUE, was sichh bei einfachen Datentypen anbietet. CALL BY REFERENCE würde hier keinen Sinn machen.

NOchmal: der Grund, sowas selbst zu schreiben, ist, daß man BUFFER_OVERFLOW vermeiden will, also den ANwender daran hindern will, daß er Unsinn eingibt oder Unsinn provoziert.

Mit getch() ist man auf der GANZ SICHEREN SEITE.

Eie Funktion ist so, wie sie ist, laufffähig. Sie funktioniert. Hier im Edit ist sie nicht eingerückt, schlecht lesbar. Wer sie ausprobieren will, soll das kopieren in den C-Editor und selbst probieren.

Garantiert: sie läuft. wink.gif



double float_eingabe(int xpos, int ypos, double vorgabe) // Standardformat %10.2f, letzte Kommastelle INDEX=7, 8+9 Nachkomma
{

char buffer[11];
sprintf(buffer,"%10.2f",vorgabe);
int stellen=10;
int ende=NEIN;
int pos=0;
char taste;
int pruef;
double dwert;
int i;
int kommapos=0;
int letzte_kommastelle=7;
int korrekt;

while (ende==NEIN)
{

gotoxy(xpos,ypos);
printf("%10s",buffer);
gotoxy(xpos+pos,ypos);
taste=getch();

if (taste>='0'&&taste<='9')
{ // if ziffer
if (pos==0)
{
strncpy(buffer,leer_VOLL,10); // alles rechts davon loeschen wg. Kommaproblem
buffer[pos]=taste; // Ziffer uebernehmen
pos++;
}
else
{
kommapos=0;
for (i=1;i<stellen;i++)if (buffer[i]=='.')kommapos=i;
if (kommapos==0) // bisher kein Komma
{
if (pos!=letzte_kommastelle)
{
buffer[pos]=taste; // Ziffer uebernehmen
if (pos<stellen)pos++;
}
}
else // komma vorhanden
{
if (pos<kommapos)
{
buffer[pos]=taste; // Ziffer uebernehmen
if (pos<stellen)pos++;
}
if (pos==kommapos) // Komma wird überschrieben alles rechts davon loeschen
if(pos!=letzte_kommastelle)
{
for (i=kommapos;i<stellen;i++) buffer[i]=BLANK;
buffer[pos]=taste;
if (pos<stellen)pos++;
}
if (pos>kommapos) if(kommapos-pos<=2)
{
buffer[pos]=taste;
if (pos<stellen)pos++;

}
} // else komma vorhanden
} // else pos>0
} // if ziffer
if (taste=='.'||taste==',') // Komma
{
kommapos=0;
for (i=0;i<stellen;i++)if (buffer[i]=='.') kommapos=i;
if (kommapos==0) // noch kein Komma vorhanden
{
korrekt=JA;
if (pos==0)korrekt=NEIN;
if (pos==1)
{
if(buffer[0]<'0'||buffer[0]>'9') korrekt=NEIN;
}
if (pos>letzte_kommastelle)korrekt=NEIN;
if (korrekt==JA)
{
for (i=pos;i<stellen;i++)buffer[i]=BLANK;
buffer[pos]='.';
pos++;
}
}// kein Komma vorhanden
} // if . ,
if (taste=='-')
if (pos==0)
{
strncpy(buffer,leer_VOLL,10);
buffer[0]=taste;
pos++;
}
switch (int(taste))
{
case ESCAPE:

return 0.0;
break;
case BACKSPACE:
buffer[pos]=BLANK;
if (pos>0)pos--;
buffer[pos]=BLANK;
break;
case ENTER:
dwert=atof(buffer);
sprintf(buffer,"%10.2f",dwert); // Formatierung durch zweimal umwandlen
gotoxy(xpos,ypos);
printf("%10s",buffer);
return dwert;
break;
} // switch
}//while
} // funktion

Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 18:54 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    
Beitrag 21.01.2012, 19:03 Uhr
sharky2014
sharky2014
Level 7 = Community-Professor
*******
Gruppe: Mitglied
Mitglied seit: 25.09.2008
Beiträge: 1.692

Kommen wir zum Problem der Portabilität der gesammelten Daten.

Eine Binär-Datei ist grundsätzlich von anderen Programmen nicht lesbar.

Zwar kann jeder Programmierer hingehen und versuchen, den Code zu knacken, und wird das auch schaffen, aber das ist hier außerhalb des Blickfeldes.

Binärdateien sind extrem effektiv für die interne Programmierung, wollen wir die Daten exportieren, müssen wir sie sichtbar machen.

Der breiteste Standard dafür sind Text-Dateien.

Dazu formatieren wir unsere struktuierten Datentypen in eine einzige Zeile um, in eine Textzeile.

Wir müssen aus 149.11 einen STring machen mit formatierter Länge, sagen wir 10.2f, und dann sehen

149.11 so aus:

" 149.11"

und sind dann keine Floatzahl mehr, sondern ein Zeichenstring.

Und wir hängen dann die ganze Struktur hintereinander, bis am Ende eine Zeile steht.

Diese Funktion wandelt die strukturierten Datensätze um in eine einzige Textzeile und speichert sie als Textdatei ab.

Der zugrundeliegende Datentyp, der in eine Textzeile umgeformt werden muß, sieht so aus:


typedef struct {
int lfd_nr;
int konto_nr;
int loeschen;
double netto;
int gkonto_nr;
double gk_betrag;
double ust_proz;
double brutto;
double ust_betrag;
int ust_konto;
datstring datum;
char text[KON_VIERTEL];
int index;
int index_dat;
int lief_nr; // Der Lieferant
int steuerschluessel;
} strc_bsatz;



Daraus wird nun die Textzeilge geformt.


int kopiere_b_datei_bin_txt()
{
char buffer[STRLEN_MAX];
FILE *bdp;
FILE *txtp;
bdp=fopen(dn_buchungen_bin,"rb");
if (bdp==NULL)
{
meldung("Kann Bin-Datei nicht oeffnen");
return NOTOK;
}
txtp=fopen(dn_buchungen_txt,"wt");
if (txtp==NULL)
{
meldung("Dateifehler");
return NOTOK;
}
// HEader:
sprintf(buffer,"Nr.; Konto; Netto; G-Konto;GK-Betrag; USt; Brutto; Steuer; USt-Konto; Datum; Index; Index; Lief-Nr.;St-Schl.; Text\n"),
fputs(buffer,txtp);


while (fread(&bsatz,sizeof(strc_bsatz),1,bdp) ==1)
{

sprintf(buffer,"%6i;%4i;%10.2f;%4i;%10.2f;%5.1f;%10.2f;%10.2f;%4i;%10s;%6i;%6i;%4i;%1i;",
bsatz.lfd_nr,
bsatz. konto_nr,
bsatz. netto,
bsatz. gkonto_nr,
bsatz. gk_betrag,
bsatz. ust_proz,
bsatz. brutto,
bsatz. ust_betrag,
bsatz. ust_konto,
bsatz.datum,
bsatz. index,
bsatz. index_dat,
bsatz.lief_nr,
bsatz.steuerschluessel);
strncat(buffer,bsatz.text,KON_VIERTEL);
strncat(buffer," ",1);
buffer[strlen(buffer)-1]=ENDOFLINE;
buffer[strlen(buffer)]=ENDOFSTRING;

fputs(buffer,txtp);
}// while

fclose(bdp);
fclose(txtp);

return OK;

}// fu


Der Beitrag wurde von sharky bearbeitet: 21.01.2012, 19:05 Uhr


--------------------
A programmer is just a tool which converts caffeine into code
TOP    



1 Besucher lesen dieses Thema (Gäste: 1)
0 Mitglieder: