/*
**  Verwaltung von Aufträgen
**
** Copyright (C) 1996 by Stefan Scherer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for non-commerical use and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation.  This software is provided "as is" without
** express or implied warranty.
*/

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <exec/lists.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <clib/alib_protos.h>

#include "Auftrag.h"
#include "LocaleSupport.h"

/* die maximale Länge einer Zeile im Auftragsfile */

#define MAX_LINE_LEN 500

/*
** intern wird der Auftrag in einer Struktur verwaltet.
*/

struct Order
  {
    struct MinCustomer customer;	/* der Kunde dieses Auftags */

    UWORD orderNumber;
    UWORD orderYear;		/* bilden zusammen die Auftragsnummer */
    char orderDate[12];		/* Tag, an dem der Auftrag erstellt wurde */

    UWORD invoiceNumber;
    UWORD invoiceYear;		/* bilden beide die komplette Rech-Nr. */
    char invoiceDate[12];	/* Tag, an dem Rechnung erstellt wurde */

    struct List orderList;	/* Liste aller Artikel in dem Auftrag */
    struct orderNode *aktNode;	/* Zeiger auf aktuellen Eintrag in der Liste */
    UWORD aktNummer;		/* aktuelle Nummer des Eintrags in der Liste */
    UWORD itemCount;		/* Anzahl Einträge in der Liste */
    double MwSt1, MwSt2;	/* die aktuellen Mehrwertsteuersätze */

/* 17.11.94: neue Einträge */

    char Unit[8];		/* Währung als String, DM */
    char GroupSeparator[8], DecimalPoint[8], FracGroupSeparator[8];
  };


/* jeder Artikel in der Liste */

struct orderNode
  {
    struct Node Node;
    struct Article item;
  };



static struct Order ord;	/* der interne Auftrag wird hier abgelegt */
static void *poolHeader = NULL;	/* Zeiger für Memory-Pool */
static BOOL status;		/* Status, ob Auftrag geändert wurde */


/* Fehlercode und Fehlerstrings */

static int error;
static const STRPTR errormsg[] =
{
  "",				//   ERR_ORD_OK
   "kein memorypool",		//   ERR_ORD_NOPOOL
   "nicht genügend Speicher",	//   ERR_ORD_NOMEM
   "Liste ist leer",		//   ERR_ORD_LISTEMPTY
   "Eintrag nicht in Liste",	//   ERR_ORD_NOITEM
   "File nicht gefunden",	//   ERR_ORD_FILENOTFOUND
   "Konnte File nicht erzeugen",	//   ERR_ORD_CANTCREATEFILE
   "Fehler beim schreiben",	//   ERR_ORD_CANTCREATEFILE
};


/*
** Konstruktur-Funktion zum Initialisieren
*/

int 
ConstructOrder (void)
{
  return (error = O_NewOrder ());
}


/*
** Destruktor-Funktion zum Speicher freigeben
*/

void 
DestructOrder (void)
{
  if (poolHeader)
    {
      LibDeletePool (poolHeader);
      poolHeader = NULL;
    }
}


/*
** neuen Auftrag beginnen. Alle Daten werden zurückgesetzt.
*/

int 
O_NewOrder (void)
{
  status = FALSE;

  ord.customer.Adresse1[0] = 0;
  ord.customer.Adresse2[0] = 0;
  ord.customer.Adresse3[0] = 0;
  ord.customer.Adresse4[0] = 0;
  ord.customer.Adresse5[0] = 0;
  ord.customer.KundenNummer = 0;
  ord.customer.Zeichen[0] = 0;

  ord.orderNumber = 0;
  ord.orderYear = GetThisYear ();

  /* Auftragsdatum auf heutigen Tag setzen */
  ord.orderDate[0] = 0;
  CorrectDate (ord.orderDate);

  ord.invoiceNumber = 0;
  ord.invoiceYear = 0;
  ord.invoiceDate[0] = 0;

  /* Memory-Pool mit der Liste entfernen */
  NewList (&ord.orderList);
  ord.aktNode = NULL;
  ord.aktNummer = 0;
  ord.itemCount = 0;

  strcpy (ord.Unit, Locale->loc_MonCS);
  strcpy (ord.GroupSeparator, Locale->loc_MonGroupSeparator);
  strcpy (ord.DecimalPoint, Locale->loc_MonDecimalPoint);
  strcpy (ord.FracGroupSeparator, Locale->loc_MonFracGroupSeparator);

  if (poolHeader)
    {
      LibDeletePool (poolHeader);
      poolHeader = NULL;
    }

  /* neuen Memory-Pool anfordern */
  if (!(poolHeader = LibCreatePool (MEMF_CLEAR, 4000, 4000)))
    return (error = ERR_ORD_NOPOOL);

  return (error = ERR_ORD_OK);
}


/* füge neuen Eintrag in die Liste ein */

int 
O_AddOrderItem (struct Article *item)
{
  struct orderNode *newitem;

  if (!(newitem = LibAllocPooled (poolHeader, sizeof (struct orderNode))))
      return (error = ERR_ORD_NOMEM);

  status = TRUE;
  newitem->item.Betrag = item->Betrag;
  newitem->item.Menge = item->Menge;
  newitem->item.Preistabelle = item->Preistabelle;
  strcpy (newitem->item.Artikelnummer, item->Artikelnummer);
  strcpy (newitem->item.Bezeichnung, item->Bezeichnung);

  newitem->item.EKBetrag = item->EKBetrag;
  strcpy (newitem->item.Lieferfirma, item->Lieferfirma);
  strcpy (newitem->item.Notiz, item->Notiz);
  newitem->item.Datum[0] = 0;

  AddTail (&ord.orderList, (struct Node *) newitem);

  ord.aktNode = newitem;
  ord.itemCount++;
  ord.aktNummer = ord.itemCount;	/* Zählung erfolgt von 1 ... */

  return (error = ERR_ORD_OK);
}


/* lösche den aktuellen Eintrag aus der Liste */

int 
O_DelOrderItem (void)
{
  struct orderNode *newakt;

  if (ord.itemCount == 0)
    return (error = ERR_ORD_LISTEMPTY);

  status = TRUE;
  if (ord.aktNummer == ord.itemCount)
    {
      if (ord.itemCount > 1)
	newakt = (struct orderNode *) ord.aktNode->Node.ln_Pred;
      else
	newakt = NULL;

      RemTail (&ord.orderList);
      LibFreePooled (poolHeader, ord.aktNode, sizeof (struct orderNode));
      ord.aktNummer--;
      ord.itemCount--;
      ord.aktNode = newakt;
    }
  else
    {
      if (ord.itemCount > 1)
	newakt = (struct orderNode *) ord.aktNode->Node.ln_Succ;
      else
	{
	  newakt = NULL;
	  ord.aktNummer = 0;
	}

      Remove ((struct Node *) ord.aktNode);
      LibFreePooled (poolHeader, ord.aktNode, sizeof (struct orderNode));
      ord.itemCount--;
      ord.aktNode = newakt;
    }
  return (error = ERR_ORD_OK);
}


/* ändere den aktuellen Eintrag in der Liste */

int 
O_ChangeOrderItem (struct Article *item)
{
  if (ord.itemCount == 0)
    return (error = ERR_ORD_LISTEMPTY);

  status = TRUE;
  ord.aktNode->item.Betrag = item->Betrag;
  ord.aktNode->item.Menge = item->Menge;
  ord.aktNode->item.Preistabelle = item->Preistabelle;
  strcpy (ord.aktNode->item.Artikelnummer, item->Artikelnummer);
  strcpy (ord.aktNode->item.Bezeichnung, item->Bezeichnung);

  ord.aktNode->item.EKBetrag = item->EKBetrag;
  strcpy (ord.aktNode->item.Lieferfirma, item->Lieferfirma);
  strcpy (ord.aktNode->item.Notiz, item->Notiz);
  ord.aktNode->item.Datum[0] = 0;

  return (error = ERR_ORD_OK);
}


/* mache den 'number'ten Eintrag zum aktuellen Eintrag in der Liste */

int 
O_SetCurrentItemNumber (UWORD number)
{
  int i;
  struct Node *node;

  if (ord.itemCount == 0)
    return (error = ERR_ORD_LISTEMPTY);

  if (number >= ord.itemCount)
    return (error = ERR_ORD_NOITEM);

  for (i = 0, node = ord.orderList.lh_Head; i < number;
   i++, node = node->ln_Succ);

  ord.aktNummer = number + 1;
  ord.aktNode = (struct orderNode *) node;

  return (error = ERR_ORD_OK);
}


/* ändere die Adresse des Kunden im Auftrag */

void 
O_SetOrderAddress (struct MinCustomer *cust)
{
  status = TRUE;
  strcpy (ord.customer.Adresse1, cust->Adresse1);
  strcpy (ord.customer.Adresse2, cust->Adresse2);
  strcpy (ord.customer.Adresse3, cust->Adresse3);
  strcpy (ord.customer.Adresse4, cust->Adresse4);
  strcpy (ord.customer.Adresse5, cust->Adresse5);
  strcpy (ord.customer.Zeichen, cust->Zeichen);
  ord.customer.KundenNummer = cust->KundenNummer;
}


/* ändere die Auftragsnummer   Format: "12/1994" oder "" wenn kein Auftrag */

void 
O_SetOrderNumber (STRPTR buffer)
{
  STRPTR p;

  status = TRUE;
  if (p = strchr (buffer, '/'))
    {
      ord.orderYear = atol (buffer);
      ord.orderNumber = atol (p + 1);
    }
  else
    {
      ord.orderYear = 0;	/* kein Auftrag vorhanden */
      ord.orderNumber = 0;
    }
}


/* ändere das Auftragsdatum */

void 
O_SetOrderDate (STRPTR date)
{
  status = TRUE;
  strncpy (ord.orderDate, date, 10);
  ord.orderDate[10] = 0;
}


/* ändere die Rechnungsnummer  Format: "12/1994" oder "" wenn keine Rechnung */

void 
O_SetInvoiceNumber (STRPTR buffer)
{
  STRPTR p;

  status = TRUE;
  if (p = strchr (buffer, '/'))
    {
      ord.invoiceYear = atol (buffer);
      ord.invoiceNumber = atol (p + 1);
    }
  else
    {
      ord.invoiceYear = 0;	/* (noch) keine Rechnung vorhanden */
      ord.invoiceNumber = 0;
    }
}


/* ändere das Rechnungsdatum */

void 
O_SetInvoiceDate (STRPTR date)
{
  status = TRUE;
  strncpy (ord.invoiceDate, date, 10);
  ord.invoiceDate[10] = 0;
}


/*
**  Auftrag laden
**  Der bisherige Auftrag wird gelöscht!
**
** Der Auftrag wird als ASCII-Text gelesen und hat folgenden Inhalt:
**
** Zeile  Inhalt
** 
** 1      Anrede
** 2      Kundenadresse
** 3      Kundenadresse
** 4      Kundenadresse
** 5      Kundenadresse
** 6      Kundennummer
**
** 17.11.94:
**------
** 6a     TAB
**
** 6b     Währung TAB
** 6c     Trenner vorkomma TAB
** 6d     Komma TAB
** 6e     Trenner nachkomma
**------
** 7      Ihre Zeichen
** 8      Auftragsjahr / Auftragsnummer
** 9      Datum für Feld "Ihr Auftrag vom" TAB Kennzeichen
**        TAB Fahrzeugnr TAB KFZzusatz
** 
** 11     Artikelbezeichnung TAB
**        Menge TAB
**        VK-Einzel-netto TAB
**        MwSt-Nr TAB
**        Summe-netto TAB
**        Artikelnummer TAB
**        EK-Einzel-netto TAB
**        Lieferfirma TAB
**        Notiz TAB Farbe TAB Größe TAB Material
** 
** 14     Abschluß der Liste mit einem TAB + Return oder nur Return
** 
** 15     Nettosumme für MwSt1
** 16     Nettosumme für MwSt2
** 17     MwStsumme 1
** 18     MwStsumme 2
** 19     Bruttosumme
**
** 20     Trennung mit Leerzeile
** 
** 21     Datum der Rechnungserstellung
** 22     Rechnungsjahr / Rechnungsnummer
** 23     MwSt 1
** 24     MwSt 2
** 
*/

int 
O_LoadOrder (STRPTR filename)
{
  FILE *file;
  int result;
  BOOL ok = TRUE, loop;
  char buffer[3 * MAX_LINE_LEN + 1];
  char *p, *oldp;

  struct Article item;

  result = O_NewOrder ();

  if (!result)
    {
      if (file = fopen (filename, "r"))
	{
	  /*
	     ** · Anrede
	     ** · Kundneadresse (4 Zeilen)
	   */
	  if (!fgets (ord.customer.Adresse1, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (p = strchr (ord.customer.Adresse1, '\n'))
	    *p = 0;
	  if (ok && !fgets (ord.customer.Adresse2, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (p = strchr (ord.customer.Adresse2, '\n'))
	    *p = 0;
	  if (ok && !fgets (ord.customer.Adresse3, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (p = strchr (ord.customer.Adresse3, '\n'))
	    *p = 0;
	  if (ok && !fgets (ord.customer.Adresse4, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (p = strchr (ord.customer.Adresse4, '\n'))
	    *p = 0;
	  if (ok && !fgets (ord.customer.Adresse5, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (p = strchr (ord.customer.Adresse5, '\n'))
	    *p = 0;

	  /*
	  ** · Kundennummer
	  */
	  if (ok && !fgets (buffer, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (ok)
	    ord.customer.KundenNummer = atol (buffer);

	  /* alte Rechnung geladen, Währung IST deutsch */
	  strcpy (ord.Unit, "DM");
	  strcpy (ord.GroupSeparator, ".");
	  strcpy (ord.DecimalPoint, ",");
	  strcpy (ord.FracGroupSeparator, ".");

	  if (p = strchr (buffer, '\t'))
	    {
	      oldp = ++p;

	      if (p = strchr (oldp, '\t'))
		{
		  *p++ = 0;
		  /* Währung */
		  strcpy (ord.Unit, oldp);
		  oldp = p;

		  if (p = strchr (oldp, '\t'))
		    {
		      *p++ = 0;
		      /* Trenner vorkomma */
		      strcpy (ord.GroupSeparator, oldp);
		      oldp = p;

		      if (p = strchr (oldp, '\t'))
			{
			  *p++ = 0;
			  /* Komma */
			  strcpy (ord.DecimalPoint, oldp);
			  oldp = p;

			  if (p = strchr (oldp, '\n'))
			    {
			      *p++ = 0;
			      /* Trenner nachkomma */
			      strcpy (ord.FracGroupSeparator, oldp);
			    }
			}
		    }
		}
	    }


	  /*
	  ** · Ihre Zeichen
	  */
	  if (ok && !fgets (ord.customer.Zeichen, MAX_ORD_LEN, file))
	    ok = FALSE;
	  if (p = strchr (ord.customer.Zeichen, '\n'))
	    *p = 0;

	  /*
	  ** · Auftragsjahr / Auftragsnummer
	  */
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;
	  if (p = strchr (buffer, '\n'))
	    *p = 0;
	  if (ok)
	    {
	      STRPTR p;
	      if (p = strchr (buffer, '/'))
		{
		  ord.orderYear = atol (buffer);
		  ord.orderNumber = atol (p + 1);
		}
	      else
		{
		  ord.orderYear = 0;	/* keine Rechnung vorhanden */
		  ord.orderNumber = 0;
		}
	    }

	  /*
	  ** · Datum für Feld "Ihr Auftrag vom"
	  */
	  if (ok && !fgets (ord.orderDate, 12, file))
	    ok = FALSE;
	  if (p = strchr (ord.orderDate, '\n'))
	    *p = 0;

	  /* jetzt kommen die einzelnen Artikel in des Auftrags
	  ** bis eine Leerzeile kommt.
	  */
	  loop = TRUE;
	  while (loop && ok)
	    {
	      /*
	      ** · Artikelbezeichnung  (alles mit TAB getrennt in einer Zeile)
	      ** · Menge
	      ** · VK-Einzel-netto
	      ** · MwSt-Nummer
	      ** · Summe netto
	      ** · Artikelnummer
	      ** · EK-Einzel-netto
	      ** · Lieferfirma
	      ** · Notiz
	      ** · Farbe
	      ** · Größe
	      ** · Material
	      */
	      if (!fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;
	      if (ok)
		{
		  if (p = strchr (buffer, '\t'))
		    {
		      if (p != buffer)
			{
			  *p++ = 0;
			  strcpy (item.Bezeichnung, buffer);
			  item.Menge = ScanMonetaryNew (p, ord.GroupSeparator, ord.DecimalPoint, ord.FracGroupSeparator);
			  if (p = strchr (p, '\t'))
			    {
			      p++;
			      item.Betrag = ScanMonetaryNew (p, ord.GroupSeparator, ord.DecimalPoint, ord.FracGroupSeparator);
			      if (p = strchr (p, '\t'))
				{
				  p++;
				  item.Preistabelle = atoi (p);

				  item.Artikelnummer[0] = 0;
				  if (p = strchr (p, '\t'))
				    {
				      p++;	/* Summe wird nicht benötigt */
				      if (p = strchr (p, '\t'))
					{
					  /* hinter der Summe ist noch was */
					  p++;
					  oldp = p;

					  if (p = strchr (p, '\t'))
					    {
					      *p++ = 0;
					      strcpy (item.Artikelnummer, oldp);

					      item.EKBetrag = ScanMonetaryNew (p, ord.GroupSeparator, ord.DecimalPoint, ord.FracGroupSeparator);

					      if (p = strchr (p, '\t'))
						{
						  p++;
						  if (p = strchr (oldp = p, '\t'))
						    {
						      *p++ = 0;
						      strcpy (item.Lieferfirma, oldp);
						      if (p = strchr (oldp = p, '\n'))
							*p = 0;
						      strcpy (item.Notiz, oldp);

						    }
						}
					    }
					}
				    }
				}
			    }

			  if (O_AddOrderItem (&item))
			    {
			      ok = FALSE;
			    }
			}
		      else
			loop = FALSE;	/* letzter Eintrag erreicht */
		    }
		  else
		    loop = FALSE;	/* kein TAB vorhanden */
		}
	    }	/* liest alle Artikel ein, bis eine Leerzeile kommt */

	  /*
	  ** · Nettosumme 1         überspringen
	  ** · Nettosumme 2
	  ** · MwSt 1
	  ** · MwSt 2
	  ** · Bruttosumme
	  */
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;

	  /*
	  ** · Trennung mit Leerzeile
	  */
	  if (ok && !fgets (buffer, MAX_LINE_LEN, file))
	    ok = FALSE;

	  if (ok)
	    {
	      /*
	      ** · Datum der Rechnungserstellung
	      */
	      if (ok && !fgets (ord.invoiceDate, 12, file))
		ok = FALSE;
	      if (p = strchr (ord.invoiceDate, '\n'))
		*p = 0;

	      /*
	      ** · Rechnungsjahr / Rechnungsnummer
	      */
	      if (ok && !fgets (buffer, MAX_LINE_LEN, file))
		ok = FALSE;
	      if (p = strchr (buffer, '\n'))
		*p = 0;

	      if (ok)
		{
		  STRPTR p;
		  if (p = strchr (buffer, '/'))
		    {
		      ord.invoiceYear = atol (buffer);
		      ord.invoiceNumber = atol (p + 1);
		    }
		  else
		    /* kein '/', dann keine Rechnung vorhanden */
		    {
		      ord.invoiceYear = 0;
		      ord.invoiceNumber = 0;
		    }
		}

	      /*
	      ** · MwSt 1
	      */
	      if (ok && !fgets (buffer, MAX_ORD_LEN, file))
		ok = FALSE;
	      if (ok)
		ord.MwSt1 = ScanMonetaryNew (buffer, ord.GroupSeparator,
					     ord.DecimalPoint,
					     ord.FracGroupSeparator);

	      /*
	      ** · MwSt 2
	      */
	      if (ok && !fgets (buffer, MAX_ORD_LEN, file))
		ok = FALSE;
	      if (ok)
		ord.MwSt2 = ScanMonetaryNew (buffer, ord.GroupSeparator,
					     ord.DecimalPoint,
					     ord.FracGroupSeparator);
	    }

	  status = FALSE;   /* geladene Rechnung wurde noch nicht geändert */

	  strcpy (ord.Unit, Locale->loc_MonCS);
	  strcpy (ord.GroupSeparator, Locale->loc_MonGroupSeparator);
	  strcpy (ord.DecimalPoint, Locale->loc_MonDecimalPoint);
	  strcpy (ord.FracGroupSeparator, Locale->loc_MonFracGroupSeparator);

	  fclose (file);
	}
      else
	result = error = ERR_ORD_FILENOTFOUND;
    }
  return (result);
}


/*
**  Auftrag speichern
**
** Der Auftrag wird als ASCII-Text gespeichert und hat folgenden Inhalt:
**
** Zeile  Inhalt
** 
** 1      Anrede
** 2      Kundenadresse
** 3      Kundenadresse
** 4      Kundenadresse
** 5      Kundenadresse
** 6      Kundennummer
**
** 17.11.94:
**------
** 6a     TAB
**
** 6b     Währung TAB
** 6c     Trenner vorkomma TAB
** 6d     Komma TAB
** 6e     Trenner nachkomma
**------
** 7      Ihre Zeichen
** 8      Auftragsjahr / Auftragsnummer
** 9      Datum für Feld "Ihr Auftrag vom"
** 
** 11     Artikelbezeichnung TAB
**        Menge TAB
**        VK-Einzel-netto TAB
**        MwSt-Nr TAB
**        Summe-netto TAB
**        Artikelnummer TAB
**        EK-Einzel-netto TAB
**        Lieferfirma TAB
**        Notiz TAB Farbe TAB Größe TAB Material
** 
** 14     Abschluß der Liste mit einem TAB + Return oder nur Return
** 
** 15     Nettosumme für MwSt1
** 16     Nettosumme für MwSt2
** 17     MwStsumme 1
** 18     MwStsumme 2
** 19     Bruttosumme
**
** 20     Trennung mit Leerzeile
** 
** 21     Datum der Rechnungserstellung
** 22     Rechnungsjahr / Rechnungsnummer
** 23     MwSt 1
** 24     MwSt 2
** 
*/

int 
O_SaveOrder (STRPTR filename)
{
  FILE *file;
  int result;
  BOOL ok = TRUE;
  char vkeinzbuf[20], sumbuf[20], ekeinzbuf[20], mengebuf[20];
  struct orderNode *node;
  STRPTR str;
  double netto1, netto2, mwst1, mwst2, brutto;

  if (file = fopen (filename, "w"))
    {
      /*
      ** · Anrede
      ** · Kundenadresse
      */
      if (fprintf (file, "%s\n%s\n%s\n%s\n%s\n", ord.customer.Adresse1,
	ord.customer.Adresse2, ord.customer.Adresse3, ord.customer.Adresse4,
		   ord.customer.Adresse5) < 0)
	ok = FALSE;

      /*
      ** · Kundennummer TAB Währung TAB Trenner vor TAB Komma TAB Trenner nach
      ** · Ihre Zeichen
      ** · Auftragsjahr
      ** · Auftragsnummer
      */
      if (ok && fprintf (file, "%d\t%s\t%s\t%s\t%s\n%s\n%04d/%d\n",
		    ord.customer.KundenNummer, ord.Unit, ord.GroupSeparator,
			 ord.DecimalPoint, ord.FracGroupSeparator,
		  ord.customer.Zeichen, ord.orderYear, ord.orderNumber) < 0)
	ok = FALSE;

      /*
      ** · Datum für Feld "Ihr Auftrag vom"
      */
      if (ok && fprintf (file, "%s\n", ord.orderDate ) < 0)
	ok = FALSE;

      /* jetzt kommt die Liste aller Artikel */

      for (node = (struct orderNode *) ord.orderList.lh_Head;
	   ok && node->Node.ln_Succ;
	   node = (struct orderNode *) node->Node.ln_Succ)
	{
	  /*
	  ** · Artikelbezeichnung
	  ** · Menge
	  ** · VK-Einzelbetrag netto
	  ** · MwSt-Nummer (1 oder 2)
	  ** · Summe netto
	  ** · Artikelnummer
	  ** · EK-Einzelbetrag netto
	  ** · Lieferfirma
	  ** · Notiz
	  ** · Farbe
	  ** · Size
	  ** · Material
	  */
	  PrintMonetary (vkeinzbuf, node->item.Betrag);
	  PrintMonetary (sumbuf, node->item.Betrag * node->item.Menge);
	  PrintMonetary (ekeinzbuf, node->item.EKBetrag);
	  PrintMonetary (mengebuf, node->item.Menge);

	  /* falls die Bezeichnung leer ist, dann ein Space als Bezeichnung
	  ** speichern.
	  */
	  if (node->item.Bezeichnung[0])
	    str = node->item.Bezeichnung;
	  else
	    str = " ";

	  if (fprintf (file, "%s\t\%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\n",
		       str, mengebuf, vkeinzbuf,
		       node->item.Preistabelle, sumbuf,
		       node->item.Artikelnummer, ekeinzbuf,
		       node->item.Lieferfirma, node->item.Notiz ) < 0)
	    ok = FALSE;
	}

      /* · Abschluß der Liste mit einer Leerzeile */
      /* zum Schluß noch die Summen, die jedoch nicht weiter */
      /* verwendet werden. */

      /*
      ** · Nettosumme für MwSt1
      ** · Nettosumme für MwSt2
      ** · MwStsumme 1
      ** · MwStsumme 2
      ** · Bruttosumme
      */
      O_GetOrderSum (&netto1, &netto2, &mwst1, &mwst2, &brutto);
      PrintMonetary (vkeinzbuf, netto1);
      if (ok && fprintf (file, "\n%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      PrintMonetary (vkeinzbuf, netto2);
      if (ok && fprintf (file, "%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      PrintMonetary (vkeinzbuf, mwst1);
      if (ok && fprintf (file, "%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      PrintMonetary (vkeinzbuf, mwst2);
      if (ok && fprintf (file, "%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      PrintMonetary (vkeinzbuf, brutto);
      if (ok && fprintf (file, "%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      /*
      ** · Trennung mit Leerzeile
      ** · Datum der Rechnungserstellung
      */
      if (ok && fprintf (file, "\n%s\n", ord.invoiceDate) < 0)
	ok = FALSE;

      /*
      ** · Rechnungsjahr
      ** · Rechnungsnummer
      ** · MwSt 1
      ** · MwSt 2
      */
      if (ok && fprintf (file, "%04d/%d\n", ord.invoiceYear,
			 ord.invoiceNumber) < 0)
	ok = FALSE;

      PrintMonetary (vkeinzbuf, ord.MwSt1);
      if (ok && fprintf (file, "%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      PrintMonetary (vkeinzbuf, ord.MwSt2);
      if (ok && fprintf (file, "%s\n", vkeinzbuf) < 0)
	ok = FALSE;

      if (ok)
	result = ERR_ORD_OK;
      else
	result = ERR_ORD_SAVE;

      status = FALSE;	/* gespeicherter Auftrag wurde nicht mehr geändert */

      fclose (file);
    }
  else
    result = ERR_ORD_CANTCREATEFILE;

  return (error = result);
}


/* lies einen bestimmten Eintrag aus der Liste aus */

int 
O_GetOrderItem (UWORD num, struct Article *item)
{
  struct orderNode *node;
  int i;

  if (ord.itemCount == 0)
    return (error = ERR_ORD_LISTEMPTY);

  if (num >= ord.itemCount)
    return (error = ERR_ORD_NOITEM);

  for (i = 0, node = (struct orderNode *) ord.orderList.lh_Head;
       i < num && node->Node.ln_Succ;
       i++, node = (struct orderNode *) node->Node.ln_Succ);

  item->Betrag = node->item.Betrag;
  item->Menge = node->item.Menge;
  item->Preistabelle = node->item.Preistabelle;
  strcpy (item->Artikelnummer, node->item.Artikelnummer);
  strcpy (item->Bezeichnung, node->item.Bezeichnung);

  item->EKBetrag = node->item.EKBetrag;
  strcpy (item->Lieferfirma, node->item.Lieferfirma);
  strcpy (item->Notiz, node->item.Notiz);
  item->Datum[0] = 0;

  return (error = ERR_ORD_OK);
}

/* Dummyversion für Demoversion */

int 
O_GetDummyOrderItem (UWORD num, struct Article *item)
{
  struct orderNode *node;
  int i;

  if (ord.itemCount == 0)
    return (error = ERR_ORD_LISTEMPTY);

  if (num >= ord.itemCount)
    return (error = ERR_ORD_NOITEM);

  for (i = 0, node = (struct orderNode *) ord.orderList.lh_Head;
       i < num && node->Node.ln_Succ;
       i++, node = (struct orderNode *) node->Node.ln_Succ);

  item->Betrag = min (node->item.Betrag, 50.0);
  item->Menge = node->item.Menge;
  item->Preistabelle = node->item.Preistabelle;
  strcpy (item->Artikelnummer, node->item.Artikelnummer);
  strcpy (item->Bezeichnung, node->item.Bezeichnung);

  item->EKBetrag = min (node->item.EKBetrag, 50.0);
  strcpy (item->Lieferfirma, node->item.Lieferfirma);
  strcpy (item->Notiz, node->item.Notiz);
  item->Datum[0] = 0;

  return (error = ERR_ORD_OK);
}


/* lies die Daten des aktuellen Eintrags aus der Liste aus */

int 
O_GetCurrentItem (struct Article *item)
{
  if (ord.itemCount == 0)
    return (error = ERR_ORD_LISTEMPTY);

  item->Betrag = ord.aktNode->item.Betrag;
  item->Menge = ord.aktNode->item.Menge;
  item->Preistabelle = ord.aktNode->item.Preistabelle;
  strcpy (item->Artikelnummer, ord.aktNode->item.Artikelnummer);
  strcpy (item->Bezeichnung, ord.aktNode->item.Bezeichnung);

  item->EKBetrag = ord.aktNode->item.EKBetrag;
  strcpy (item->Lieferfirma, ord.aktNode->item.Lieferfirma);
  strcpy (item->Notiz, ord.aktNode->item.Notiz);
  item->Datum[0] = 0;

  return (error = ERR_ORD_OK);
}


/* lies die Nummer des aktuellen Eintrags in der Liste aus */

int 
O_GetCurrentItemNumber (void)
{
  return (ord.aktNummer - 1);
}


/* lies die Anzahl der Einträge im Auftrag aus */

int 
O_GetOrderItemCount (void)
{
  return (ord.itemCount);
}


/* lies die Kundenadresse aus */

void 
O_GetOrderAddress (struct MinCustomer *cust)
{
  strcpy (cust->Adresse1, ord.customer.Adresse1);
  strcpy (cust->Adresse2, ord.customer.Adresse2);
  strcpy (cust->Adresse3, ord.customer.Adresse3);
  strcpy (cust->Adresse4, ord.customer.Adresse4);
  strcpy (cust->Adresse5, ord.customer.Adresse5);
  strcpy (cust->Zeichen, ord.customer.Zeichen);
  cust->KundenNummer = ord.customer.KundenNummer;

}


/* lies die Auftragsnummer aus */

void 
O_GetOrderNumber (STRPTR buffer)
{
  sprintf (buffer, "%04d/%d", ord.orderYear, ord.orderNumber);
}


/* lies das Auftragsdatum aus */

void 
O_GetOrderDate (STRPTR date)
{
  strncpy (date, ord.orderDate, 10);
  date[10] = 0;
}


/* lies die Rechnungsnummer aus */

void 
O_GetInvoiceNumber (STRPTR buffer)
{
  sprintf (buffer, "%04d/%d", ord.invoiceYear, ord.invoiceNumber);
}


/* lies das Rechnungsdatum aus */

void 
O_GetInvoiceDate (STRPTR date)
{
  strncpy (date, ord.invoiceDate, 10);
  date[10] = 0;
}


/*
** Prüfe, ob der Auftrag verändert (TRUE) wurde oder nicht (FALSE).
*/

BOOL 
O_GetStatus (void)
{
  return (status);
}

/*
** Mehrwertsteuersätze einstellen
*/

void 
O_SetMwSt (double mwst1, double mwst2)
{
  status = TRUE;
  ord.MwSt1 = mwst1;
  ord.MwSt2 = mwst2;
}

/*
** Mehrwertsteuersätze auslesen
**
** wenn Preistab == 2 ist, dann bekommt man den zweiten MwSt-Satz (7%),
** sonst immer den ersten MwSt-Satz (15%)
*/

double 
O_GetMwSt (UWORD preistab)
{
  if (preistab == 2)
    return (ord.MwSt2);
  return (ord.MwSt1);
}


/*
** Ermittle die Summe
**
** wenn Einträge nicht gewünscht sind, so können diese mit NULL belegt werden.
*/

void 
O_GetOrderSum (double *netto1, double *netto2, double *summwst1,
	       double *summwst2, double *brutto)
{
  struct orderNode *node;

  double n1, n2, s1, s2, b;

  n1 = n2 = 0.0;
  for (node = (struct orderNode *) ord.orderList.lh_Head;
       node->Node.ln_Succ;
       node = (struct orderNode *) node->Node.ln_Succ)
    {
      if (node->item.Preistabelle == 1)
	n1 += node->item.Betrag * node->item.Menge;
      else
	n2 += node->item.Betrag * node->item.Menge;
    }
  s1 = (double) ((LONG) (n1 * ord.MwSt1 + .5)) / 100;
  s2 = (double) ((LONG) (n2 * ord.MwSt2 + .5)) / 100;
  b = n1 + n2 + s1 + s2;

  if (netto1)
    *netto1 = n1;
  if (netto2)
    *netto2 = n2;
  if (summwst1)
    *summwst1 = s1;
  if (summwst2)
    *summwst2 = s2;
  if (brutto)
    *brutto = b;
}


/*
** lies die wichtigsten Daten auf einen Schlag
*/

void 
O_GetMinOrder (struct MinOrder *minorder)
{
  char buffer[100];

  minorder->orderNumber = ord.orderNumber;
  minorder->orderYear = ord.orderYear;
  strcpy (minorder->orderDate, ord.orderDate);

  /* nur den Nachnamen finden */
  C_PrintName (&ord.customer, buffer);
  strcpy (minorder->Kunde, buffer);

  minorder->invoiceNumber = ord.invoiceNumber;
  minorder->invoiceYear = ord.invoiceYear;
  strcpy (minorder->invoiceDate, ord.invoiceDate);
}


/*
** Lies den Fehlerstring aus
*/

STRPTR 
O_GetErrorMsg (void)
{
  return (errormsg[error]);
}
