...feel the spirit of Microsoft Dynamics AX RSS 2.0
 Friday, March 13, 2009

Im Standard von Microsoft Dynamics AX besteht auf jeder Maske, auf der Artikel und deren Lagerdimensionen angezeigt werden, die Möglichkeit, die Lagerdimensionen, bzw. die angezeigten Felder der Lagerdimensionen, über die Funktion "Lager-Dimensionenanzeige" entsprechend zu steuern.

Die einzelnen Elemente (Felder) der Lagerdimension können über diese Funktion ein- bzw. ausgebledet werden.

Weiterhin ist es auch möglich, durch Parametrisierung zu bestimmen, ob ein Feld einer Lagerdimension eingeben werden muss (Mussfeld) oder ob überhaupt eine Eingabe möglich ist.

Ein gutes Beispiel hierfür ist die Maske "Aufträge".

Wie ist es nun, wenn eine neue Maske erstellt werden soll, welche Artikelinformation und Lagerdimensionen anzeigen soll?
Wie genau muss vorgegangen werden, um die bereits an vielen Stellen im Standard verwendete Funktionalität auch für die selbst erstellte Maske bereitzustellen? 

Gehen wir einmal davon aus, es wurde eine neue Tabelle erstellt, welche die Artikelnummer (ItemId) und die Lagerdimensionsnummer (InventDimId) speichert.
Für diese Tabelle soll eine Maske erstellt werden, úm dem Benutzer die Möglichkeit zu geben, Datensätze zu erfassen, zu ändern oder einfach nur anzuzeigen.

Dies könnte z.B. so aussehen:

Um nun die Funktion der Lagerdimensionensteuerung einzubauen muss zuerst die Tabelle InventDim als DataSource der Maske hinzugefügt werden.
Anschließend müssen die Eigenschaften (Properties) der DataSource noch auf folgende Werte geändert werden.

Name

InventDim

JoinSource

Haupt-Datenquelle (hier: AKUDemoTable)

LinkType

InnerJoin

DelayActive

No

InsertAtEnd

No

InsertIfEmpty

No

Nun muss eine neue ButtonGroup (Name: "Inventory") im Designzweig der Maske erstellt werden. Diese sollte das LAbel "Lager" zugewiesen werden.
Nun noch das MenuItem "InventDimParmFixed" in diese ButtonGroup ziehen (z.B. per drag & drop aus dem AOT) und dem so erstellten MenuItemButton folgende Eigenschaften zuweisen.

Name

InventDimParmFixed

MenuItemName

InventDimParmFixed

DataSource

Haupt-Datenquelle (hier: AKUDemoTable)

Über das MenuItem (oder genauer über den erstellten MenuItemButton) wird nun wie im Standard, die Maske "Lagerdimensionen" zu öffnen.

Allerdings öffnet sich die Maske „Lagerdimensionen“ noch nicht wie gewünscht über den MenuItemButton. Hierfür sind noch weitere Anpassungen notwendig.

Damit sich die Maske „Lagerdimensionen“ wie gewünscht öffnet muss die neue Maske die Methode „inventDimSetupObject“ implementieren welche eine Instanz von „InventDimCtrl_Frm“ zurück gibt.

Die Klasse „InventDimCtrl_Frm“, bzw. eine der von ihr abgeleiteten Klassen, steuert z.B. welche Lagerdimensionen für den aktuellen Datensatz zulässig sind oder welche Dimensionen für den aktuellen Datensatz angegeben werden müssen, damit dieser gespeichert werden kann.

Da über die Parametrisierung der Lagersteuerungsgruppen und der Modulparameter hierfür durchaus unterschiedliche Einstellungen gewählt werden können, sind in Dynamics AX etliche Ableitungen dieser Klasse vorhanden (jede wird für eine oder mehrere andere Masken verwendet).

Je nachdem, was für eine Funktionalität bzw. was für ein Business-Prozess erstellt werden soll, kann entweder eine der bereits im Standard vorhandenen Klassen verwendet werden oder es muss eine neue Klasse geschrieben werden, um die benötigte Funktionalität zu liefern (z.B. welche Dimensionen immer angezeigt werden müssen).

Das Erstellen einer neuen Klasse, welche von „InventDimCtrl_Frm“ abgeleitet  ist, ist recht einfach.

Es sollte immer die Methode „new“ überschrieben werden und mindestens die statischen Methoden „construct“ und „newFromForm“ erstellt werden.

class AKUInventDimCtrl_Frm_Demo extends InventDimCtrl_Frm
{
}

protected void new()
{
  super();
}

public static AKUInventDimCtrl_Frm_Demo construct()
{
  return new AKUInventDimCtrl_Frm_Demo();
}

static AKUInventDimCtrl_Frm_Demo newFromForm(FormRun _formRun)
{
  AKUInventDimCtrl_Frm_Demo inventDimCtrl = AKUInventDimCtrl_Frm_Demo::construct();
  InventDimAxFormAdapter adapter = InventDimAxFormAdapter::newFromForm(_formRun);
  ;
  inventDimCtrl.parmCallingElement(adapter);
  inventDimCtrl.init();
  return inventDimCtrl;
}

Weiterhin können noch andere Methoden überschrieben werden, um z.B. zu steuern, welche Felder der Tabelle „InventDim“ beim Aufruf der Maske angezeigt werden sollen.
Weitere Informationen hierzu sind im Microsoft Dynamics AX Developer Center zu finden: http://msdn.microsoft.com/en-us/library/cc618009.aspx

NoYes mustShowGridField(fieldId _dimFieldId)
{
  NoYes ret;

  ret = super(_dimFieldId);
  //always show InventLocationId in Grid
  if(_dimfieldId == fieldnum(InventDim, InventLocationId))
  {
    ret = NoYes::Yes;
  }

  return ret;
}

Wie zuvor beschrieben muss nun die Methode „inventDimSetupObject“ auf der Maske implementiert werden. Das diese eine Instanz von „InventDimCtrl_Frm“ zurück geben muss, ist diese ebenfalls zu erzeugen. Als erstes muss eine Objektvariable für das „InventDimCtrl_Frm“ Objekt erstellt werden.

public class FormRun extends ObjectRun
{
  InventDimCtrl_Frm inventDimFormSetup;
}

Anschließend kann die Methode „inventDimSetupObject“ erstellt werden.

Object inventDimSetupObject()
{
  return inventDimFormSetup;
}

Da die Objektvariable durch diesen Quelltext noch nicht initialisiert wird, muss noch entsprechender Code zur Initialisierung geschrieben werden.

void updateDesign(InventDimFormDesignUpdate mode)
{
  inventDimParm inventDimParmShow;
  inventDimParm inventDimParmEnabled;
  ;
  switch (mode)
  {
    case InventDimFormDesignUpdate::Init :
      if (!inventDimFormSetup)
      {
        inventDimFormSetup = AKUInventDimCtrl_Frm_Demo::newFromForm(element);
      }
      inventDimFormSetup.parmSkipOnHandLookUp(true);

    case InventDimFormDesignUpdate::Active :
      inventDimFormSetup.formActiveSetup(
      inventTable::find(AKUDemoTable.ItemId).dimGroupId);
      inventDimFormSetup.formSetControls(true);
      break;

    case InventDimFormDesignUpdate::FieldChange :
      inventDimFormSetup.formActiveSetup(
      inventTable::find(AKUDemoTable.ItemId).dimGroupId);
      inventDim.clearNotSelectedDim(inventDimFormSetup.parmDimParmEnabled());
      inventDimFormSetup.formSetControls(true);
      break;

    default :
      throw error(strfmt("@SYS54195",funcname()));
  }
}

public void init()
{
  ;
  super();
  element.updateDesign(InventDimFormDesignUpdate::Init);
}

Da die Logik, welche durch die Methode „updateDesign“ bereit gestellt wird, mehrfach benötigt wird, erfolgt die Initialisierung des „InventDimCtrl_Frm“ Objekts nicht direkt in der „init“ Methode.

Damit die in der Maske erstellten Datensätze auch richtig gespeichert werden können, müssen nun noch einige weitere Anpassungen an den Methoden der Datenquellen vorgenommen werden.

Datasource „AKUDemoTable“ (Hauptdatenquelle):
Hier sind die Methoden „write“, „validateWrite“ und „active“ zu überschreiben.

public void write()
{
  ;
  ttsbegin;

  AKUDemoTable.inventDimId = InventDim::findOrCreate(InventDim).inventDimId;

  super();

  if(AKUDemoTable.inventDimId != InventDim.inventDimId)
  {
    InventDim.data(InventDim::find(AKUDemoTable.inventDimId));
    InventDim_ds.setCurrent();
  }

  ttscommit;
}

public boolean validateWrite()
{
  boolean ret;
  ;
  AKUDemoTable.InventDimId = inventDim::findOrCreate(InventDim).inventDimId;

  ret = super();
  return ret;
}

int active()
{
  int ret;
  ;
  ret = super();

  element.updateDesign(InventDimFormDesignUpdate::Active);

  inventDim_DS.active();

  return ret;
}

Datasource „InventDim“:
Hier müssen die Methoden „initValue“ und „write“ überschrieben werden.

public void initValue()
{
  ;
  InventDim.data(InventDim::find(AKUDemoTable.inventDimId));

  super();
}

public void write()
{
  //super();
}

Hierbei muss unbedingt beachtet werden, dass der „super“ Aufruf in der „write“ Methode der Datasource „InventDim“ auskommentiert wird, um das Speichern von falschen InventDim Datensätzen zu verhindern.

Als letzte Methode sollte nun noch die Methode „modified“ des DataSource-Field „ItemId“ der Datasource „AKUDemoTable“ überschrieben werden, damit auf eine Änderung der Artikelnummer reagiert werden kann (z.B. Artikelabhängige Anzeige der Lagerdimensionen).

public void modified()
{
  ;
  super();
  element.updateDesign(InventDimFormDesignUpdate::FieldChange);
}

Somit sind alle benötigten Quelltextanpassungen durchgeführt, sodass nur noch die Feldgruppe „InventoryDimensions“ der DataSource „InventDim“ mit in das Grid gezogen werden muss um die Lagerdimensionen auf der Maske anzuzeigen. Optional kann diese auch in die TabPage „Dimensions“ gezogen werden um ein standardkonformes Aussehen der Maske zu erhalten.

Das vorgestellt Bespiel steht hier als Download bereit um die einzelnen Schritte genau ansehen/nachvollziehen zu können.
AKU_Demo_InventDimFrm.rar (2,71 KB)

Friday, March 13, 2009 5:50:59 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 |  |  |  | 

 Saturday, April 12, 2008

Das Erstellen von Produktionsaufträgen sollte an sich kein Problem darstellen. Leider ist dem nicht ganz so.

Anders als in anderen Modulen (z.B. Aufträge) von Dynamics AX, existiert hierfür keine Klassenstruktur, welche die entsprechenden Funktionen bereit stellt.
Der Dynamics AX Standard erstellt Produktionsaufträge immer über die Maske „ProdTableCreate“. Es gibt aber Situationen, wo für die Erstellung eines Produktionsauftrages keine Maske verwendet werden kann. Ein Beispiel hierfür könnte eine Schnittstelle sein, welche über eine Textdatei die zu produzierenden Waren einließt und entsprechende Produktionsaufträge im System generiert.

Die Frage ist nun, wie erstellt man Produktionsaufträge per Quellcode, damit diese auch „richtig“ im System erzeugt werden (inkl. Stückliste, Arbeitsplan und Lagerbuchung).

  • Zuerst muss der Produktionsauftrag mit den Daten des zu produzierenden Artikels initialisiert werden.
  • Weiterhin müssen Produktionsmenge und Lieferdatum festgelegt werden.
  • Ebenfalls sind die zu verwendende Stückliste und der Arbeitsplan zu definieren.
  • Und als letzter Schritt muss der Produktionsauftrag noch erzeugt werden.

Hierbei gilt es aber zu beachten, dass die Erstellung (Speichern in der Datenbank) nicht mit der Methode „insert“ der Tabelle „ProdTable“ geschieht, sondern dass hierfür die Klasse „ProdTableType“ und deren Methode „insert“ verwendet wird. Nur so wird die entsprechende Lagerbewegung / Lagerbuchung im System erzeugt und wenn notwendig Referenzen zu einem Verkaufsauftrag oder einer anderen Produktion hinterlegt.

Um dies zu veranschaulichen ein kurzes Beispiel, in welchem ein neuer Produktionsauftrag erstellt wird.

static void CreateProductionOrder(Args _args)
{
    //Die zu produzierende Menge
    ProdQtySched productionQty = 1;
    //Der zu produzierende Artikel
    ItemId productionItem = "Artikelnummer";

    ProdTable prodTable;
    InventTable inventTable;
    ;
    inventTable = InventTable::find(productionItem);

    //Initialisierung des Produktionsauftrags
    prodTable.initValue();
    prodTable.ItemId = inventTable.ItemId;
    prodTable.initFromInventTable(inventTable);

    //Lieferdatum festlegen
    prodTable.DlvDate = today();

    prodTable.QtySched = productionQty;
    prodTable.RemainInventPhysical = prodTable.QtySched;

    //Die zu verwendende Stückliste und Arbeitsplan bestimmen
    prodTable.initRouteVersion();
    prodTable.initBOMVersion();

    //Produktionsauftrag erstellen
    prodTable.type().insert();
}

Selbstverständlich sind auch weitere Angaben bei der Erstellung des Produktionsauftrags möglich.
Z.B. kann ein Produktionsauftrag auch aus einer Verkaufsauftragsposition erzeugt werden (bei Verwendung der Methode "initFromSalesLine").

Saturday, April 12, 2008 2:30:59 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 |  | 

 Saturday, January 26, 2008

Das Buchen von Bestellungen in Microsoft Dynamics AX geschieht über die Klasse „PurchFormLetter“ bzw. einer ihrer konkretisierten (abgeleiteten) Klassen. Jeder Buchungstyp (z.B. Bestätigung oder Rechnung) ist durch eine eigene Klasse abgebildet, welche von der Basisklasse „PurchFormLetter“ abgeleitet ist (siehe Abbildung).

Abbildung 1 - Klassenhierarchie der Klasse „PurchFormLetter“

Vergleicht man die Klassenhierarchie der „PurchFormLetter“ Klassen mit der Klassenhierarchie der „SalesFormLetter“ Klassen, so ist zu erkennen, dass auch das Buchen von Bestellungen vom Prinzip her genau so funktioniert wie das Buchen von Aufträgen (Vergleiche hierzu: Microsoft Dynamics AX API – Teil 3 „Buchen von Aufträgen“).

Deswegen sind auch für das Buchen von Bestellungen im Wesentlichen nur zwei Schritte notwendig.

  1. Über die Methode „construct“ der Klasse „PurchFormLetter“ ein dem Buchungstyp einsprechendes Objekt erzeugen.
  2. Über den Aufruf der Methode „update“ die Bestellung buchen.

Hierzu ein Beispiel (Buchen des Lieferscheins für eine Bestellung):

static void PurchPostPackingSlip(Args _args)
{
   PurchFormLetter purchFormLetter;
   PurchTable purchTable;
   PurchId purchId;
   Num packingSlipId;
   ;
   //Angabe der Bestellung, für welche der Lieferschein gebucht werden soll.
   purchId = "00244_049";
   purchTable = PurchTable::find(purchId);

   //Bestimmen des Buchungstyps durch Angabe des DocumentStatus (Lieferschein).
   purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);

   //Festlegen der externen Lieferscheinnummer.
   packingSlipId = "EXT-100155L";

   //Buchen des Lieferscheins.
   purchFormLetter.update(purchTable,
                          packingSlipId,
                          SystemDateGet(),
                          PurchUpdate::All,
                          AccountOrder::Auto,
                          NoYes::No,
                          NoYes::No,
                          NoYes::No,
                          NoYes::No);
}

Einziger Unterschied zu den Auftragsbuchen ist, dass bei der Buchung einer Bestellung die „externe“ Nummer des Belegs (Lieferscheinnummer, Rechnungsnummer, etc.) angegeben werden muss.

Analog zu den Auftragsbuchen, sind auch beim Buchen von Bestellungen umfangreichere oder etwas speziellere Buchungsszenarien möglich (Vergleiche hierzu: Microsoft Dynamics AX API – Teil 3 „Buchen von Aufträgen“).

Saturday, January 26, 2008 3:12:18 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Thursday, October 25, 2007

Das Buchen von Aufträgen in Microsoft Dynamics AX geschieht über die Klasse „SalesFormLetter“ bzw. einer ihrer konkretisierten (abgeleiteten) Klassen. Jeder Buchungstyp (z.B. Bestätigung, Lieferschein, Rechnung) ist durch eine eigene Klasse abgebildet, welche von der Basisklasse „SalesFormLetter“ abgeleitet ist (siehe Abbildung).

Um einen Auftrag per Programmcode zu buchen, muss ein Objekt der Klasse „SalesFormLetter“ erstellt werden.

salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);

Dies geschieht, wie Allgemein in Microsoft Dynamics AX üblich, über die “construct” Methode der Klasse. Als Parameter muss dieser Methode die gewünschte Art der Buchung (z.B. Bestätigung, Lieferschein, Rechnung) angegeben werden. Die „construct“ Methode erzeugt ein,der Buchungsart entsprechendes, Objekt und gibt dieses zurück (In diesem Fall wird ein „SalesFormLetter_Confirm“ Objekt erzeugt).
Die eigentliche Buchung wird über die Methode „update“ aufgerufen. Da dieser Methode alle für die Buchung notwendigen Daten als Parameter übergeben werden können, ist eine einzelne Zuweisung von z.B. dem Auftrag, welcher gebucht werden soll, nicht notwendig.

Hierzu ein Beispiel:

// --- Buchen ohne Ausdruck ---
static void PostingConfimation(Args _args)
{
   SalesFormLetter salesFormLetter;
   SalesTable salesTable;
   SalesId salesId;
   PrintJobSettings printJobSettings;
   ;
   //Angabe des Auftrags, welcher gebucht werden soll.
   salesId = "00423_036";
   salesTable = SalesTable::find(salesId);

   // Bestimmen des Buchungstyps durch Angabe des DocumentStatus
   salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);

   //Buchen des Auftrags (aber nicht Drucken).
   salesFormLetter.update(salesTable,
                          SystemDateGet(),
                          SalesUpdate::All,
                          AccountOrder::None,
                          NoYes::No,
                          NoYes::No);
}

Bei diesem Beispiel ist gut zu sehen, dass für die Buchung eines Auftrags im Wesentlichen nur zwei Schritte notwendig sind.

  1. Über die Methode „construct“ ein dem Buchungstyp einsprechendes Objekt erzeugen.

  2. Über den Aufruf der Methode „update“ den Auftrag buchen.

Natürlich können auch noch umfangreichere oder etwas speziellere Buchungsszenarien mit der Klasse „salesFormLetter“ abgebildet werden. So ist es z.B. möglich, gleich bei der Buchung entsprechende Dokumente auszudrucken (einmal, mehrfach und in verschiedene Formate), die Maske für die Buchung zu öffnen (damit der Benutzer Einfluss auf die Buchung nehmen kann) oder die Buchung nicht direkt auszuführen, sondern diese für die Stapelverarbeitung bereit zu stellen.

Damit es nicht zu komplex wird, kurz noch ein Beispiel zum Buchung und gleichzeitigen ausdrucken entsprechender Dokumente.

// --- Buchen mit Ausdruck ---
static void PostingConfimation(Args _args)
{
   SalesFormLetter salesFormLetter;
   SalesTable salesTable;
   SalesId salesId;
   PrintJobSettings printJobSettings;
   ;
   //Angabe des Auftrags, welcher gebucht werden soll.
   salesId = "00423_036";
   salesTable = SalesTable::find(salesId);
   salesFormLetter = SalesFormLetter::construct(DocumentStatus::Confirmation);

   //Buchen des Auftrags und drucken (Druckmedium aus Std. Einstellung).
   salesFormLetter.update(salesTable,
                          SystemDateGet(),
                          SalesUpdate::All,
                          AccountOrder::None,
                          NoYes::No,
                          NoYes::Yes);

   //2ter Ausdruck.
   printJobSettings = new PrintJobSettings(salesFormLetter.printerSettingsFormletter(
                                                           PrintSetupOriginalCopy::Original));
   //Wohin möchten wir drucken (hier Datei).
   printJobSettings.setTarget(PrintMedium::File);

   //In welches Format soll gedruckt werden (hier PDF).
   printJobSettings.format(PrintFormat::PDF);
   printJobSettings.fileName(@"C:\Test_Order.pdf");

   //Übergabe der Druckoptionen an das SalesFormLetter Objekt.
   salesFormLetter.updatePrinterSettingsFormLetter(printJobSettings.packPrintJobSettings());

   salesFormLetter.printJournal();
}

Thursday, October 25, 2007 6:45:14 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Monday, September 03, 2007

Eine Bestellung umfasst in Microsoft Dynamics AX immer einen Datensatz der Tabelle „PurchTable“ und wenn die Bestellung einen Artikel enthält, auch einen Datensatz in der Tabelle „PurchLine“. Zusätzlich werden in Abhängigkeit von den Daten der Bestellung (Einmallieferant: Ja/Nein, Intercompany: Ja/Nein, etc.) zusätzliche Datensätze in anderen Tabellen erzeugt bzw. geändert. Beispielhaft sei hier die Tabelle „VendTable“ genannt. In dieser wird ein neuer Lieferant erstellt, wenn beim Erstellen der Bestellung angegeben wurde, dass es sich um einen Einmallieferanten handelt. Ein weiteres Beispiel wäre die Tabelle „MarkupTrans“ in der in Abhängigkeit von den Einstellungen für sonstige Zuschläge ebenfalls weitere Datensätze erzeugt werden.

Die Logik, die das Erstellen der einzelnen Datensätze der verschiedenen Tabellen steuert wird in Microsoft Dynamics AX durch die Klassen „PurchTableType“ (Abbildung 1) und „PurchLineType“ (Abbildung 2), sowie deren abgeleiteten Klassen abgebildet. Diese Klassen steuern das Verhalten bei Anlage, Änderung und Löschung einer Bestellung. Dies beinhaltet auch, welche Werte ein Feld bei welchem Bestellungstyp annehmen darf, was geschieht wenn ein Feld geändert wird, was wird wie gebucht und so weiter.

Diese Klassen werden von überschriebenen Methoden der Tabellen „PurchTable“ und „PurchLine“ aufgerufen. So ruft zum Beispiel die Methode „Insert“ der Tabelle „PurchTable“, die Methode „Insert“ der Klasse „PurchTableType“ auf. Abhängig vom Bestellungstyp wird über die Methode „construct“ bei der Initialisierung eines „PurchTableType“ Objekts gesteuert, welches konkrete Objekt erzeugt wird („PurchTableType_Purch“, „PurchTableType_ReturnItem“, etc.). Dies erfolgt in der Methode „type“ der Tabelle „PurchTable“ oder „PurchLine“. Unter anderem sind weiterhin die Methoden „Update“, „Delete“, „InitValue“, „ValidateField“ und „Delete“ auf die gleiche Weise überschrieben.
Ein Blick in die Methoden der Tabelle „PurchTable“ sollte dies verdeutlichen.

Somit ist die Logik, die für die Steuerung von Bestellungen in Microsoft Dynamics AX verantwortlich ist, vom Prinzip her vergleichbar mit der Logik welche die Aufträge „steuert“ (vergleiche hierzu: Microsoft Dynamics AX API – Teil 1 „Erstellen von Aufträgen“).

Deswegen ist das Erstellen einer Bestellung genau so einfach wie das Erstellen eines Auftrags. Um eine neue Bestellung zu erstellen muss im Wesentlichen nur:

  1. Eine neue Nummer des entsprechenden Nummernkreises gezogen werden.
  2. Die Methode „InitValue“ der Tabelle „PurchTable“ aufgerufen werden.
  3. Die Methode „InitFromVendTable“ der Tabelle „PurchTable“ mit Angabe des Lieferanten Datensatzes aufgerufen werden.
  4. Die Methode „Insert“ der Tabelle  „PurchTable“ aufgerufen werden.

Soll für diese gerade erzeugte Bestellung nun noch eine Artikelposition erzeugt werden, muss im Wesentlichen nur die Methode „CreateLine“ der Tabelle „PurchLine“, mit vorheriger Definition von Bestellungsnummer („PurchLine.PurchId“) und Artikelnummer („PurchLine.ItemId“), aufgerufen werden.

Hierzu ein Beispiel:

void createPurchTableAndLine()
{
   VendAccount vendAccount = "<yourVendAccount>";
   ItemId itemId = "<yourItemId>";

   PurchTable purchTable;
   PurchLine purchLine;
   NumberSeq numberSeq;
   InventTable inventTable;
   ;
   //Bestellungskopf (PurchTable)
   //Neue Bestellungsnummer aus Nummernkreis erzeugen
   NumberSeq = NumberSeq::newGetNumFromCode(
   PurchParameters::numRefPurchId().numberSequence);
   purchTable.PurchId = NumberSeq.num();

   //Bestellungskopf initialisieren
   purchTable.initValue();

   //Initialisierung der lieferantenspezifischen Bestellungsdaten
   purchTable.initFromVendTable(VendTable::find(vendAccount));

   //Bestellungskopf erstellen
   purchTable.insert();

   //Bestellungsposition (PurchLine)
   purchLine.clear();

   //Zuweisen von Bestellungsnummer und Artikelnummer
   purchLine.purchId = purchTable.PurchId;
   purchLine.ItemId = itemId;

   //Bestellungsposition erstellen (ruft PurchLine.insert auf)
   purchLine.createLine(NoYes::Yes, NoYes::Yes, NoYes::Yes,
                        NoYes::Yes, NoYes::Yes, NoYes::Yes);
}

Monday, September 03, 2007 8:02:32 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 

 Friday, August 17, 2007

Ein Auftrag umfasst in Microsoft Dynamics AX immer einen Datensatz in der Tabelle „SalesTable“ (Auftragskopf) und wenn der Auftrag einen Artikel enthält (Auftragsposition), auch einen Datensatz in der Tabelle „SalesLine“. Zusätzlich werden in Abhängigkeit von den Daten des Auftrags (Einmalkunde: Ja/Nein, Intercompany: Ja/Nein, etc.) zusätzliche Datensätze in anderen Tabellen erzeugt bzw. geändert. Beispielhaft sei hier die Tabelle „CustTable“ genannt. In dieser wird ein neuer Kunde erstellt, wenn beim Erstellen des Auftrags angegeben wurde, dass es sich um einen Einmalkunden handelt. Ein weiteres Beispiel wäre die Tabelle „MarkupTrans“ in der in Abhängigkeit von den Einstellungen für Sonstige Zuschläge ebenfalls weitere Datensätze erzeugt werden.

Die Logik, die das Erstellen der einzelnen Datensätze der verschiedenen Tabellen steuert (die so genannte Geschäftslogik) wird in Microsoft Dynamics AX durch die Klassen „SalesTableType“ (Abbildung 1) und „SalesLineType“ (Abbildung 2), sowie deren abgeleiteten Klassen abgebildet. Diese Klassen steuern das Verhalten bei Anlage, Änderung und Löschung eines Auftrags. Dies beinhaltet auch, welche Werte ein Feld bei welchem Auftragstyp annehmen darf, was geschieht wenn ein Feld geändert wird, was wird wie gebucht und so weiter.

Diese Klassen werden von überschriebenen Methoden der Tabellen „SalesTable“ und „SalesLine“ aufgerufen. So ruft zum Beispiel die Methode „Insert“ der Tabelle „SalesTable“, die Methode „Insert“ der Klasse „SalesTableType“ auf. Abhängig vom Auftragstyp wird über die Methode „construct“ bei der Initialisierung eines „SalesTableType“ Objekts gesteuert, welches konkrete Objekt erzeugt wird („SalesTableType_Sales“, „SalesTableType_ItemReq“, etc.).
Unter anderem sind weiterhin die Methoden „Update“, „Delete“, „InitValue“, „ValidateField“ und „Delete“ auf die gleiche Weise überschrieben. Ein Blick in die Methoden der Tabelle „SalesTable“ oder „SalesLine“ sollte dies verdeutlichen.

Somit gestaltet sich das Erstellen eines neuen Auftrags sehr einfach, da die gesamte Geschäftslogik die hinter einem Auftrag steht, automatisch aufgerufen wird.

Um einen neuen Auftrag zu erstellen muss im Wesentlichen nur

  1. Eine neue Nummer des entsprechenden Nummernkreises gezogen werden.
  2. Die Methode „InitValue“ der Tabelle „SalesTable“ aufgerufen werden.
  3. Die Kundennummer zugewiesen werden.
  4. Die Methode „InitFromCustAccount“ der Tabelle „SalesTable“ aufgerufen werden.
  5. Die Methode „Insert“ der Tabelle  „SalesTable“ aufgerufen werden.

Soll für diesem gerade erzeugten Auftrag nun noch eine Artikelposition erzeugt werden, muss im Wesentlichen nur die Methode „CreateLine“ der Tabelle „SalesLine“, mit vorheriger Definition von Auftragsnummer („SalesLine.SalesId“) und Artikelnummer („SalesLine.ItemId“), aufgerufen werden.

Hierzu ein Beispiel:

void createSalesTableAndLine()
{
   AccountNum custAccount = <yourCustAccount>;
   ItemId itemId = <yourItemId>;

   SalesTable salesTable;
   SalesLine salesLine;
   NumberSeq NumberSeq;
   ;
   //Auftragskopf (SalesTable)
   //Neue Auftragsnummer aus Nummernkreis erzeugen
   NumberSeq = NumberSeq::newGetNumFromCode(
   SalesParameters::numRefSalesId().numberSequence);
   salesTable.SalesId = NumberSeq.num();

   //Auftragskopf initialisieren
   salesTable.initValue();
   salesTable.CustAccount = custAccount;

   //Initialisierung der kundenspezifischen Auftragsdaten
   salesTable.initFromCustTable();

   //Auftragskopf erstellen
   salesTable.insert();

   //Auftragsposition (SalesLine)
   salesLine.clear();

   //Zuweisen von Auftragsnummer und Artikelnummer
   salesLine.SalesId = salesTable.SalesId;
   salesLine.ItemId = itemId;

   //Auftragsposition erstellen (ruft SalesLine.insert auf)
   salesLine.createLine(NoYes::Yes, NoYes::Yes, NoYes::Yes, NoYes::Yes,
                        NoYes::Yes, NoYes::Yes);
}

Friday, August 17, 2007 3:47:28 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 | 



Translate
Über/Kontakt

     







© Copyright 2010 Axel Kühn
Sign In
Subscribe this blog
Blogroll
 Arijit Basu
 Axapta Blog
Blog around Microsoft Business Solutions Axapta by Helmut Wimmer
 BlaBlubBlog
Der Blog von Kai Gloth
 Dave Bowles
 Dick Wenning
Ax(apta) start pages
 Fred Shen
 Harish Mohanbabu
 jinx´s AX Blog
Everything about Microsoft Dynamcis AX
 Lars Keller
All about .NET, VSTS, VSTO and more
 Max Belugin
 TaReMoTi Blog
Der Blog von Karsten Döring
Archiv
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
Statistik
Total Posts: 131
This Year: 13
This Month: 0
This Week: 0
Comments: 46





All Content © 2010, Axel Kühn
DasBlog theme 'Business' created by Christoph De Baene (delarou)