我在逻辑上遇到问题,并会感谢任何帮助/提示。
我有<Deposits>
元素和<Receipts>
元素。但是,没有任何标识向什么存款支付了什么收据。
我正在尝试<Deposits>
使用以下属性更新元素:
- @DueAmont - 仍需支付的金额
- @Status - 无论是已付、未付(部分付清)还是到期
- @ReceiptDate - 支付这笔押金的最新收据日期
每笔押金都可以用一张或多张收据支付。也有可能发生,一张收据可以涵盖一笔或多笔存款。例如。如果有 3 个存款:
- 500
- 100
- 450
使用以下收据支付:
- 200
- 100
- 250
我想获得以下信息:
押金 1已全额支付(状态=已付,dueAmount=0,receiptNum=3。
押金 2已部分支付(状态=未结,dueAmount=50,receiptNum=3。
押金 3未支付(状态=到期,到期金额=450,收据编号=NAN。
实际 XML:
<Deposits DepositDate="2010-04-07T00:00:00" DepositTotalAmount="500.0000" NoOfPeople="10.0000" PerPerson="50.00"/>
<Deposits DepositDate="2010-04-12T00:00:00" DepositTotalAmount="100.0000" NoOfPeople="10.0000" PerPerson="10.00"/>
<Deposits DepositDate="2010-04-26T00:00:00" DepositTotalAmount="450.0000" NoOfPeople="10.0000" PerPerson="45.00"/>
<Receipts Amount="200.00" PaymentType="Cheque" Comment="" ReceiptAmount="200.00" ActionDate="2010-04-07T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
<Receipts Amount="100.00" PaymentType="Cheque" Comment="" ReceiptAmount="100.00" ActionDate="2010-04-11T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
<Receipts Amount="250.00" PaymentType="Cheque" Comment="" ReceiptAmount="250.00" ActionDate="2010-04-20T11:01:47" PayingInSlipNumber="" IsCard="No" IsRefund="No"/>
我在代码中添加了注释,解释了我正在尝试做什么。我现在连续第三天盯着这段代码 - 看不出我做错了什么。请问有人可以帮我吗?:)
谢谢!
设置:
$deposits - 所有可用存款
$receiptsAsc - 所有可用收据按其@ActionDate 排序
代码:
<!-- Accumulate all the deposits with @Status, @DueAmount and @ReceiptDate attributes Provide all deposits, receipts and start with 1st receipt -->
<xsl:variable name="depositsClassified">
<xsl:call-template name="classifyDeposits">
<xsl:with-param name="depositsAll" select="$deposits"/>
<xsl:with-param name="receiptsAll" select="$receiptsAsc"/>
<xsl:with-param name="receiptCount" select="'1'"/>
</xsl:call-template>
</xsl:variable>
<!-- Recursive function to associate deposits' total amounts with overall receipts paid
to determine whether a deposit is due, outstanding or paid. Also determine what's the due amount and latest receipt towards the deposit for each deposit -->
<xsl:template name="classifyDeposits">
<xsl:param name="depositsAll"/>
<xsl:param name="receiptsAll"/>
<xsl:param name="receiptCount"/>
<!-- If there are deposits to proceed -->
<xsl:if test="$depositsAll">
<!-- Get the 1st deposit -->
<xsl:variable name="deposit" select="$depositsAll[1]"/>
<!-- Calculate the sum of all receipts up to and including currenly considered -->
<xsl:variable name="receiptSum">
<xsl:choose>
<xsl:when test="$receiptsAll">
<xsl:value-of select="sum($receiptsAll[position() <= $receiptCount]/@ReceiptAmount)"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- Difference between deposit amount and sum of the receipts calculated
above -->
<xsl:variable name="diff" select="$deposit/@DepositTotalAmount - $receiptSum"/>
<xsl:choose>
<!-- Deposit isn't paid fully and there are more receipts/payments exist.
So consider the same deposit, but take next receipt into calculation as
well -->
<xsl:when test="($diff > 0) and ($receiptCount < count($receiptsAll))">
<xsl:call-template name="classifyDeposits">
<xsl:with-param name="depositsAll" select="$depositsAll"/>
<xsl:with-param name="receiptsAll" select="$receiptsAll"/>
<xsl:with-param name="receiptCount" select="$receiptCount + 1"/>
</xsl:call-template>
</xsl:when>
<!-- Deposit is paid or we ran out of receipts -->
<xsl:otherwise>
<!-- process the deposit. Determine its status and then update
corresponding attributes -->
<xsl:apply-templates select="$deposit" mode="defineDeposit">
<xsl:with-param name="diff" select="$diff"/>
<xsl:with-param name="receiptNum" select="$receiptCount"/>
</xsl:apply-templates>
<!-- Recursively call the template with the rest of deposits excluding the first. Before hand update the @ReceiptsAmount. For the receipts before current it is now 0, for the current is what left in the $diff, and simply copy over receipts after current one. -->
<xsl:variable name="receiptsUpdatedRTF">
<xsl:for-each select="$receiptsAll">
<xsl:choose>
<!-- these receipts was fully accounted for the current deposit. Make them 0 -->
<xsl:when test="position() < $receiptCount">
<xsl:copy>
<xsl:copy-of select="./@*"/>
<xsl:attribute name="ReceiptAmount">0</xsl:attribute>
</xsl:copy>
</xsl:when>
<!-- this receipt was partly/fully(in case $diff=0) accounted for the current deposit. Make it whatever is in $diff -->
<xsl:when test="position() = $receiptCount">
<xsl:copy>
<xsl:copy-of select="./@*"/>
<xsl:attribute name="ReceiptAmount">
<xsl:value-of select="format-number($diff, '#.00;#.00')"/>
</xsl:attribute>
</xsl:copy>
</xsl:when>
<!-- these receipts weren't yet considered - copy them over -->
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="receiptsUpdated" select="msxsl:node-set($receiptsUpdatedRTF)/Receipts"/>
<!-- Recursive call for the next deposit. Starting counting receipts from the current one. -->
<xsl:call-template name="classifyDeposits">
<xsl:with-param name="depositsAll" select="$deposits[position() != 1]"/>
<xsl:with-param name="receiptsAll" select="$receiptsUpdated"/>
<xsl:with-param name="receiptCount" select="$receiptCount"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<!-- Determine deposit's status and due amount -->
<xsl:template match="MultiDeposits" mode="defineDeposit">
<xsl:param name="diff"/>
<xsl:param name="receiptNum"/>
<xsl:choose>
<xsl:when test="$diff <= 0">
<xsl:apply-templates select="." mode="addAttrs">
<xsl:with-param name="status" select="'paid'"/>
<xsl:with-param name="dueAmount" select="'0'"/>
<xsl:with-param name="receiptNum" select="$receiptNum"/>
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$diff = ./@DepositTotalAmount">
<xsl:apply-templates select="." mode="addAttrs">
<xsl:with-param name="status" select="'due'"/>
<xsl:with-param name="dueAmount" select="$diff"/>
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$diff < ./@DepositTotalAmount">
<xsl:apply-templates select="." mode="addAttrs">
<xsl:with-param name="status" select="'outstanding'"/>
<xsl:with-param name="dueAmount" select="$diff"/>
<xsl:with-param name="receiptNum" select="$receiptNum"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
<!-- Add new attributes (@Status, @DueAmount and @ReceiptDate) to the
deposit element -->
<xsl:template match="MultiDeposits" mode="addAttrs">
<xsl:param name="status"/>
<xsl:param name="dueAmount"/>
<xsl:param name="receiptNum" select="''"/>
<xsl:copy>
<xsl:copy-of select="./@*"/>
<xsl:attribute name="Status"><xsl:value-of select="$status"/></xsl:attribute>
<xsl:attribute name="DueAmount"><xsl:value-of select="$dueAmount"/></xsl:attribute>
<xsl:if test="$receiptNum != ''">
<xsl:attribute name="ReceiptDate">
<xsl:value-of select="$receiptsAsc[position() = $receiptNum]/@ActionDate"/>
</xsl:attribute>
</xsl:if>
<xsl:copy-of select="./*"/>
</xsl:copy>
</xsl:template>