![]() |
Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Hallo zusammen,
ich muss in einem Programm Rechnungsnummern mit fortlaufender Nummer vergeben ohne eine Lücke zu produzieren. Die Vergabe muss auch noch dann funktionieren, wenn mehrere Leute eine Rechnung erstellen. Ich habe dazu zwei Tabellen für die Rechnung. Die erste Tabelle enthält alle Daten zum Kunden und natürlich die Rechnungsnummer und die zweite Tabelle enthält alle Rechnungspositionen, mit Referenz auf die Rechnungsnummer. Ich hatte mir dazu zwei Möglichkeiten überlegt.
Wie würdet Ihr die Aufgabe lösen ? Eine meiner Möglichkeiten verwenden, wenn ja welche und warum ? Oder gibt es noch einen ganz anderen Ansatz ? P.S. : Wenn es umbedingt nötig ist, kann das Design der beiden Tabellen geändert werden. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Hallo,
Du hast doch mit Sicherheit eine Tabele, in der ggf. nur die vergebenen Rechnungsnummern stehen. Wenn Du beim Speichern die Tabelle kurzzeitig sperrst, den gröten bereits gespeicherten Wert ausliest, deine demnach nächst höhere Nummer spiecherst und dann die Tabelle für den nächsten freigibst sollte nichts mehr passieren können. Also im Prinzip Dein 2. Ansatz. Schwierig wird es jedoch, wenn Du mit verschiedenen Severn zu tun hast und diese erst synchronisiert werden. Dort könnte es dann zu Problenmen, bzw. bemerkbaren teitlichen Verzögerungen kommen. Auf welche Weise ist das DB-System aufgebaut, bzw. wie werden die Zugriffe geregelt udn welche Technologie setzt Du beim Zugriff auf die DB ein? Viele Grüße, |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Hallo,
ich mache es so: Es gibt eine Tabelle mit Rechnungsnummern, nur eine Spalte. Wenn eine Nummer gebraucht wird, holt sich der Client die kleinste Nummer aus der Tabelle und löscht sie. Wenn die Tabelle nahezu leer ist, wird sie wieder aufgefüllt. Bricht jemand eine Rechnung ab oder es geht sonst etwas schief, wird die Nummer wieder in die Tabelle zurückgeschrieben. Die Zeit von Nummer holen bis "verbrauchen" halte ich sehr kurz, die Nummer wird erst geholt wenn die Rechnung ausgegeben wird, nicht schon wenn die Positionen bearbeitet werden. Ist die Rechnung gedruckt und gegebenenfalls bestätigt ist die Nummer entgültig verbraucht. Dann kann man nur noch eine Stornorechnung machen. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Wie werden die Rechnungen erstellt?
Ich mache das so: Es wird zunächst eine offene Rechnung erstellt. Erst wenn diese vollständig (und in der DB vollständig gespeichert) ist, wird per Stored Procedure eine eindeutige und lückenlos steigende Rechnungsnummer erstellt. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Hallo...
welches DBMS ist im Einsatz ? Persönlich würde ich folgenden Ablauf bevorzugen: 1. RE speichern 2. DBMS vergibt eine Nummer über einen Generator (Firebird)... ist damit eindeutig und fortlaufend 3. Die Query enthält als Rückgabewert die Nummer 4. Mit dieser Nummer können dann die Positionen gespeichert werden (Zuordnung) |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
@haentschman
so kenn ich es auch, unter Berücksichtigung der Vorgaben finde ich die Implementierung von Neumann am interessantesten. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Zitat:
Zitat:
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Zitat:
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Klar, in diesem Ausnahmefall (bei fehlerhaftem Eintragen in die DB) wäre dann die Nummer verbraucht. Mit diesem Sonderfall hätten wahrscheinlich alle Lösungen ein Problem und sollte seperat behandelt werden.
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Zitat:
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Hallo,
die Sache mit dem Generator hat aber mit der Rechnungsnummer nichts zu tun (?). Es gibt 2 Felder, RechnungsID (PrimKey,über Generator) und RechnungsNr(über eigene Logik, z.B. Sperrtabelle). Heiko |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Na, die Idee stand im Raum, das man für die Rechnungs-Nr auch einen Generator verwendet.
Ich halte aber die Tabelle mit allen Rechnungsnummern (der nächsten 100 Jahre ;-)) für den einzig richtigen Weg, um Lücken zu vermeiden. Es ist ja schwer, dem Finanzamt zu vermitteln, weshalb Rechnung Nr.: 12345 nicht eingereicht wurde. Die interessiert dann nicht, wenn man dann die DB-Logdatei vorzeigt, der belegt, das eine Transaktion aufgrund was-weiss-ich fehlschlug. Allerdings muss man bei der Lösung sicherstellen, das zu Ultimo (z.B. Monatsende) keine Lücken vorhanden sind. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Das Finanzamt sollte mittlerweile aber Erfahrung im Einsatz von DBMS haben udn wissen, dass es immer wieder mal zu Fehlern kommen kann. :evil:
Aufgrund der beschriebenen Architektur würde ich persönlich auch noch immer dabei bleiben die Re-Nr. erst zu vergeben, wenn die Rechnung tatsächlich gespeichert wird. Bei der Rechnungsspeicherung darf es dann, wie bereits erwähnt, kein Rollback geben. Man kann natürlich auch darauf vertrauen, dass es, aufgrund weniger Rechnungsstellungen pro Tag, hoffentlich niemals zu einem zeitgleichen Speichervorgang in der DB kommt, aber das wäre mir zu wage. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
OT:
Ist das wirklich so, dass das Finanzamt auf sowas besteht? Dann vielleicht zum Monatsende oder Quartalsabschluss eine extra Liste mit fortlaufenden Nummern und Verweise auf die "interne" Rechnungsnummer produzieren und abheften. ;) |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Mit MySQL würde das so aussehen:
Code:
Zum Testen habe ich folgendes (mit 10+ Programm-Instanzen) ausführen lassen:
CREATE TABLE `beltab` (
`BelID` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT , `BelTyp` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `BelNr` int(11) NOT NULL DEFAULT 0 , `BelInfo` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , PRIMARY KEY (`BelID`), UNIQUE INDEX `UNQ_Typ_Nr` (`BelTyp`, `BelNr`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci AUTO_INCREMENT=1044 ROW_FORMAT=COMPACT; CREATE DEFINER=`root`@`%` TRIGGER `beltab_before_insert` BEFORE INSERT ON `NewTable` FOR EACH ROW SET NEW.BelNr = GetNewScopeLfd( NEW.BelTyp ); CREATE TABLE `tbl_lfd` ( `Scope` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `LastLfd` int(11) NOT NULL , `Step` int(11) NOT NULL DEFAULT 1 , PRIMARY KEY (`Scope`) ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci ROW_FORMAT=COMPACT; CREATE DEFINER = `root`@`%` FUNCTION `GetNewScopeLfd`(Scope varchar(50)) RETURNS int(11) BEGIN DECLARE NewLfd int; UPDATE tbl_lfd SET LastLfd = LastLfd + Step WHERE tbl_lfd.Scope = Scope; SELECT LastLfd INTO NewLfd FROM tbl_lfd WHERE tbl_lfd.Scope = Scope; RETURN NewLfd; END;
Delphi-Quellcode:
Es treten weder Lücken auf, noch kommt es zu Ausnahmen, weil eine Beleg-Nummer doppelt vergeben wurde.
unit View.Main;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, DBAccess, Uni, UniProvider, MySQLUniProvider, StdCtrls, ExtCtrls; type TForm1 = class( TForm ) MySQLUniProvider1 : TMySQLUniProvider; UniConnection1 : TUniConnection; Timer1 : TTimer; CheckBox1 : TCheckBox; procedure CheckBox1Click( Sender : TObject ); procedure Timer1Timer( Sender : TObject ); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1 : TForm1; implementation {$R *.dfm} procedure TForm1.CheckBox1Click( Sender : TObject ); begin Timer1.Enabled := CheckBox1.Checked; end; procedure TForm1.Timer1Timer( Sender : TObject ); begin Timer1.Enabled := False; if not UniConnection1.Connected then UniConnection1.Open; UniConnection1.StartTransaction; try UniConnection1.ExecSQL( 'INSERT INTO beltab (BelTyp, BelInfo) VALUES(:BelTyp,:BelInfo);', ['RECHNUNG', 'Nur so'] ); Sleep( 250 ); if Random( 2 ) = 1 then UniConnection1.Commit else UniConnection1.Rollback; except UniConnection1.Rollback; end; Timer1.Enabled := CheckBox1.Checked; end; end. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Zitat:
Soweit ich weiß, ist nur eine eindeutige aber keine fortlaufende Nummer wichtig. Da gab es ein paar Entscheidungen, da man gegenüber einem Kunden den Rückschluss auf die Anzahl der Rechnungen einer Firma verhindern wollte. |
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
In der Dokumentation von MySQL steht dazu folgendes:
Zitat:
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Ich denke auch, dass es lediglich um die Eindeutigkeit einer Rechnungsnummer zu einem Vorgang geht, d.h. keine doppelten Rechnungsnummern o.ä. Fortlaufend müssen diese aber nicht zwingend sein. Man schaue sich nur mal z.B. die Rechnungen von Amazon an, dort wird eine Folge von (alpha-)numerischen Zeichen in Groß- und Kleinschreibung sowie Ziffern verwendet. Diese sind wohl eindeutig, aber fortlaufend wohl kaum...
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Ein
![]() Zitat:
|
AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
Zitat:
Gerade weil hier nicht nur mit Ziffern gearbeitet wird, ist es schwer dieses nachzuvollziehen, wenn man die Regel kennt, aber sehr wohl. Der Hintergrund bei amazon ist aber wohl der, dass die Rechnungsnummern bei denen sehr schnell die Seitenbreite sprengen würden (bei der hohen Anzahl an Rechnungen) und daher haben die eben wohl ein 62er-ZahlenSystem (0..9,A..Z,a..z) genommen um relativ kurze Rechnungsnummern zu erhalten. Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz