Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb (https://www.delphipraxis.net/164731-vorgehensweise-fuer-rechnungsnummernvergabe-im-multi-user-betrieb.html)

hoika 28. Nov 2011 07:10

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

Furtbichler 28. Nov 2011 07:40

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.

MGC 28. Nov 2011 08:14

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.

jobo 28. Nov 2011 09:10

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.
;)

Sir Rufo 28. Nov 2011 09:13

AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
 
Mit MySQL würde das so aussehen:
Code:
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;
Zum Testen habe ich folgendes (mit 10+ Programm-Instanzen) ausführen lassen:
Delphi-Quellcode:
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.
Es treten weder Lücken auf, noch kommt es zu Ausnahmen, weil eine Beleg-Nummer doppelt vergeben wurde.

ChrisE 28. Nov 2011 09:16

AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
 
Zitat:

Zitat von jobo (Beitrag 1138187)
OT:
Ist das wirklich so, dass das Finanzamt auf sowas besteht?

OT:
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.

Sir Rufo 28. Nov 2011 09:19

AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
 
In der Dokumentation von MySQL steht dazu folgendes:
Zitat:

Zitat von MySQL Dokumentation 5.1
Betrachten wir ein anderes Beispiel: Wir haben in der Tabelle child_codes ein Zählerfeld eines Integer-Typs, das wir dazu benutzen, jedem Kind, das der child-Tabelle hinzugefügt wird, eine eindeutige Kennnummer zu geben. Da wäre es natürlich keine gute Idee, den Wert des Zählers mit einer konsistenten Leseoperation oder im Shared-Modus zu lesen, da zwei Datenbanknutzer dann vielleicht denselben Zählerwert sehen und einen Fehler wegen Schlüsselduplikaten auslösen, sofern sie versuchen, Kindeinträge mit derselben Nummer in die Tabelle einzufügen.

Hier ist LOCK IN SHARE MODE keine gute Lösung. Denn wenn zwei Benutzer gleichzeitig den Zähler lesen, könnte mindestens einer von ihnen in einen Deadlock geraten, wenn er versucht, den Zähler zu aktualisieren.

Hier haben Sie zwei gute Möglichkeiten, das Lesen und Inkrementieren des Zählers zu implementieren: (1) Sie inkrementierten zuerst den Zähler um 1 und führen erst dann die Leseoperation durch, oder (2) Sie lesen den Zähler zuerst im Sperrmodus FOR UPDATE und inkrementieren ihn danach. Der zweite Ansatz kann folgendermaßen implementiert werden:
Code:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
Ein SELECT … FOR UPDATE liest die neuesten verfügbaren Daten und errichtet eine exklusive Sperre auf jeder Zeile, die es liest. Somit setzt es dieselben Sperren, die auch ein Searched SQL UPDATE auf den Zeilen erwerben würde.

Die obige Beschreibung ist nur ein Beispiel dafür, wie SELECT … FOR UPDATE funktioniert. In MySQL können Sie einen eindeutigen Identifier grundsätzlich mit nur einem einzigen Tabellenzugriff generieren:
Code:
UPDATE child_codes SET counter_field = LAST_INSERT_ID(counter_field + 1);
SELECT LAST_INSERT_ID();
Die SELECT-Anweisung ruft nur die Identifier-Information ab (die für die aktuelle Verbindung spezifisch ist). Sie greift auf keine Tabellen zu.

Sperren von IN SHARE MODE- und FOR UPDATE-Leseoperationen werden freigegeben, wenn die Transaktion committet oder zurückgerollt wird.


webcss 28. Nov 2011 09:53

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...

Uwe Raabe 28. Nov 2011 10:07

AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
 
Ein Zitat der Oberfinanzdirektion Koblenz zu diesem Thema:

Zitat:

Nach den Erörterungen der obersten Finanzbehörden des Bundes und der Länder gilt Folgendes:

...

Angabe einer fortlaufenden Nummer in der Rechnung
Die in § 14 Abs. 4 S. 1 Nr. 4 UStG enthaltene Pflichtangabe einer fortlaufenden Nummer in der Rechnung macht keine zahlenmäßige Abfolge der ausgestellten Rechnungsnummern zwingend, da es lediglich um die Einmaligkeit der erteilten Rechnungsnummer geht. Die Anforderungen an die Rechnung sind vor dem Hintergrund zu interpretieren, dass es um die Verhinderung eines ungerechtfertigten Vorsteuerabzugs geht. Diesbezüglich reicht die Einmaligkeit der Nummerierung aus (Abschn. 185 Abs. 10 UStR).

Sir Rufo 28. Nov 2011 10:18

AW: Vorgehensweise für Rechnungsnummernvergabe im Multi-User Betrieb
 
Zitat:

Zitat von webcss (Beitrag 1138198)
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...

Woher willst du wissen, dass diese NICHT fortlaufend sind? Kennst du die Nummerierungs-Regeln von amazon?
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:

Ich hätte da mal eine Nachfrage zu einer Rechnung mit der Nummer 71...[halbe Stunde später]...68


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:37 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz