Wie bereits in unserem vorherigen Artikel über die automatische Berechnung von Mehrwertsteuern angekündigt, werde ich an dieser Stelle die technische Umsetzung der dort aufgezeigten beschriebenen Lösung beleuchten.
Mögliche Ansätze
Bei der Berechnung der Mehrwertsteuer gibt es aus technischer Sicht in CRM zwei Ansätze einer Implementierung: Als Javascript oder in Form eines Plugin’s. Bei dieser Gegenüberstellung haben sich folgende Nachteile bei der Umsetzung als Javascript herauskristallisiert:
Setzt man die Funktionalität in einem CRM Plugin als Post-Operation um, fallen all diese Nachteile weg. Aus diesem Grund haben wir uns für diesen Weg entschieden.
Plugin Funktionalität
Wie oben bereits erwähnt wurde das Plugin als Post-Operation umgesetzt. Zu diesem Zeitpunkt ist der Datensatz bereits mit den berechneten Preiswerten in der Datenbank abgespeichert und diese Daten können somit für die Berechnung der Mehrwertsteuer herangezogen werden. Anzumerken ist hier jedoch, daß nicht ein Pre- oder Post-Image genutzt werden kann, sondern die Daten über die Webservices abgefragt werden müssen, da die Images noch die alten Daten beinhalten. Das Plugin ist für die Update-Nachricht registriert. Diese wird durch die interne CRM-Preisberechnung auch bei dem Erzeugen eines Verkaufschancenprodukts, Auftragsprodukts etc. aufgerufen.
Der Ablauf des Plugins sieht somit folgendermaßen aus:
Der Code ist an den meisten Stellen trivial, da er primär aus Webservice-Anfragen zum Abfragen von Daten besteht. Ich habe hier allerdings mit Late Bound Klassen gearbeitet, um auf einfache Weise die gleiche Funktionalität für Verkaufschancenprodukte, Auftragsprodukte etc. arbeiten zu können. Da die wichtigen Felder wie Betrag, Steuer oder Rabatt auf diesen Entitäten überall gleich benannt sind, ist dies sehr einfach und verhindert redundanten Programmcode. So können beispielsweise die Daten für jede der vier Entitäten durch folgenden Aufruf abgefragt werden:
//Get current Values of entity ColumnSet currentValueColumns = new ColumnSet(PRODUCTID_FIELD_NAME, BASEAMOUNT_FIELD_NAME, MANUALDISCOUNTAMOUNT_FIELD_NAME, NOTAX_FIELD_NAME, VATCONFIGID_FIELD_NAME, parentEntityFieldName); Entity currentValue = localContext.OrganizationService.Retrieve(localContext.PluginExecutionContext.PrimaryEntityName, localContext.PluginExecutionContext.PrimaryEntityId, currentValueColumns); if (currentValue == null) { return; }
Alles weitere ist das Anwenden der im vorherigen Artikel beschriebenen Formeln und Bedingungen.
JavaScript
Neben der zentralen Plugin-Funktionalität wurden auch mehrere, kleinere Hilfsfunktionalitäten in JavaScript implementiert, um den Nutzern ein bequemes Arbeiten zu ermöglichen. Zum einen wird das Lookup-Feld Mehrwertsteuer ausgeblendet, wenn ein vorhandenes Produkt ausgewählt wird. Wählt der Nutzer ein Produkt manuell eingeben aus, wird dieses Lookup-Feld eingeblendet und mit der gültigen Standard-Mehrwertsteuer vorbelegt. Des Weiteren gibt es eine Funktion, welche dem Nutzer einen Hinweis anzeigt, dass der Kunde der Verkaufschance ein ausländischer Kunde ist. Hierdurch wird sichergestellt, dass der Benutzer direkt versteht, warum an dieser Stelle die Mehrwertsteuer nicht berechnet wird. Dieser Hinweis sieht beispielsweise so aus:
Diese Funktionalitäten sind auf drei Javascript Funktionen aufgeteilt. Auf diese Weise muss ein Nutzer der Bibliothek nur die für ihn notwendigen Funktionen einbinden. In meinen Augen ist die Funktionalität des Nutzerhinweises hier am spannensten, weshalb ich hier das Codesnippet zeigen möchte:
/** brief Displays a notifaction if the customer of the parent entity is a foreigner */ function VATPluginSetForeignerNotification() { //Validate data if (typeof XrmServiceToolkit == "undefined" || Xrm.Page.getControl(VATPLUGIN_NO_TAX_FIELD) == null || Xrm.Page.getControl(VATPLUGIN_VAT_CONFIG_ID_FIELD) == null) { return; } //Get parentcustomer Id var parentEntityFieldName = ""; var parentEntity = ""; var entityName = Xrm.Page.data.entity.getEntityName(); switch (entityName) { case "quotedetail": parentEntityFieldName = "quoteid"; parentEntity = "quote"; break; case "opportunityproduct": parentEntityFieldName = "opportunityid"; parentEntity = "opportunity"; break; case "salesorderdetail": parentEntityFieldName = "salesorderid"; parentEntity = "salesorder"; break; case "invoicedetail": parentEntityFieldName = "invoiceid"; parentEntity = "invoice"; break; } //Retrieve entity, parententity and customer var cols = [ VATPLUGIN_CUSTOMERID_FIELD ]; var retrievedParentEntity = XrmServiceToolkit.Soap.Retrieve(parentEntity, Xrm.Page.getAttribute(parentEntityFieldName).getValue(), cols); if (retrievedParentEntity == null || retrievedParentEntity.attributes[VATPLUGIN_CUSTOMERID_FIELD] == null) { return; } cols = [ VATPLUGIN_BOOKINGGROUP_FIELD ]; var retrievedCustomerEntity = XrmServiceToolkit.Soap.Retrieve(retrievedParentEntity.attributes[VATPLUGIN_CUSTOMERID_FIELD].logicalName, retrievedParentEntity.attributes[VATPLUGIN_CUSTOMERID_FIELD].id, cols); if(retrievedCustomerEntity == null || retrievedCustomerEntity.attributes[VATPLUGIN_BOOKINGGROUP_FIELD] == null) { return; } //Check if customer is a foreigner add notification for user that tax will not be calculated if (retrievedCustomerEntity.attributes[VATPLUGIN_BOOKINGGROUP_FIELD].value != VATPLUGIN_BOOKINGGROUP_NATIVE) { var notificationsArea = document.getElementById('crmNotifications'); notificationsArea.AddNotification("VATPlugin_Info_Foreigner", 3, "Mwst.", "Übergeordneter Kunde ist kein Inländer. Steuer wird nicht berechnet."); Xrm.Page.getControl(VATPLUGIN_NO_TAX_FIELD).setDisabled(true); Xrm.Page.getControl(VATPLUGIN_VAT_CONFIG_ID_FIELD).setDisabled(true); } }
Zu Beginn wird hier der Name der Entität, welche dem Produkt übergeordnet ist, ermittelt (Verkaufschance über dem Verkaufschancenprodukt, etc.). Anschließend kann darüber die Verkaufschance abgefragt werden und hierrüber der Kunde. Wie in der Lösungsbeschreibung gezeigt ist dieses am Kunden abgelegt, ob es sich um einen inländischen Kunden handelt oder nicht. Ist der Kunde kein Inländer wird nun die „notificationArea“ abgefragt. Dieses Element mit der Id „crmNotifications“ ist ein besonderes HTML-Objekt, an dem die Benachrichtigungen an den Usern hängen. Über die Funktion AddNotification kann man nun eine neue Benachrichtigung hinzufügen. Die 3 ist dabei der Schweregrad der Benachrichtigung. in diesem Fall wird eine Info angezeigt. Eine Zwei ist hier gleichbedeutend mit einer Warnung. Eine Eins zeigt einen kritischen Fehler an. Anschließend werden hier noch die die Steuerelemente, welche mit der Mehrwertsteuer zu tun haben deaktiviert.
Mapping der neuen Felder
Ein weiterer Punkt, der bedacht werden muss, ist die Vererbung, der neu hinzugefügten Felder von Verkaufschancenprodukten zu Angebotsprodukten etc. Hierfür kann das CRM-interne Mapping genutzt werden. Dieses muss lediglich um die neuen Felder erweitert werden. Wie man diese Erweiterung durchführt ist in folgendem englischem Blogartikel schön beschrieben: Mapping MSCRM fields from Opportunity Product to Quote Product
Fazit
Durch diese gut konfigurierbare Lösung kann man auf einfache Weise CRM um die Funktionalität, automatisiert die Mehrwertsteuer zu berechnen, erweitern.
Die hier vorgestellte Lösung haben wir ebenfalls auf Codeplex hochgeladen.
Kategorien: Dynamics CRM, Erklärt, Technical
Schlagwörter: Dynamics CRM, HowTo, Mehrwertsteuer, MwSt
Haben Sie Fragen zu diesem Artikel oder brauchen Sie Unterstützung?
Nehmen Sie mit uns Kontakt auf!
Wir unterstützen Sie gerne bei Ihren Vorhaben!