У меня проблемы с логикой, и я был бы признателен за любую помощь/советы.
У меня есть элементы <Deposits>
и элементы <Receipts>
. Однако нет никакой идентификации, какая квитанция была выплачена на какой депозит.
Я пытаюсь обновить элементы <Deposits>
со следующими атрибутами:
- @DueAmont — сумма, которую еще нужно заплатить
- @Статус - оплачено ли, непогашено (частично оплачено) или подлежит оплате
- @ReceiptDate — дата последней квитанции, которая была выплачена в счет этого депозита.
Каждый депозит может быть оплачен одной или несколькими квитанциями. Также может случиться так, что 1 квитанция может покрывать один или несколько депозитов. Например. Если депозитов 3:
- 500
- 100
- 450
Которые оплачиваются следующими квитанциями:
- 200
- 100
- 250
Я хочу получить следующую информацию:
Депозит 1 полностью оплачен (статус=оплачен, dueAmount=0, квитанцияNum=3.
Депозит 2 частично выплачен (status=outstanding, dueAmount=50, квитанцияNum=3.
Депозит 3 не выплачен (status=due, dueAmount=450, квитанцияNum=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"/>
Я добавил комментарии в код, объясняющие, что я пытаюсь сделать. Я смотрю на этот код уже 3-й день без остановки - не вижу, что я делаю неправильно. Пожалуйста, может ли кто-нибудь помочь мне с этим? :)
Спасибо!
Настройка:
$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>