Vero-integroinnin tietokenttien lisääminen laajennuksen avulla
Tässä artikkelissa kerrotaan, kuinka X++ -laajennuksia käytetään tietokenttien lisäämiseen verointegrointiin. Nämä kentät voidaan laajentaa veropalvelun verotietomalliin, ja niitä voidaan käyttää verokoodien määrittämiseen. Lisätietoja on kohdassa Tietokenttien lisääminen verokonfiguraatioihin.
Tietomalli
Tietomallin tietoja säilyttävät objektit ja luokat toteuttavat ne.
Seuraavassa on luettelo tärkeimmistä objekteista:
- AxClass/TaxIntegrationDocumentObject
- AxClass/TaxIntegrationLineObject
- AxClass/TaxIntegrationTaxLineObject
Seuraavassa kuvassa kerrotaan, miten nämä objektit liittyvät toisiinsa.
]
Document-objekti voi sisältää useita Line-objekteja. Kukin objekti sisältää veropalvelun metatietoja.
-
TaxIntegrationDocumentObject
-kohteessa onoriginAddress
-metatieto, jotka sisältävät tietoja lähde-osoitteesta jaincludingTax
-metatieto, joka ilmaisee, sisältääkö rivisumma arvonlisäveron. -
TaxIntegrationLineObject
-kohteella onitemId
-,quantity
- jacategoryId
-metatiedot.
Muistiinpano
TaxIntegrationLineObject
toteuttaa myös Charge-objektit.
Integroinnin työnkulku
Toiminnot manipuloivat työnkulun tietoja.
Tärkeimmät toiminnot
- AxClass/TaxIntegrationCalculationActivityOnDocument
- AxClass/TaxIntegrationCurrencyExchangeActivityOnDocument
- AxClass/TaxIntegrationDataPersistenceActivityOnDocument
- AxClass/TaxIntegrationDataRetrievalActivityOnDocument
- AxClass/TaxIntegrationSettingRetrievalActivityOnDocument
Tehtävät suoritetaan seuraavassa järjestyksessä:
- Noutamisen määrittäminen
- Tietojen noutaminen
- Laskentapalvelu
- Valuutan vaihto
- Tietojen säilyvyys
Esimerkiksi laajenna Tietojen nouto ennen kuin Laskentapalvelu.
Tietojen noutamisen tehtävät
Tietojen noutamisen tehtävät noutavat tietoja tietokannasta. Eri tapahtumien sovittimet ovat käytettävissä tietojen hakemiseen eri tapahtumatauluista:
- AxClass/TaxIntegrationPurchTableDataRetrieval
- AxClass/TaxIntegrationPurchParmTableDataRetrieval
- AxClass/TaxIntegrationPurchREQTableDataRetrieval
- AxClass/TaxIntegrationPurchRFQTableDataRetrieval
- AxClass/TaxIntegrationVendInvoiceInfoTableDataRetrieval
- AxClass/TaxIntegrationSalesTableDataRetrieval
- AxClass/TaxIntegrationSalesParmDataRetrieval
Näissä tietojen noutamisen tehtävissä tiedot kopioidaan tietokannasta TaxIntegrationDocumentObject
- ja TaxIntegrationLineObject
-kohteeseen. Koska kaikki nämä tehtävät laajentavat saman abstraktin malliluokan, niillä on yhteisiä metodeita.
Laskentapalvelun tehtävät
Laskentapalvelun tehtävä on veropalvelun ja verointegraaton välinen linkki. Tämä tehtävä on vastuussa seuraavista toiminnoista:
- Muodosta pyyntö.
- Lähetä pyyntö veropalveluun.
- Hae vastaus veropalvelusta.
- Jäsennä vastaus.
Pyyntöön lisättävä tietokenttä lähetetään yhdessä muiden metatietojen kanssa.
Laajennuksen toteutus
Tässä osassa on yksityiskohtaisia ohjeita laajennuksen toteuttamisesta. Esimerkkejä ovat taloushallinnon dimensiot Kustannuspaikka ja Projekti.
Vaihe 1. Tietomuuttujan lisääminen objektiluokkaan
Objektiluokka sisältää tietomuuttujan sekä tietojen getter-/setter-metodit. Lisää tietokenttä joko TaxIntegrationDocumentObject
- tai TaxIntegrationLineObject
-objektiin kentän tason mukaan. Seuraavassa esimerkissä käytetään rivitasoa, ja tiedoston nimi on TaxIntegrationLineObject_Extension.xpp
.
Muistiinpano
Jos lisätty tietokenttä on tiedostotasolla, muuta tiedoston nimeksi TaxIntegrationDocumentObject_Extension.xpp
.
[ExtensionOf(classStr(TaxIntegrationLineObject))]
final class TaxIntegrationLineObject_Extension
{
private OMOperatingUnitNumber costCenter;
private ProjId projectId;
/// <summary>
/// Gets a costCenter.
/// </summary>
/// <returns>The cost center.</returns>
public final OMOperatingUnitNumber getCostCenter()
{
return this.costCenter;
}
/// <summary>
/// Sets the cost center.
/// </summary>
/// <param name = "_value">The cost center.</param>
public final void setCostCenter(OMOperatingUnitNumber _value)
{
this.costCenter = _value;
}
/// <summary>
/// Gets a project ID.
/// </summary>
/// <returns>The project ID.</returns>
public final ProjId getProjectId()
{
return this.projectId;
}
/// <summary>
/// Sets the project ID.
/// </summary>
/// <param name = "_value">The project ID.</param>
public final void setProjectId(ProjId _value)
{
this.projectId = _value;
}
}
Kustannuspaikka ja Projekti lisätään yksityisinä muuttujina. Voit käsitellä tietoja luomalla getter- ja setter-metodit näille tietokentille.
Vaihe 2. Tietojen noutaminen tietokannasta
Määritä tapahtuma ja nouda tiedot laajentamalla asianmukaiset sovitinluokat. Jos käytät esimerkiksi Ostotilaus-tapahtumaa, on laajennettava TaxIntegrationPurchTableDataRetrieval
- ja TaxIntegrationVendInvoiceInfoTableDataRetrieval
-luokkia.
Muistiinpano
TaxIntegrationPurchParmTableDataRetrieval
on peritty TaxIntegrationPurchTableDataRetrieval
-luokasta. Sitä ei saa muuttaa, ellei purchTable
- ja purchParmTable
-taulujen logiikka ole erilainen.
Jos tietokenttä on lisättävä kaikille tapahtumille, laajenna kaikki DataRetrieval
-luokat.
Koska Tietojen nouto -tehtävät laajentavat samaa malliluokkaa, luokkarakenteet, muuttujat ja metodit ovat samankaltaisia.
protected TaxIntegrationDocumentObject document;
/// <summary>
/// Copies to the document.
/// </summary>
protected abstract void copyToDocument()
{
// It is recommended to implement as:
//
// this.copyToDocumentByDefault();
// this.copyToDocumentFromHeaderTable();
// this.copyAddressToDocument();
}
/// <summary>
/// Copies to the current line of the document.
/// </summary>
/// <param name = "_line">The current line of the document.</param>
protected abstract void copyToLine(TaxIntegrationLineObject _line)
{
// It is recommended to implement as:
//
// this.copyToLineByDefault(_line);
// this.copyToLineFromLineTable(_line);
// this.copyQuantityAndTransactionAmountToLine(_line);
// this.copyAddressToLine(_line);
// this.copyToLineFromHeaderTable(_line);
}
Seuraavassa esimerkissä esitetään perusrakenne, kun PurchTable
-taulua käytetään.
public class TaxIntegrationPurchTableDataRetrieval extends TaxIntegrationAbstractDataRetrievalTemplate
{
protected PurchTable purchTable;
protected PurchLine purchLine;
// Query builder methods
[Replaceable]
protected SysDaQueryObject getDocumentQueryObject()
[Replaceable]
protected SysDaQueryObject getLineQueryObject()
[Replaceable]
protected SysDaQueryObject getDocumentChargeQueryObject()
[Replaceable]
protected SysDaQueryObject getLineChargeQueryObject()
// Data retrieval methods
protected void copyToDocument()
protected void copyToDocumentFromHeaderTable()
protected void copyToLine(TaxIntegrationLineObject _line)
protected void copyToLineFromLineTable(TaxIntegrationLineObject _line)
...
}
Kun CopyToDocument
-metodia kutsutaan, this.purchTable
-puskuri on jo olemassa. Tämän metodin avulla voit kopioida kaikki tarvittavat tiedot this.purchTable
-kohteesta document
-objektiin käyttämällä DocumentObject
-luokassa luotua setter-metodia.
Samoin this.purchLine
-puskuri on jo olemassa CopyToLine
-metodissa. Tämän metodin avulla voit kopioida kaikki tarvittavat tiedot this.purchLine
-kohteesta _line
-objektiin käyttämällä LineObject
-luokassa luotua setter-metodia.
Kaikkein suoraviivaisin tapa on laajentaa CopyToDocument
- ja CopyToLine
-metodeja. On kuitenkin suositeltavaa kokeilla ensin copyToDocumentFromHeaderTable
- ja copyToLineFromLineTable
-metodeja. Jos ne eivät toimi niin kuin on tarpeen, toteuta oma metodi ja kutsu sitä CopyToDocument
- ja CopyToLine
-metodeissa. Tätä lähestymistapaa voidaan käyttää kolmessa yleisessä tilanteessa:
Pakollinen kenttä on kohteessa
PurchTable
taiPurchLine
. Tässä tapauksessa voit laajentaa kohteitacopyToDocumentFromHeaderTable
jacopyToLineFromLineTable
. Tässä on esimerkkikoodi./// <summary> /// Copies to the current line of the document from. /// </summary> /// <param name = "_line">The current line of the document.</param> protected void copyToLineFromLineTable(TaxIntegrationLineObject _line) { next copyToLineFromLineTable(_line); // if we already added XXX in TaxIntegrationLineObject _line.setXXX(this.purchLine.XXX); }
Vaadittavat tiedot eivät ole tapahtuman oletustaulussa. Oletustauluun liittyy kuitenkin joitakin liitossuhteita, ja useimmilla riveillä kenttä on pakollinen. Tässä tapauksessa voit korvata
getDocumentQueryObject
- taigetLineObject
-metodin kyselläksesi taulusta liitossuhteen avulla. Seuraavassa esimerkissä Toimita nyt -kenttä integroidaan rivitasolla myyntitilauksen kanssa.public class TaxIntegrationSalesTableDataRetrieval { protected MCRSalesLineDropShipment mcrSalesLineDropShipment; /// <summary> /// Gets the query for the lines of the document. /// </summary> /// <returns>The query for the lines of the document</returns> [Replaceable] protected SysDaQueryObject getLineQueryObject() { return SysDaQueryObjectBuilder::from(this.salesLine) .where(this.salesLine, fieldStr(SalesLine, SalesId)).isEqualToLiteral(this.salesTable.SalesId) .outerJoin(this.mcrSalesLineDropShipment) .where(this.mcrSalesLineDropShipment, fieldStr(MCRSalesLineDropShipment, SalesLine)).isEqualTo(this.salesLine, fieldStr(SalesLine, RecId)) .toSysDaQueryObject(); } }
Tässä esimerkissä
mcrSalesLineDropShipment
-puskurit määritetään ja kysely määritetään kohdassagetLineQueryObject
. Kysely käyttää suhdettaMCRSalesLineDropShipment.SalesLine == SalesLine.RecId
. Kun olet laajentamassa tässä tilanteessa, voit korvatagetLineQueryObject
-kohteen omalla luodulla kyselyobjektilla. Ota kuitenkin seuraavat seikat huomioon:- Koska
getLineQueryObject
-metodin palautusarvo onSysDaQueryObject
, sinun on muodostettava tämä objekti SysDa-lähestymistavan avulla. - Aiemmin luotua taulua ei voi poistaa.
- Koska
Vaadittavat tiedot liittyvät tapahtumatauluun monimutkaisella liitossuhteella, tai suhde ei ole yksi yhteen (1:1) vaan yksi moneen (1:N). Tässä tapauksessa tilanne on hieman monimutkaisempi. Tämä tilanne koskee taloushallinnon dimensioiden esimerkkiä.
Tässä tapauksessa voit toteuttaa oman metodin tietojen hakemiseksi. Tässä on esimerkkikoodi
TaxIntegrationPurchTableDataRetrieval_Extension.xpp
-tiedostossa.[ExtensionOf(classStr(TaxIntegrationPurchTableDataRetrieval))] final class TaxIntegrationPurchTableDataRetrieval_Extension { private const str CostCenterKey = 'CostCenter'; private const str ProjectKey = 'Project'; /// <summary> /// Copies to the current line of the document from. /// </summary> /// <param name = "_line">The current line of the document.</param> protected void copyToLineFromLineTable(TaxIntegrationLineObject _line) { Map dimensionAttributeMap = this.getDimensionAttributeMapByDefaultDimension(this.purchline.DefaultDimension); if (dimensionAttributeMap.exists(CostCenterKey)) { _line.setCostCenter(dimensionAttributeMap.lookup(CostCenterKey)); } if (dimensionAttributeMap.exists(ProjectKey)) { _line.setProjectId(dimensionAttributeMap.lookup(ProjectKey)); } next copyToLineFromLineTable(_line); } private Map getDimensionAttributeMapByDefaultDimension(RefRecId _defaultDimension) { DimensionAttribute dimensionAttribute; DimensionAttributeValue dimensionAttributeValue; DimensionAttributeValueSetItem dimensionAttributeValueSetItem; Map ret = new Map(Types::String, Types::String); select Name, RecId from dimensionAttribute join dimensionAttributeValue where dimensionAttributeValue.dimensionAttribute == dimensionAttribute.RecId join DimensionAttributeValueSetItem where DimensionAttributeValueSetItem.DimensionAttributeValue == DimensionAttributeValue.RecId && DimensionAttributeValueSetItem.DimensionAttributeValueSet == _defaultDimension; while(dimensionAttribute.RecId) { ret.insert(dimensionAttribute.Name, dimensionAttributeValue.DisplayValue); next dimensionAttribute; } return ret; } }
Vaihe 3. Tietojen lisääminen pyyntöön
Laajenna copyToTaxableDocumentHeaderWrapperFromTaxIntegrationDocumentObject
- tai copyToTaxableDocumentLineWrapperFromTaxIntegrationLineObjectByLine
-metodi lisätäksesi tiedot pyyntöön. Tässä on esimerkkikoodi TaxIntegrationCalculationActivityOnDocument_CalculationService_Extension.xpp
-tiedostossa.
[ExtensionOf(classStr(TaxIntegrationCalculationActivityOnDocument_CalculationService))]
final static class TaxIntegrationCalculationActivityOnDocument_CalculationService_Extension
{
// Define the field name in the request
private const str IOCostCenter = 'Cost Center';
private const str IOProject = 'Project';
// private const str IOEnumExample = 'Enum Example';
/// <summary>
/// Copies to <c>TaxableDocumentLineWrapper</c> from <c>TaxIntegrationLineObject</c> by line.
/// </summary>
/// <param name = "_destination"><c>TaxableDocumentLineWrapper</c>.</param>
/// <param name = "_source"><c>TaxIntegrationLineObject</c>.</param>
protected static void copyToTaxableDocumentLineWrapperFromTaxIntegrationLineObjectByLine(Microsoft.Dynamics.TaxCalculation.ApiContracts.TaxableDocumentLineWrapper _destination, TaxIntegrationLineObject _source)
{
next copyToTaxableDocumentLineWrapperFromTaxIntegrationLineObjectByLine(_destination, _source);
// Set the field we need to integrated for tax service
_destination.SetField(IOCostCenter, _source.getCostCenter());
_destination.SetField(IOProject, _source.getProjectId());
// If the field to be extended is an enum type, use enum2Symbol to convert an enum variable exampleEnum of ExampleEnumType to a string
// _destination.SetField(IOEnumExample, enum2Symbol(enumNum(ExampleEnumType), _source.getExampleEnum()));
}
}
Tässä koodissa _destination
on paketointiobjekti, jota käytetään pyynnön luonnissa ja _source
on TaxIntegrationLineObject
-objekti.
Muistiinpano
Määritä kentän nimi, jota käytetään pyynnössä nimellä private const str. Merkkijonon on oltava täsmälleen sama kuin solmun nimi (ei selite), joka lisättiin artikkelissa Tietokenttien lisääminen veromäärityksiin.
Määritä kenttä menetelmässä copyToTaxableDocumentLineWrapperFromTaxIntegrationLineObjectByLine käyttämällä SetField-menetelmää. Toisen parametrin tietotyypin on oltava merkkijono. Jos tietotyyppi ei ole merkkijono, muunna se merkkijonoksi. Jos tietotyyppi on X++ -kielen luettelointityyppi, suosittelemme luettelointiarvon muuntamiseen merkkijonoksi enum2Symbol-menetelmää. Veromäärityksessä lisätyn luettelointiarvon on täsmättävä täysin luetteloinnin nimen kanssa. Seuraavassa on luettelo luettelointiarvon, selitteen ja nimen eroista.
- Luetteloinnin nimi on symbolinen nimi koodissa. Menetelmä enum2Symbol() voi muuntaa luetteloinnin sen nimeksi.
- Luetteloinnin arvo on kokonaisluku.
- Luetteloinnin tunniste voi vaihdella ensisijaisten kielten välillä. Menetelmä enum2Str() voi muuntaa luetteloinnin sen selitteeksi.
Malliriippuvuus
Kokoa projekti onnistuneesti lisäämällä malliriippuvuuksiin seuraavat viitemallit:
- ApplicationPlatform
- ApplicationSuite
- Veromoduuli
- Dimensiot, jos taloushallinnon dimensioita käytetään
- Muut tarpeelliset mallit, joihin viitataan koodissa
Oikeellisuustarkistus
Kun olet suorittanut edelliset vaiheet, voit vahvistaa muutoksesi.
- Siirry Financessa kohtaan Ostoreskontra ja lisää URL-osoitteeseen &debug=vs%2CconfirmExit&. Esimerkiksi
https://usnconeboxax1aos.cloud.onebox.dynamics.com/?cmp=DEMF&mi=PurchTableListPage&debug=vs%2CconfirmExit&
. Lopussa on oltava &. - Voit luoda ostotilauksen avaamalla sivun Ostotilaus ja valitsemalla Uusi.
- Määritä mukautetun kentän arvo ja valitse sitten Arvonlisävero. Vianmääritystiedosto etuliitteellä TaxServiceTroubleshootingLog latautuu automaattisesti. Tämä tiedosto sisältää veronlaskentapalveluun kirjatut tiedot.
- Tarkista, että lisätty mukautettu kenttä näkyy Veropalvelun laskennan syöte-JSON -osassa ja että sen arvo on oikein. Jos arvo ei ole oikein, käy tämän asiakirjan vaiheet läpi uudelleen.
Tiedostoesimerkki:
===Tax service calculation input JSON:===
{
"TaxableDocument": {
"Header": [
{
"Lines": [
{
"Line Type": "Normal",
"Item Code": "",
"Item Type": "Item",
"Quantity": 0.0,
"Amount": 1000.0,
"Currency": "EUR",
"Transaction Date": "2022-1-26T00:00:00",
...
/// The new fields added at line level
"Cost Center": "003",
"Project": "Proj-123"
}
],
"Amount include tax": true,
"Business Process": "Journal",
"Currency": "",
"Vendor Account": "DE-001",
"Vendor Invoice Account": "DE-001",
...
// The new fields added at header level, no new fields in this example
...
}
]
},
}
...
Liite
Tästä liitteestä ilmenee taloushallinnon dimensioiden (Kustannuspaikka ja Projekti) integroinnin koko esimerkkikoodi rivitasolla.
TaxIntegrationLineObject_Extension.xpp
[ExtensionOf(classStr(TaxIntegrationLineObject))]
final class TaxIntegrationLineObject_Extension
{
private OMOperatingUnitNumber costCenter;
private ProjId projectId;
/// <summary>
/// Gets a costCenter.
/// </summary>
/// <returns>The cost center.</returns>
public final OMOperatingUnitNumber getCostCenter()
{
return this.costCenter;
}
/// <summary>
/// Sets the cost center.
/// </summary>
/// <param name = "_value">The cost center.</param>
public final void setCostCenter(OMOperatingUnitNumber _value)
{
this.costCenter = _value;
}
/// <summary>
/// Gets a project ID.
/// </summary>
/// <returns>The project ID.</returns>
public final ProjId getProjectId()
{
return this.projectId;
}
/// <summary>
/// Sets the project ID.
/// </summary>
/// <param name = "_value">The project ID.</param>
public final void setProjectId(ProjId _value)
{
this.projectId = _value;
}
}
TaxIntegrationPurchTableDataRetrieval_Extension.xpp
[ExtensionOf(classStr(TaxIntegrationPurchTableDataRetrieval))]
final class TaxIntegrationPurchTableDataRetrieval_Extension
{
private const str CostCenterKey = 'CostCenter';
private const str ProjectKey = 'Project';
/// <summary>
/// Copies to the current line of the document from.
/// </summary>
/// <param name = "_line">The current line of the document.</param>
protected void copyToLineFromLineTable(TaxIntegrationLineObject _line)
{
Map dimensionAttributeMap = this.getDimensionAttributeMapByDefaultDimension(this.purchline.DefaultDimension);
if (dimensionAttributeMap.exists(CostCenterKey))
{
_line.setCostCenter(dimensionAttributeMap.lookup(CostCenterKey));
}
if (dimensionAttributeMap.exists(ProjectKey))
{
_line.setProjectId(dimensionAttributeMap.lookup(ProjectKey));
}
next copyToLineFromLineTable(_line);
}
private Map getDimensionAttributeMapByDefaultDimension(RefRecId _defaultDimension)
{
DimensionAttribute dimensionAttribute;
DimensionAttributeValue dimensionAttributeValue;
DimensionAttributeValueSetItem dimensionAttributeValueSetItem;
Map ret = new Map(Types::String, Types::String);
select Name, RecId from dimensionAttribute
join dimensionAttributeValue
where dimensionAttributeValue.dimensionAttribute == dimensionAttribute.RecId
join DimensionAttributeValueSetItem
where DimensionAttributeValueSetItem.DimensionAttributeValue == DimensionAttributeValue.RecId
&& DimensionAttributeValueSetItem.DimensionAttributeValueSet == _defaultDimension;
while(dimensionAttribute.RecId)
{
ret.insert(dimensionAttribute.Name, dimensionAttributeValue.DisplayValue);
next dimensionAttribute;
}
return ret;
}
}
TaxIntegrationCalculationActivityOnDocument_CalculationService_Extension.xpp
[ExtensionOf(classStr(TaxIntegrationCalculationActivityOnDocument_CalculationService))]
final static class TaxIntegrationCalculationActivityOnDocument_CalculationService_Extension
{
// Define the field name in the request
private const str IOCostCenter = 'Cost Center';
private const str IOProject = 'Project';
/// <summary>
/// Copies to <c>TaxableDocumentLineWrapper</c> from <c>TaxIntegrationLineObject</c> by line.
/// </summary>
/// <param name = "_destination"><c>TaxableDocumentLineWrapper</c>.</param>
/// <param name = "_source"><c>TaxIntegrationLineObject</c>.</param>
protected static void copyToTaxableDocumentLineWrapperFromTaxIntegrationLineObjectByLine(Microsoft.Dynamics.TaxCalculation.ApiContracts.TaxableDocumentLineWrapper _destination, TaxIntegrationLineObject _source)
{
next copyToTaxableDocumentLineWrapperFromTaxIntegrationLineObjectByLine(_destination, _source);
// Set the field we need to integrated for tax service
_destination.SetField(IOCostCenter, _source.getCostCenter());
_destination.SetField(IOProject, _source.getProjectId());
}
}