Author: hansbak
Date: Thu Oct 2 00:33:43 2008 New Revision: 701022 URL: http://svn.apache.org/viewvc?rev=701022&view=rev Log: now possble to apply a payment on an invoice of another currency, removed the convertinvoice service as suggested by jacopo. Modified: ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/invoice/InvoiceServices.xml ofbiz/trunk/applications/accounting/servicedef/services_invoice.xml ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentWorker.java ofbiz/trunk/applications/accounting/webapp/accounting/WEB-INF/actions/payment/ListNotAppliedInvoices.groovy ofbiz/trunk/applications/accounting/webapp/accounting/payment/PaymentForms.xml Modified: ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/invoice/InvoiceServices.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/invoice/InvoiceServices.xml?rev=701022&r1=701021&r2=701022&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/invoice/InvoiceServices.xml (original) +++ ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/invoice/InvoiceServices.xml Thu Oct 2 00:33:43 2008 @@ -506,57 +506,6 @@ <call-simple-method method-name="copyInvoice"/> </simple-method> - <simple-method method-name="convertInvoiceToOtherCurrency" short-description="service to convert an invoice to another currency having the original currency still there using the exchange rate table."> - <entity-one entity-name="Invoice" value-name="invoice"/> - <if-empty field="invoice"> - <add-error><fail-message message="Invoice not found"/></add-error> - </if-empty> - <entity-one entity-name="Uom" value-name="newCurrencyUom"> - <field-map field-name="uomId" env-name="parameters.newCurrencyUomId"/> - </entity-one> - <if-empty field="newCurrencyUom"> - <add-error><fail-message message="New Currency Code not found"/></add-error> - </if-empty> - <if-compare-field field="parameters.newCurrencyUomId" operator="equals" to-field="invoice.currencyUomId"> - <add-error><fail-message message="Invoice already has the requested currency"/></add-error> - </if-compare-field> - <check-errors/> - - <get-related value-name="invoice" relation-name="InvoiceItem" list-name="invoiceItems"/> - <iterate list-name="invoiceItems" entry-name="invoiceItem"> - <calculate field-name="invoiceItem.amount" type="Double" decimal-scale="15"> - <calcop operator="divide"> - <calcop operator="get" field-name="invoiceItem.amount"/> - <calcop operator="get" field-name="parameters.exchangeRate"/> - </calcop> - </calculate> - <store-value value-name="invoiceItem"/> - </iterate> - - <entity-one entity-name="UomConversionDated" value-name="uomValue"> - <field-map field-name="uomId" env-name="parameters.newCurrencyUomId"/> - <field-map field-name="uomIdTo" env-name="invoice.currencyUomId"/> - <field-map field-name="fromDate" env-name="invoice.invoiceDate"/> - </entity-one> - - <make-value entity-name="UomConversionDated" value-name="uomConversionDated"/> - <set field="uomConversionDated.uomId" from-field="parameters.newCurrencyUomId"/> - <set field="uomConversionDated.uomIdTo" from-field="invoice.currencyUomId"/> - <set field="uomConversionDated.fromDate" from-field="invoice.invoiceDate"/> - <set field="uomConversionDated.thruDate" from-field="invoice.invoiceDate"/> - <set field="uomConversionDated.conversionFactor" from-field="parameters.exchangeRate"/> - <if-empty field="uomValue"> - <create-value value-name="uomConversionDated"/> - <else> - <store-value value-name="uomConversionDated"/> - </else> - </if-empty> - - <set field="invoice.currencyUomId" from-field="parameters.newCurrencyUomId"/> - <store-value value-name="invoice"/> - <field-to-result field-name="parameters.invoiceId" result-name="invoiceId"/> - </simple-method> - <!-- ===============subroutine services =================--> <simple-method method-name="InvoiceStatusInProgress" short-description="Check if the invoiceStatus is in progress"> <!-- find the current header record --> Modified: ofbiz/trunk/applications/accounting/servicedef/services_invoice.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/servicedef/services_invoice.xml?rev=701022&r1=701021&r2=701022&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/servicedef/services_invoice.xml (original) +++ ofbiz/trunk/applications/accounting/servicedef/services_invoice.xml Thu Oct 2 00:33:43 2008 @@ -280,11 +280,4 @@ <auto-attributes mode="IN" include="pk" optional="false"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> </service> - <service name="convertInvoiceToOtherCurrency" engine="simple" - location="org/ofbiz/accounting/invoice/InvoiceServices.xml" invoke="convertInvoiceToOtherCurrency"> - <description>service to convert an invoice to another currency having the original currency still there using the exchange rate table.</description> - <attribute name="invoiceId" mode="INOUT" type="String"/> - <attribute name="newCurrencyUomId" mode="IN" type="String"/> - <attribute name="exchangeRate" mode="IN" type="Double"/> - </service> </services> \ No newline at end of file Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java?rev=701022&r1=701021&r2=701022&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java (original) +++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/invoice/InvoiceServices.java Thu Oct 2 00:33:43 2008 @@ -2507,31 +2507,19 @@ !payment.getString("currencyUomId").equals(invoice.getString("currencyUomId"))) { Debug.logInfo(UtilProperties.getMessage(resource, "AccountingInvoicePaymentCurrencyProblem", UtilMisc.toMap("invoiceCurrency", invoice.getString("currencyUomId"), "paymentCurrency", payment.getString("currencyUomId")),locale), module); - Debug.logInfo("will convert invoice currency according original currency amount on payment", module); + Debug.logInfo("will try to apply payment on the actualCurrency amount on payment", module); if (payment.get("actualCurrencyAmount") == null || payment.get("actualCurrencyUomId") == null) { - errorMessageList.add("in order to properly convert the Invoice we need the actual currency and actual amount on the payment"); + errorMessageList.add("Actual amounts are required in the currency of the invoice to make this work...."); } else { if (!payment.get("actualCurrencyUomId").equals(invoice.get("currencyUomId"))) { errorMessageList.add("actual currency on payment not the same as original invoice currency"); - } else { - // calculate exchange rate, convert/retrieve invoice - try { - Double exchangeRate = new Double( payment.getDouble("actualCurrencyAmount").doubleValue() / payment.getDouble("amount").doubleValue()); - Map inMap = UtilMisc.toMap("userLogin", userLogin, "invoiceId", invoiceId, "newCurrencyUomId", payment.getString("currencyUomId")); - inMap.put("exchangeRate", exchangeRate); - dispatcher.runSync("convertInvoiceToOtherCurrency", inMap); - invoice = delegator.findByPrimaryKey("Invoice", UtilMisc.toMap("invoiceId", invoiceId)); - } catch (GenericServiceException se) { - Debug.logError(se, se.getMessage(), module); - return ServiceUtil.returnError(se.getMessage()); - } catch (GenericEntityException e) { - ServiceUtil.returnError(e.getMessage()); - } - } + } + } + paymentApplyAvailable = payment.getBigDecimal("actualCurrencyAmount").subtract(PaymentWorker.getPaymentAppliedBd(payment)).setScale(decimals,rounding); + if (amountApplied.signum() == 0) { + amountAppliedMax = paymentApplyAvailable; } - - } // check if the invoice already covered by payments Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentWorker.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentWorker.java?rev=701022&r1=701021&r2=701022&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentWorker.java (original) +++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentWorker.java Thu Oct 2 00:33:43 2008 @@ -19,6 +19,7 @@ package org.ofbiz.accounting.payment; import java.math.BigDecimal; +import java.math.MathContext; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -254,6 +255,32 @@ return getPaymentAppliedBd(payment); } /** + * Method to return the amount applied converted to the currency of payment + * @param String paymentApplicationId + * @return the applied amount as BigDecimal + */ + public static BigDecimal getPaymentAppliedAmount(GenericDelegator delegator, String paymentApplicationId) { + GenericValue paymentApplication = null; + BigDecimal appliedAmount = BigDecimal.ZERO; + try { + paymentApplication = delegator.findByPrimaryKey("PaymentApplication", UtilMisc.toMap("paymentApplicationId", paymentApplicationId)); + appliedAmount = paymentApplication.getBigDecimal("amountApplied"); + if (paymentApplication.get("paymentId") != null) { + GenericValue payment = paymentApplication.getRelatedOne("Payment"); + if (paymentApplication.get("invoiceId") != null && payment.get("actualCurrencyAmount") != null && payment.get("actualCurrencyUomId") != null) { + GenericValue invoice = paymentApplication.getRelatedOne("Invoice"); + if (payment.getString("actualCurrencyUomId").equals(invoice.getString("currencyUomId"))) { + appliedAmount = appliedAmount.multiply(payment.getBigDecimal("amount")).divide(payment.getBigDecimal("actualCurrencyAmount"),new MathContext(100)); + } + } + } + } catch (GenericEntityException e) { + Debug.logError(e, "Problem getting Payment", module); + } + return appliedAmount; + } + + /** * Method to return the total amount of an payment which is applied to a payment * @param payment GenericValue object of the Payment * @return the applied total as double @@ -267,30 +294,24 @@ List paymentApplications = null; try { paymentApplications = payment.getRelated("PaymentApplication"); - } catch (GenericEntityException e) { - Debug.logError(e, "Trouble getting paymentApplicationlist", module); - } - if (UtilValidate.isNotEmpty(paymentApplications)) { - Iterator p = paymentApplications.iterator(); - while (p.hasNext()) { - GenericValue paymentApplication = (GenericValue) p.next(); - paymentApplied = paymentApplied.add(paymentApplication.getBigDecimal("amountApplied")).setScale(decimals,rounding); - } - } - // check for payment to payment applications - paymentApplications = null; - try { - paymentApplications = payment.getRelated("ToPaymentApplication"); - } catch (GenericEntityException e) { - Debug.logError(e, "Trouble getting the 'to' paymentApplicationlist", module); - } - if (UtilValidate.isNotEmpty(paymentApplications)) { - Iterator p = paymentApplications.iterator(); - while (p.hasNext()) { - GenericValue paymentApplication = (GenericValue) p.next(); - paymentApplied = paymentApplied.add(paymentApplication.getBigDecimal("amountApplied")).setScale(decimals,rounding); + if (UtilValidate.isNotEmpty(paymentApplications)) { + Iterator p = paymentApplications.iterator(); + while (p.hasNext()) { + GenericValue paymentApplication = (GenericValue) p.next(); + BigDecimal amountApplied = paymentApplication.getBigDecimal("amountApplied"); + // check currency invoice and if different convert amount applied for display + if (paymentApplication.get("invoiceId") != null && payment.get("actualCurrencyAmount") != null && payment.get("actualCurrencyUomId") != null) { + GenericValue invoice = paymentApplication.getRelatedOne("Invoice"); + if (payment.getString("actualCurrencyUomId").equals(invoice.getString("currencyUomId"))) { + amountApplied = amountApplied.multiply(payment.getBigDecimal("amount")).divide(payment.getBigDecimal("actualCurrencyAmount"),new MathContext(100)); + } + } + paymentApplied = paymentApplied.add(amountApplied).setScale(decimals,rounding); + } } - } + } catch (GenericEntityException e) { + Debug.logError(e, "Trouble getting entities", module); + } return paymentApplied; } public static double getPaymentNotApplied(GenericValue payment) { Modified: ofbiz/trunk/applications/accounting/webapp/accounting/WEB-INF/actions/payment/ListNotAppliedInvoices.groovy URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/webapp/accounting/WEB-INF/actions/payment/ListNotAppliedInvoices.groovy?rev=701022&r1=701021&r2=701022&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/webapp/accounting/WEB-INF/actions/payment/ListNotAppliedInvoices.groovy (original) +++ ofbiz/trunk/applications/accounting/webapp/accounting/WEB-INF/actions/payment/ListNotAppliedInvoices.groovy Thu Oct 2 00:33:43 2008 @@ -24,8 +24,11 @@ import org.ofbiz.accounting.invoice.*; import org.ofbiz.accounting.payment.*; import org.ofbiz.accounting.util.UtilAccounting; +import org.ofbiz.entity.condition.EntityCondition; +import org.ofbiz.entity.condition.EntityOperator; +import org.ofbiz.entity.condition.EntityExpr; +import org.ofbiz.entity.condition.EntityConditionList; import java.math.*; -import java.text.NumberFormat; paymentId = parameters.paymentId; payment = delegator.findByPrimaryKey("Payment", [paymentId : paymentId]); @@ -33,67 +36,56 @@ decimals = UtilNumber.getBigDecimalScale("invoice.decimals"); rounding = UtilNumber.getBigDecimalRoundingMode("invoice.rounding"); -//retrieve invoices for the related parties which have not been (fully) applied yet and which have the same currency. -List invoices = delegator.findByAnd("Invoice", [partyId : payment.partyIdFrom, partyIdFrom : payment.partyIdTo, currencyUomId : payment.currencyUomId], ["invoiceDate"]); -if (invoices) { - invoicesList = []; // to pass back to the screeen list of unapplied invoices - paymentApplied = PaymentWorker.getPaymentAppliedBd(payment); - paymentToApply = payment.getBigDecimal("amount").setScale(decimals,rounding).subtract(paymentApplied); - invoices.each { invoice -> - invoiceAmount = InvoiceWorker.getInvoiceTotalBd(invoice).setScale(decimals,rounding); - invoiceApplied = InvoiceWorker.getInvoiceAppliedBd(invoice).setScale(decimals,rounding); - if (!invoiceAmount.equals(invoiceApplied) && - !invoice.statusId.equals("INVOICE_CANCELLED") && - !invoice.statusId.equals("INVOICE_IN_PROCESS")) { - // put in the map - invoiceToApply = invoiceAmount.subtract(invoiceApplied); - invoiceMap = [:]; - invoiceMap.invoiceId = invoice.invoiceId; - invoiceMap.currencyUomId = invoice.currencyUomId; - invoiceMap.amount = invoiceAmount; - invoiceMap.description = invoice.description; - invoiceMap.invoiceDate = invoice.invoiceDate.toString().substring(0,10); // display only YYYY-MM-DD - invoiceMap.amountApplied = invoiceApplied; - if (paymentToApply.compareTo(invoiceToApply) < 0 ) { - invoiceMap.amountToApply = paymentToApply; - } else { - invoiceMap.amountToApply = invoiceToApply; - } - invoicesList.add(invoiceMap); - } - } - context.invoices = invoicesList; -} +exprList = [EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, payment.partyIdFrom), + EntityCondition.makeCondition("partyIdFrom", EntityOperator.EQUALS, payment.partyIdTo)]; +partyCond = EntityCondition.makeCondition(exprList, EntityOperator.OR); + +exprList1 = [EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "INVOICE_APPROVED"), + EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "INVOICE_SEND"), + EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "INVOICE_READY"), + EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "INVOICE_RECEIVED")]; +statusCond = EntityCondition.makeCondition(exprList1, EntityOperator.OR); + +currCond = EntityCondition.makeCondition("currencyUomId", EntityOperator.EQUALS, payment.currencyUomId); +actualCurrCond = EntityCondition.makeCondition("currencyUomId", EntityOperator.EQUALS, payment.actualCurrencyUomId); -//retrieve invoices for the related parties which have not been (fully) applied yet and which have another currency -invoices = delegator.findByAnd("Invoice", [partyId : payment.partyIdFrom, partyIdFrom : payment.partyIdTo], ["invoiceDate"]); -// remove same currencies -for (int ind=0; ind < invoices.size(); ind++ ) { - if (invoices[ind].currencyUomId.equals(payment.currencyUomId)) { - invoices.remove(ind); +topCond = EntityCondition.makeCondition([partyCond, statusCond, currCond], EntityOperator.AND); +topCondActual = EntityCondition.makeCondition([partyCond, statusCond, actualCurrCond], EntityOperator.AND); +fields = new HashSet(["invoiceId", "currencyUomId", "description", "invoiceDate"]); + +//retrieve invoices for the related parties which have not been (fully) applied yet and which have the same currency as the payment +invoices = delegator.findList("Invoice", topCond, fields, ["invoiceDate"], null, false); +context.invoices = getInvoices(invoices, false); +//retrieve invoices for the related parties which have not been (fully) applied yet and which have the same originalCurrency as the payment +invoices = delegator.findList("Invoice", topCondActual, fields, ["invoiceDate"], null, false); +context.invoicesOtherCurrency = getInvoices(invoices, true); + +List getInvoices(List invoices, boolean actual) { + if (invoices) { + invoicesList = []; // to pass back to the screeen list of unapplied invoices + paymentApplied = PaymentWorker.getPaymentAppliedBd(payment); + paymentToApply = payment.getBigDecimal("amount").setScale(decimals,rounding).subtract(paymentApplied); + if (actual) { + paymentToApply = payment.getBigDecimal("actualCurrencyAmount").setScale(decimals,rounding).subtract(paymentApplied); + } + invoices.each { invoice -> + invoiceAmount = InvoiceWorker.getInvoiceTotalBd(invoice).setScale(decimals,rounding); + invoiceApplied = InvoiceWorker.getInvoiceAppliedBd(invoice).setScale(decimals,rounding); + invoiceToApply = invoiceAmount.subtract(invoiceApplied); + if (invoiceToApply.signum() == 1) { + invoiceMap = [:]; + invoiceMap.putAll(invoice); + invoiceMap.amount = invoiceAmount; + invoiceMap.description = invoice.description; + invoiceMap.amountApplied = invoiceApplied; + if (paymentToApply.compareTo(invoiceToApply) < 0 ) { + invoiceMap.amountToApply = paymentToApply; + } else { + invoiceMap.amountToApply = invoiceToApply; + } + invoicesList.add(invoiceMap); + } + } + return invoicesList; } } -if (invoices) { - invoicesList = []; // to pass back to the screeen list of unapplied invoices - paymentApplied = PaymentWorker.getPaymentAppliedBd(payment); - paymentToApply = payment.getBigDecimal("amount").setScale(decimals,rounding).subtract(paymentApplied); - invoices.each { invoice -> - invoiceAmount = InvoiceWorker.getInvoiceTotalBd(invoice).setScale(decimals,rounding); - invoiceApplied = InvoiceWorker.getInvoiceAppliedBd(invoice).setScale(decimals,rounding); - if (!invoiceAmount.equals(invoiceApplied) && - !invoice.statusId.equals("INVOICE_CANCELLED") && - !invoice.statusId.equals("INVOICE_IN_PROCESS")) { - // put in the map - invoiceToApply = invoiceAmount.subtract(invoiceApplied); - invoiceMap = [:]; - invoiceMap.invoiceId = invoice.invoiceId; - invoiceMap.currencyUomId = invoice.currencyUomId; - invoiceMap.amount = invoiceAmount; - invoiceMap.description = invoice.description; - invoiceMap.invoiceDate = invoice.invoiceDate.toString().substring(0,10); // display only YYYY-MM-DD - invoiceMap.amountApplied = invoiceApplied; - invoicesList.add(invoiceMap); - } - } - context.invoicesOtherCurrency = invoicesList; -} Modified: ofbiz/trunk/applications/accounting/webapp/accounting/payment/PaymentForms.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/webapp/accounting/payment/PaymentForms.xml?rev=701022&r1=701021&r2=701022&view=diff ============================================================================== --- ofbiz/trunk/applications/accounting/webapp/accounting/payment/PaymentForms.xml (original) +++ ofbiz/trunk/applications/accounting/webapp/accounting/payment/PaymentForms.xml Thu Oct 2 00:33:43 2008 @@ -57,9 +57,7 @@ </service> </actions> <row-actions> - <set field="amountToApply" value="${bsh: - import java.text.NumberFormat; - return(NumberFormat.getNumberInstance(context.get("locale")).format(org.ofbiz.accounting.payment.PaymentWorker.getPaymentNotAppliedBd(delegator,paymentId)));}"/> + <set field="amountToApply" value="${bsh:org.ofbiz.accounting.payment.PaymentWorker.getPaymentNotAppliedBd(delegator,paymentId);}"/> </row-actions> <field name="paymentId" widget-style="buttontext"> <hyperlink description="${paymentId}" target="paymentOverview?paymentId=${paymentId}"/> @@ -310,7 +308,7 @@ <field name="paymentId"><hidden/></field> <field name="invoiceId" widget-style="buttontext"><hyperlink target="invoiceOverview?invoiceId=${invoiceId}" description="${invoiceId}"/></field> <field name="description"><display/></field> - <field name="invoiceDate"><display/></field> + <field name="invoiceDate"><display type="date"/></field> <field name="amount"><display type="currency" currency="${currencyUomId}"/></field> <field name="amountApplied" parameter-name="dummy"><display type="currency" currency="${currencyUomId}"/></field> <field name="amountToApply" parameter-name="amountApplied"><text size="10"/></field> @@ -321,20 +319,7 @@ </field> </form> - <form name="listInvoicesNotAppliedOtherCurrency" type="list" list-name="invoicesOtherCurrency" target="updatePaymentApplication" title="" - odd-row-style="alternate-row" default-table-style="basic-table hover-bar"> - <field name="paymentId"><hidden/></field> - <field name="invoiceId" widget-style="buttontext"><hyperlink target="invoiceOverview?invoiceId=${invoiceId}" description="${invoiceId}"/></field> - <field name="description"><display/></field> - <field name="invoiceDate"><display/></field> - <field name="amount"><display type="currency" currency="${currencyUomId}"/></field> - <field name="amountApplied" parameter-name="dummy"><display type="currency" currency="${currencyUomId}"/></field> - <field name="invoiceProcessing" use-when=""${uiConfigMap.invoiceProcessing}".equals("Y")"><check/></field> - <field name="invoiceProcessing" use-when=""${uiConfigMap.invoiceProcessing}".equals("N")"><check/></field> - <field name="applyButton" widget-style="smallSubmit" title="Convert Invoice to Payment currency and save rate"> - <submit button-type="button"/> - </field> - </form> + <form name="listInvoicesNotAppliedOtherCurrency" extends="listInvoicesNotApplied" list-name="invoicesOtherCurrency"/> <form name="listPaymentsNotApplied" type="list" list-name="payments" target="updatePaymentApplication" title="" odd-row-style="alternate-row" default-table-style="basic-table hover-bar"> @@ -416,6 +401,9 @@ <order-by field-name="invoiceItemSeqId"/> </entity-condition> </actions> + <row-actions> + <set field="amountApplied" value="${bsh:org.ofbiz.accounting.payment.PaymentWorker.getPaymentAppliedAmount(delegator, paymentApplicationId);}"/> + </row-actions> <auto-fields-entity entity-name="PaymentApplication" default-field-type="display"/> <field name="paymentApplicationId"><hidden/></field> <field name="paymentId"><hidden/></field> |
Free forum by Nabble | Edit this page |