26afdf3e9a
Both delivery paths (HU via E1EDL37/E1EDL44 and no-HU via E1EDL24) now produce one SGTIN-96 XMLEPC per unit when EDI_DC40/TEST = 'X' and no E1EPC03 URNs are present in the message. Serials are derived from MD5(DOCNUM + SSCC+POSNR+counter) for HU items and MD5(DOCNUM + POSNR+counter) for direct items, ensuring uniqueness across positions and handling units. DeliveredQuantity in the no-HU path corrected from LGMNG to LFIMG.
257 lines
10 KiB
XML
257 lines
10 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
||
<!-- 11.03.2026 Oject-10438 Merging all HUs into single message with multiple XMLSSCCGROUPS-->
|
||
<!-- 22.12.2023 DEV-8311 SAP sends delivery advices to stores MAPPING: SOURCE
|
||
- SAP ZFSHDLV TARGET - syspro internal Format -->
|
||
<xsl:stylesheet version="2.0"
|
||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||
xmlns:ns0="http://sap.com/xi/XI/SplitAndMerge"
|
||
xmlns:gs1="urn:gs1:epc"
|
||
exclude-result-prefixes="xs ns0 gs1">
|
||
|
||
<xsl:output method="xml" indent="yes"/>
|
||
<xsl:strip-space elements="*"/>
|
||
|
||
<!-- Wurzel-Template: nur eine Nachricht -->
|
||
<xsl:template match="/">
|
||
<ns0:Messages>
|
||
<ns0:Message1>
|
||
<xsl:apply-templates select="//ZFSHDLV/IDOC"/>
|
||
</ns0:Message1>
|
||
</ns0:Messages>
|
||
</xsl:template>
|
||
|
||
<!-- Template für IDOC: eine einzige XMLDESADV -->
|
||
<xsl:template match="ZFSHDLV/IDOC">
|
||
<xsl:variable name="docnum" select="normalize-space(EDI_DC40/DOCNUM)"/>
|
||
<xsl:variable name="testMode" select="EDI_DC40/TEST = 'X'"/>
|
||
<XMLDESADV>
|
||
|
||
<xsl:comment>SAP IDOC Number: <xsl:value-of select="EDI_DC40/DOCNUM"/> </xsl:comment>
|
||
|
||
<XMLDESADVHEADER>
|
||
<!-- DocumentId mit erster SSCC -->
|
||
<DocumentId>
|
||
<xsl:value-of select="E1EDL20/VBELN"/>
|
||
</DocumentId>
|
||
|
||
<!-- DeliveryNote: LIFEX oder VBELN -->
|
||
<DeliveryNote>
|
||
<xsl:value-of select="if (E1EDL20/LIFEX) then E1EDL20/LIFEX else E1EDL20/VBELN"/>
|
||
</DeliveryNote>
|
||
|
||
<DocumentType>XMLDESADV</DocumentType>
|
||
<DocumentSubType>
|
||
<xsl:call-template name="DocumentSubType">
|
||
<xsl:with-param name="LFART" select="E1EDL21/LFART"/>
|
||
</xsl:call-template>
|
||
</DocumentSubType>
|
||
|
||
<!-- DocumentDate (QUALF='015') -->
|
||
<DocumentDate>
|
||
<xsl:value-of
|
||
select="format-dateTime(
|
||
adjust-dateTime-to-timezone(
|
||
xs:dateTime(concat(
|
||
substring(E1EDL20/E1EDT13[QUALF='015']/NTANF,1,4),'-',
|
||
substring(E1EDL20/E1EDT13[QUALF='015']/NTANF,5,2),'-',
|
||
substring(E1EDL20/E1EDT13[QUALF='015']/NTANF,7,2),'T',
|
||
substring(E1EDL20/E1EDT13[QUALF='015']/NTANZ,1,2),':',
|
||
substring(E1EDL20/E1EDT13[QUALF='015']/NTANZ,3,2),':',
|
||
substring(E1EDL20/E1EDT13[QUALF='015']/NTANZ,5,2)
|
||
))),
|
||
'[Y0000]-[M00]-[D00]T[H00]:[m00]:[s00].[f0000000][Z]')
|
||
"/>
|
||
</DocumentDate>
|
||
|
||
<!-- DeliveryDate (QUALF='007') -->
|
||
<DeliveryDate>
|
||
<xsl:value-of
|
||
select="format-dateTime(
|
||
adjust-dateTime-to-timezone(
|
||
xs:dateTime(concat(
|
||
substring(E1EDL20/E1EDT13[QUALF='007']/NTANF,1,4),'-',
|
||
substring(E1EDL20/E1EDT13[QUALF='007']/NTANF,5,2),'-',
|
||
substring(E1EDL20/E1EDT13[QUALF='007']/NTANF,7,2),'T',
|
||
substring(E1EDL20/E1EDT13[QUALF='007']/NTANZ,1,2),':',
|
||
substring(E1EDL20/E1EDT13[QUALF='007']/NTANZ,3,2),':',
|
||
substring(E1EDL20/E1EDT13[QUALF='007']/NTANZ,5,2)
|
||
))),
|
||
'[Y0000]-[M00]-[D00]T[H00]:[m00]:[s00].[f0000000][Z]')
|
||
"/>
|
||
</DeliveryDate>
|
||
|
||
<!-- GLNs -->
|
||
<SenderGLN><xsl:value-of select="E1IDOCENHANCEMENT[IDENTIFIER='SENDERGLN']/DATA"/></SenderGLN>
|
||
<ReceipientGLN><xsl:value-of select="E1IDOCENHANCEMENT[IDENTIFIER='RECEIVERGLN']/DATA"/></ReceipientGLN>
|
||
<!-- leere Felder optional -->
|
||
<AllocationReference/>
|
||
<ReferenceSupplierOrder/>
|
||
<ReferenceBuyerOrder/>
|
||
<ReferenceDocument><xsl:value-of select="E1EDL20/VBELN"/></ReferenceDocument>
|
||
<SupplierGLN/>
|
||
<BuyerGLN/>
|
||
<DeliveryPartyGLN/>
|
||
<UltimateConsignyGLN/>
|
||
<ReturnGLN/>
|
||
<SendFromGLN/>
|
||
<SendToGLN/>
|
||
<DeliveryCurrency/>
|
||
</XMLDESADVHEADER>
|
||
|
||
<!-- Package Group -->
|
||
<XMLPACKAGEGROUP>
|
||
<NumberOfPackages>
|
||
<xsl:value-of select="if (E1EDL20/ANZPK and number(E1EDL20/ANZPK) > 0)
|
||
then format-number(E1EDL20/ANZPK, '#')
|
||
else '1'"/>
|
||
</NumberOfPackages>
|
||
<PackageCode>33E</PackageCode>
|
||
</XMLPACKAGEGROUP>
|
||
|
||
<!-- HUs – pro HU eine XMLSSCCGROUP -->
|
||
<xsl:for-each select="E1EDL20/E1EDL37">
|
||
<XMLSSCCGROUP>
|
||
<SSCC>
|
||
<xsl:value-of select="
|
||
if (string-length(translate(normalize-space(EXIDV), '0123456789', '')) != 0)
|
||
then normalize-space(EXIDV)
|
||
else replace(normalize-space(EXIDV), '^0+', '')
|
||
"/>
|
||
</SSCC>
|
||
<PackageCode>33E</PackageCode>
|
||
<PackageType>BJ</PackageType>
|
||
|
||
<!-- Artikel für diese HU -->
|
||
<xsl:for-each select="E1EDL44">
|
||
<xsl:variable name="posnr" select="POSNR"/>
|
||
<xsl:variable name="rawGtin" select="normalize-space(../../../E1EDL20/E1EDL24[POSNR = $posnr]/EAN11)"/>
|
||
<xsl:variable name="gtin14" select="substring(concat('00000000000000', $rawGtin), string-length($rawGtin) + 1, 14)"/>
|
||
<xsl:variable name="qty" select="xs:integer(xs:decimal(./VEMNG))"/>
|
||
<xsl:variable name="sscc" select="normalize-space(../EXIDV)"/>
|
||
<xsl:variable name="hasEpc" select="E1EPC03[URN and string-length(normalize-space(URN)) > 0]"/>
|
||
<XMLITEMS>
|
||
<PositionNumber><xsl:value-of select="$posnr"/></PositionNumber>
|
||
<GTIN><xsl:value-of select="$rawGtin"/></GTIN>
|
||
<DeliveredQuantity>
|
||
<xsl:value-of select="xs:decimal(./VEMNG)"/>
|
||
</DeliveredQuantity>
|
||
<QuantityQualifier>
|
||
<xsl:call-template name="QuantityQualifier">
|
||
<xsl:with-param name="UoM" select="./VEMEH"/>
|
||
</xsl:call-template>
|
||
</QuantityQualifier>
|
||
<DeliveryPrice></DeliveryPrice>
|
||
<ReferenceSupplierOrder>
|
||
<xsl:value-of select="../../../E1EDL20/E1EDL24[POSNR = $posnr]/VGBEL"/>
|
||
</ReferenceSupplierOrder>
|
||
<ReferenceBuyerOrder></ReferenceBuyerOrder>
|
||
<!-- EPCs from message -->
|
||
<xsl:if test="$hasEpc">
|
||
<xsl:for-each select="E1EPC03[URN and string-length(normalize-space(URN)) > 0]">
|
||
<XMLEPC>
|
||
<EPC><xsl:value-of select="normalize-space(URN)"/></EPC>
|
||
</XMLEPC>
|
||
</xsl:for-each>
|
||
</xsl:if>
|
||
<!-- Test-mode synthetic EPCs: one per unit (VEMNG), keyed by SSCC+POSNR+counter -->
|
||
<xsl:if test="$testMode and not($hasEpc)">
|
||
<xsl:for-each select="1 to $qty">
|
||
<XMLEPC>
|
||
<EPC>
|
||
<xsl:value-of select="gs1:encodeSgtin96FromIdoc(
|
||
$gtin14,
|
||
$docnum,
|
||
concat($sscc, '-', $posnr, '-', string(.)),
|
||
xs:integer(1),
|
||
xs:integer(7)
|
||
)"/>
|
||
</EPC>
|
||
</XMLEPC>
|
||
</xsl:for-each>
|
||
</xsl:if>
|
||
</XMLITEMS>
|
||
</xsl:for-each>
|
||
</XMLSSCCGROUP>
|
||
</xsl:for-each>
|
||
|
||
<!-- Handle case when there are no handling units (E1EDL37) -->
|
||
<xsl:if test="not(E1EDL20/E1EDL37) and E1EDL20/E1EDL24">
|
||
<XMLSSCCGROUP>
|
||
<SSCC><xsl:value-of select="E1EDL20/VBELN"/></SSCC>
|
||
<PackageCode>33E</PackageCode>
|
||
<PackageType>BJ</PackageType>
|
||
|
||
<!-- Process direct items when no handling units exist -->
|
||
<xsl:for-each select="E1EDL20/E1EDL24">
|
||
<!-- Capture node values before context shifts inside the seq loop -->
|
||
<xsl:variable name="rawGtin" select="normalize-space(./EAN11)"/>
|
||
<xsl:variable name="gtin14" select="substring(concat('00000000000000', $rawGtin), string-length($rawGtin) + 1, 14)"/>
|
||
<xsl:variable name="posnr" select="string(./POSNR)"/>
|
||
<xsl:variable name="qty" select="xs:integer(xs:decimal(./LFIMG))"/>
|
||
<xsl:variable name="hasEpc" select="E1EPC03[URN and string-length(normalize-space(URN)) > 0]"/>
|
||
<XMLITEMS>
|
||
<PositionNumber>
|
||
<xsl:value-of select="./POSNR"/>
|
||
</PositionNumber>
|
||
<GTIN>
|
||
<xsl:value-of select="./EAN11"/>
|
||
</GTIN>
|
||
<DeliveredQuantity>
|
||
<xsl:value-of select="xs:decimal(./LFIMG)"/>
|
||
</DeliveredQuantity>
|
||
<QuantityQualifier>
|
||
<xsl:call-template name="QuantityQualifier">
|
||
<xsl:with-param name="UoM">
|
||
<xsl:value-of select="./MEINS"/>
|
||
</xsl:with-param>
|
||
</xsl:call-template>
|
||
</QuantityQualifier>
|
||
<DeliveryPrice></DeliveryPrice>
|
||
<ReferenceSupplierOrder>
|
||
<xsl:value-of select="./VGBEL"/>
|
||
</ReferenceSupplierOrder>
|
||
<ReferenceBuyerOrder></ReferenceBuyerOrder>
|
||
<!-- One unique SGTIN-96 EPC per unit (LFIMG actual qty) when test mode is active
|
||
and no E1EPC03 URN is present. Counter appended to POSNR makes
|
||
each serial unique: MD5(DOCNUM + POSNR-1), MD5(DOCNUM + POSNR-2) … -->
|
||
<xsl:if test="$testMode and not($hasEpc)">
|
||
<xsl:for-each select="1 to $qty">
|
||
<XMLEPC>
|
||
<EPC>
|
||
<xsl:value-of select="gs1:encodeSgtin96FromIdoc(
|
||
$gtin14,
|
||
$docnum,
|
||
concat($posnr, '-', string(.)),
|
||
xs:integer(1),
|
||
xs:integer(7)
|
||
)"/>
|
||
</EPC>
|
||
</XMLEPC>
|
||
</xsl:for-each>
|
||
</xsl:if>
|
||
</XMLITEMS>
|
||
</xsl:for-each>
|
||
</XMLSSCCGROUP>
|
||
</xsl:if>
|
||
</XMLDESADV>
|
||
</xsl:template>
|
||
|
||
<!-- Hilfs-Templates -->
|
||
<xsl:template name="DocumentSubType">
|
||
<xsl:param name="LFART"/>
|
||
<xsl:choose>
|
||
<xsl:when test="$LFART = 'ZIL'">DESADV_IBT</xsl:when>
|
||
<xsl:otherwise>DESADV_GI</xsl:otherwise>
|
||
</xsl:choose>
|
||
</xsl:template>
|
||
|
||
<xsl:template name="QuantityQualifier">
|
||
<xsl:param name="UoM"/>
|
||
<xsl:choose>
|
||
<xsl:when test="$UoM = 'PCE'">12</xsl:when>
|
||
<xsl:otherwise>999</xsl:otherwise>
|
||
</xsl:choose>
|
||
</xsl:template>
|
||
|
||
</xsl:stylesheet> |