This is an automated email from the ASF dual-hosted git repository. nmalin pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push: new a380a7846e Improved: Convert InvoiceServices.xml from mini-lang to Groovy (OFBIZ-13085) a380a7846e is described below commit a380a7846ec95f293052014b30de935ee6fc4b00 Author: Nicolas Malin <nicolas.ma...@nereide.fr> AuthorDate: Tue May 7 15:21:05 2024 +0200 Improved: Convert InvoiceServices.xml from mini-lang to Groovy (OFBIZ-13085) Convert following services to groovy : * createInvoice * copyInvoice * getInvoice * updateInvoice * setInvoiceStatus * copyInvoiceToTemplate * checkInvoiceStatusInProgress * createInvoiceItem * updateInvoiceItem * removeInvoiceItem * sendInvoicePerEmail * autoGenerateInvoiceFromExistingInvoice * cancelInvoice * getInvoiceRunningTotal * addTaxOnInvoice * getInvoicesFilterByAssocType * removeInvoiceItemAssocOnCancelInvoice * resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice * massChangeInvoiceStatus * createInvoiceFromOrder * isInvoiceInForeignCurrency * removePaymentApplication (move to payment package) These services to entity-auto : * createInvoiceRole * removeInvoiceRole * createInvoiceTerm * createInvoiceContent * updateInvoiceContent Introduce new services : * checkInvoiceStatusInProgress * createInvoiceContentAndUpdateContent * updateInvoiceContentAndContent checkInvoiceStatusInProgress have been added as permission service to autorize or not edit service on invoice. createInvoiceContentAndUpdateContent and updateInvoiceContentAndContent have be added to manage both entity InvoiceContent and Content, and let createInvoiceContent and updateInvoiceContent as crud service --- .../accounting/config/AccountingUiLabels.xml | 22 +- .../minilang/invoice/InvoiceServices.xml | 895 --------------------- .../accounting/servicedef/services_invoice.xml | 339 ++++---- .../accounting/servicedef/services_payment.xml | 4 +- .../accounting/AutoAcctgInvoiceTests.groovy | 7 +- .../accounting/InvoicePerShipmentTests.groovy | 2 +- .../invoice/InvoiceServicesScript.groovy | 530 +++++++++++- .../accounting/payment/PaymentServices.groovy | 60 ++ .../webapp/accounting/WEB-INF/controller.xml | 2 +- 9 files changed, 779 insertions(+), 1082 deletions(-) diff --git a/applications/accounting/config/AccountingUiLabels.xml b/applications/accounting/config/AccountingUiLabels.xml index 3d3e4ddf7c..f4e0391f49 100644 --- a/applications/accounting/config/AccountingUiLabels.xml +++ b/applications/accounting/config/AccountingUiLabels.xml @@ -8500,17 +8500,17 @@ <value xml:lang="zh-TW">發票[${invoiceId}]金額合計為0....無法應用...</value> </property> <property key="AccountingInvoiceUpdateOnlyWithInProcessStatus"> - <value xml:lang="ar">يمكن تحديث الفاتورة فقط عندما تكون الحالة قيد الإنجاز... الحالة الحالية: ${lookedUpValue.statusId}</value> - <value xml:lang="de">Kann nur Rechnungen im Status "in Bearbeitung" aktualisieren... aktueller Status: ${lookedUpValue.statusId}</value> - <value xml:lang="en">Can only update Invoice, when status is in-process...current status: ${lookedUpValue.statusId}</value> - <value xml:lang="es">Sólo puede actualizar la factura, cuando el estado está 'En Proceso'. Estado actual: ${lookedUpValue.statusId}</value> - <value xml:lang="fr">Il n'est possible de mettre à jour une facture que si son statut est "en cours", actuellement il est ${lookedUpValue.statusId}</value> - <value xml:lang="it">La fattura può essere aggiornata solo quando lo stato è in-corso...stato attuale: ${lookedUpValue.statusId}</value> - <value xml:lang="ja">処理中の請求書のみ更新可能です...現在のステータス: ${lookedUpValue.statusId}</value> - <value xml:lang="pt">Só é possível atualizar fatura quando o estado é "em processo"... estado atual: ${lookedUpValue.statusId}</value> - <value xml:lang="vi">Chỉ có thể cập nhật Hóa đơn khi trạng thái là 'Đang xử lý'... trạng thái hiện tại là: ${lookedUpValue.statusId}</value> - <value xml:lang="zh">只有在状态为处理中(in-process)时才能更新发票(Invoice),当前状态:${lookedUpValue.statusId}</value> - <value xml:lang="zh-TW">只有在狀態為處理中(in-process)時才能更新發票(Invoice),目前狀態:${lookedUpValue.statusId}</value> + <value xml:lang="ar">يمكن تحديث الفاتورة فقط عندما تكون الحالة قيد الإنجاز... الحالة الحالية: ${statusId}</value> + <value xml:lang="de">Kann nur Rechnungen im Status "in Bearbeitung" aktualisieren... aktueller Status: ${statusId}</value> + <value xml:lang="en">Can only update Invoice, when status is in-process...current status: ${statusId}</value> + <value xml:lang="es">Sólo puede actualizar la factura, cuando el estado está 'En Proceso'. Estado actual: ${statusId}</value> + <value xml:lang="fr">Il n'est possible de mettre à jour une facture que si son statut est "en cours", actuellement il est ${statusId}</value> + <value xml:lang="it">La fattura può essere aggiornata solo quando lo stato è in-corso...stato attuale: ${statusId}</value> + <value xml:lang="ja">処理中の請求書のみ更新可能です...現在のステータス: ${statusId}</value> + <value xml:lang="pt">Só é possível atualizar fatura quando o estado é "em processo"... estado atual: ${statusId}</value> + <value xml:lang="vi">Chỉ có thể cập nhật Hóa đơn khi trạng thái là 'Đang xử lý'... trạng thái hiện tại là: ${statusId}</value> + <value xml:lang="zh">只有在状态为处理中(in-process)时才能更新发票(Invoice),当前状态:${statusId}</value> + <value xml:lang="zh-TW">只有在狀態為處理中(in-process)時才能更新發票(Invoice),目前狀態:${statusId}</value> </property> <property key="AccountingInvoices"> <value xml:lang="ar">الفواتير</value> diff --git a/applications/accounting/minilang/invoice/InvoiceServices.xml b/applications/accounting/minilang/invoice/InvoiceServices.xml deleted file mode 100644 index 166b166d24..0000000000 --- a/applications/accounting/minilang/invoice/InvoiceServices.xml +++ /dev/null @@ -1,895 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. ---> - -<simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd"> - - <simple-method method-name="createInvoice" short-description="Create a new Invoice"> - <now-timestamp field="nowTimestamp"/> - - <make-value entity-name="Invoice" value-field="newEntity"/> - - <!-- call getNextInvoiceId service with the parameters.partyIdFrom when invoice Id is not suplied - else use it from the input --> - <if-empty field="parameters.invoiceId"> - <set-service-fields service-name="getNextInvoiceId" map="parameters" to-map="getNextInvoiceIdMap"/> - <set field="getNextInvoiceIdMap.partyId" from-field="parameters.partyIdFrom"/> - <call-service service-name="getNextInvoiceId" in-map-name="getNextInvoiceIdMap"> - <result-to-field result-name="invoiceId" field="parameters.invoiceId"/> - </call-service> - </if-empty> - <field-to-result field="parameters.invoiceId" result-name="invoiceId"/> - - <!-- set the invoice date if not provided --> - <if-empty field="parameters.invoiceDate"> - <set from-field="nowTimestamp" field="parameters.invoiceDate"/> - </if-empty> - - <!-- set the invoice status if not provided --> - <if-empty field="parameters.statusId"> - <set field="parameters.statusId" value="INVOICE_IN_PROCESS"/> - </if-empty> - - <!-- use currency of receiving company --> - <entity-one entity-name="Party" value-field="party"/> - <if-not-empty field="party.preferredCurrencyUomId"> - <set field="parameters.currencyUomId" from-field="party.preferredCurrencyUomId"/> - </if-not-empty> - - <set-nonpk-fields map="parameters" value-field="newEntity"/> - <set-pk-fields map="parameters" value-field="newEntity"/> - <create-value value-field="newEntity"/> - - <!-- create new status entry, and set lastStatusUpdate date --> - <set field="createInvoiceStatusMap.invoiceId" from-field="newEntity.invoiceId" /> - <set field="createInvoiceStatusMap.statusId" from-field="newEntity.statusId" /> - <call-service service-name="createInvoiceStatus" in-map-name="createInvoiceStatusMap"/> - </simple-method> - - <simple-method method-name="copyInvoice" short-description="Create a new Invoice from an existing invoice"> - <set field="invoiceLookup.invoiceId" from-field="parameters.invoiceIdToCopyFrom"/> - <call-service service-name="getInvoice" in-map-name="invoiceLookup"> - <result-to-field result-name="invoice" field="invoice"/> - <result-to-field result-name="invoiceItems" field="invoiceItems"/> - </call-service> - <set field="invoice.invoiceId" from-field="parameters.invoiceId"/> - <now-timestamp field="nowTimestamp"/> - <set field="invoice.invoiceDate" from-field="nowTimestamp"/> - <set field="invoice.statusId" value="INVOICE_IN_PROCESS"/> - <if-not-empty field="parameters.invoiceTypeId"> - <set field="invoice.invoiceTypeId" from-field="parameters.invoiceTypeId"/> - </if-not-empty> - <set-service-fields service-name="createInvoice" map="invoice" to-map="newInvoice"/> - <clear-field field="newInvoice.invoiceId"/> - <call-service service-name="createInvoice" in-map-name="newInvoice"> - <result-to-field result-name="invoiceId" field="invoiceId"/> - </call-service> - <field-to-result field="invoiceId" result-name="invoiceId"/> - <field-to-request field="invoiceId" request-name="invoiceId"/> - <iterate list="invoiceItems" entry="invoiceItem"> - <set-service-fields service-name="createInvoiceItem" map="invoiceItem" to-map="createInvoiceItem"/> - <set field="createInvoiceItem.invoiceId" from-field="invoiceId"/> - <call-service service-name="createInvoiceItem" in-map-name="createInvoiceItem"/> - </iterate> - </simple-method> - - <simple-method method-name="getInvoice" short-description="Retrieve an invoice and the items"> - <!-- find the invoice record --> - <make-value entity-name="Invoice" value-field="lookupPKMap"/> - <set-pk-fields map="parameters" value-field="lookupPKMap"/> - <find-by-primary-key entity-name="Invoice" map="lookupPKMap" value-field="invoiceValue"/> - <field-to-result field="invoiceValue" result-name="invoice"/> - <!-- and the items --> - <get-related value-field="invoiceValue" relation-name="InvoiceItem" list="invoiceItemValues"/> - <field-to-result field="invoiceItemValues" result-name="invoiceItems"/> - </simple-method> - - <simple-method method-name="updateInvoice" short-description="Update the header of an existing Invoice"> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - <!-- find the current record --> - <make-value entity-name="Invoice" value-field="lookupPKMap"/> - <set-pk-fields map="parameters" value-field="lookupPKMap"/> - <find-by-primary-key entity-name="Invoice" map="lookupPKMap" value-field="lookedUpValue"/> - - <!-- only try to update content if the status is in process.... --> - <if-compare field="lookedUpValue.statusId" operator="equals" value="INVOICE_IN_PROCESS"> - <clone-value value-field="lookedUpValue" new-value-field="savedValue"/> - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> - - <!-- only save if something has changed, do not update status here --> - <set from-field="savedValue.statusId" field="lookedUpValue.statusId"/> <!-- get old status back --> - <if-compare-field field="lookedUpValue" to-field="savedValue" operator="not-equals" type="Object"> - <store-value value-field="lookedUpValue"/> <!-- update all non status and key fields --> - </if-compare-field> - <else> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceUpdateOnlyWithInProcessStatus"/> - </add-error> - <log level="error" message="Can only update Invoice, when status is in-process...current Status: ${lookedUpValue.statusId}"/> - <check-errors/> - </else> - </if-compare> - - <!-- check if there is a requested status change if yes call invoice status update service --> - <if-not-empty field="parameters.statusId"> - <if-compare-field field="parameters.statusId" to-field="savedValue.statusId" operator="not-equals"> - <set from-field="parameters.invoiceId" field="inputMap.invoiceId"/> - <set from-field="parameters.statusId" field="inputMap.statusId"/> - <now-timestamp field="inputMap.statusDate"/> - <call-service service-name="setInvoiceStatus" in-map-name="inputMap"/> - </if-compare-field> - </if-not-empty> - </simple-method> - - <simple-method method-name="sendInvoicePerEmail" short-description="Send an invoice per Email"> - <set-service-fields service-name="sendMailFromScreen" map="parameters" to-map="emailParams"/> - <set field="emailParams.xslfoAttachScreenLocation" value="component://accounting/widget/AccountingPrintScreens.xml#InvoicePDF"/> - <set field="emailParams.bodyParameters.invoiceId" from-field="parameters.invoiceId"/> - <set field="emailParams.bodyParameters.userLogin" from-field="parameters.userLogin"/> - <set field="emailParams.bodyParameters.other" from-field="parameters.other"/><!-- to to print in 'other currency' --> - <call-service-asynch service-name="sendMailFromScreen" in-map-name="emailParams"/> - <property-to-field resource="AccountingUiLabels" property="AccountingEmailScheduledToSend" field="successMessage"/> - </simple-method> - - <simple-method method-name="createInvoiceItem" short-description="Create a new Invoice Item"> - <set field="invoiceId" from-field="parameters.invoiceId"/> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - <make-value entity-name="InvoiceItem" value-field="newEntity"/> - <set-pk-fields map="parameters" value-field="newEntity"/> - <set-nonpk-fields map="parameters" value-field="newEntity"/> - <if-empty field="newEntity.invoiceItemSeqId"> - <make-next-seq-id value-field="newEntity" seq-field-name="invoiceItemSeqId"/> <!-- this finds the next sub-sequence ID --> - <field-to-result field="newEntity.invoiceItemSeqId" result-name="invoiceItemSeqId"/> - </if-empty> - <!-- if there is no amount and a productItem is supplied fill the amount(price) and description from the product record - TODO: there are return adjustments now that make this code very broken. The check for price was added as a quick fix. --> - <if-empty field="parameters.amount"> - <if-not-empty field="parameters.productId"> - <entity-one entity-name="Product" value-field="product"/> - <set from-field="product.description" field="newEntity.description"/> - <set from-field="product" field="calculateProductPriceMap.product"/> - <call-service service-name="calculateProductPrice" in-map-name="calculateProductPriceMap"> - <result-to-field result-name="price" field="newEntity.amount"/> - </call-service> - </if-not-empty> - </if-empty> - <if-not-empty field="parameters.productId"> - <if-empty field="parameters.quantity"> - <set field="newEntity.quantity" value="1.0" type="BigDecimal"/> - </if-empty> - </if-not-empty> - <if-empty field="newEntity.amount"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceAmountIsMandatory"/> - </add-error> - </if-empty> - <create-value value-field="newEntity"/> - </simple-method> - <simple-method method-name="updateInvoiceItem" - short-description="Update an existing Invoice Item"> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - <make-value entity-name="InvoiceItem" value-field="lookupPKMap"/> - <set-pk-fields map="parameters" value-field="lookupPKMap"/> - - <find-by-primary-key entity-name="InvoiceItem" map="lookupPKMap" value-field="lookedUpValue"/> - <clone-value value-field="lookedUpValue" new-value-field="savedValue"/> - - <!-- set all parameters --> - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> - - <!-- check if the productNumber is updated, when yes retrieve product description and price --> - <if-not-empty field="productId"> - <if-compare-field to-field="lookedUpValue.productId" field="savedValue.productId" operator="not-equals"> - <entity-one entity-name="Product" value-field="product"/> - <set from-field="product.description" field="lookedUpValue.description"/> - - <set from-field="product" field="calculateProductPriceMap.product"/> - <call-service service-name="calculateProductPrice" in-map-name="calculateProductPriceMap"> - <result-to-field result-name="price" field="lookedUpValue.amount"/> - </call-service> - </if-compare-field> - </if-not-empty> - <if-empty field="newEntity.amount"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceAmountIsMandatory"/> - </add-error> - </if-empty> - <if-compare-field field="lookedUpValue" to-field="savedValue" operator="not-equals" type="Object"> - <store-value value-field="lookedUpValue"/> - </if-compare-field> - <field-to-result field="lookedUpValue.invoiceItemSeqId" result-name="invoiceItemSeqId"/> - <field-to-result field="lookedUpValue.invoiceId" result-name="invoiceId"/> - </simple-method> - <simple-method method-name="removeInvoiceItem" short-description="Remove an existing Invoice Item"> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - <set field="invoiceId" from-field="parameters.invoiceId"/> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - - <set field="paymentApplicationMap.invoiceId" from-field="parameters.invoiceId"/> - <set field="paymentApplicationMap.invoiceItemSeqId" from-field="parameters.invoiceItemSeqId"/> - <if-not-empty field="parameters.invoiceItemSeqId"> - <!-- check if there are specific item paymentApplications when yes remove those --> - <remove-by-and entity-name="PaymentApplication" map="paymentApplicationMap"/> - <else><!-- update global application with a null sequence number --> - <!-- TODO: reduce amount on global paymentApplication record --> - </else> - </if-not-empty> - - <entity-one entity-name="InvoiceItem" value-field="lookedUpValue"/> - <remove-value value-field="lookedUpValue"/> - </simple-method> - - <simple-method method-name="removePaymentApplication" short-description="Remove an existing payment application"> - <entity-one entity-name="PaymentApplication" value-field="paymentApplication"> - <field-map field-name="paymentApplicationId" value="${parameters.paymentApplicationId}"/> - </entity-one> - <if-empty field="paymentApplication"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingPaymentApplicationNotFound"/> - </add-error> - <check-errors/> - </if-empty> - <!-- payment --> - <set field="currencyUomId" value=""/><!-- currency of the paymentApplication --> - <if-not-empty field="paymentApplication.paymentId"> - <entity-one entity-name="Payment" value-field="payment"> - <field-map field-name="paymentId" value="${paymentApplication.paymentId}"/> - </entity-one> - <if-not-empty field="payment"> - <if-compare field="payment.statusId" operator="equals" value="PMNT_CONFIRMED"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingPaymentApplicationCannotRemovedWithConfirmedStatus"/> - </add-error> - </if-compare> - <check-errors/> - </if-not-empty> - <field-to-result field="paymentApplication.paymentId" result-name="paymentId"/> - <set field="currencyUomId" from-field="paymentId.currencyUomId"/> - </if-not-empty> - <!-- check invoice --> - <if-not-empty field="paymentApplication.invoiceId"> - <entity-one entity-name="Invoice" value-field="invoice"> - <field-map field-name="invoiceId" value="${paymentApplication.invoiceId}"/> - </entity-one> - <if-empty field="invoice"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceNotFound"/> - </add-error> - <log level="info" message="Invoice not found, invoice Id: ${invoiceId}"/> - <check-errors/> - </if-empty> - <set field="currencyUomId" from-field="invoice.currencyUomId"/> - <!-- if the invoice is already PAID, then set it back to READY and clear out the paidDate --> - <if-compare field="invoice.statusId" operator="equals" value="INVOICE_PAID"> - <set field="invoiceStatusMap.invoiceId" value="${paymentApplication.invoiceId}"/> - <set field="invoiceStatusMap.statusId" value="INVOICE_READY"/> - <call-service service-name="setInvoiceStatus" in-map-name="invoiceStatusMap"/> - </if-compare> - <check-errors/> - <field-to-result field="paymentApplication.invoiceId" result-name="invoiceId"/> - <property-to-field resource="AccountingUiLabels" property="AccountingPaymentApplToInvoice" field="toMessage"/> - </if-not-empty> - <!-- invoice item --> - <if-not-empty field="paymentApplication.invoiceItemSeqId"> - <field-to-result field="paymentApplication.invoiceItemSeqId" result-name="invoiceItemSeqId"/> - <property-to-field resource="AccountingUiLabels" property="AccountingApplicationToInvoiceItem" field="toMessage"/> - </if-not-empty> - <!-- toPayment --> - <if-not-empty field="paymentApplication.toPaymentId"> - <entity-one entity-name="Payment" value-field="toPayment"> - <field-map field-name="paymentId" value="${paymentApplication.toPaymentId}"/> - </entity-one> - <if-not-empty field="toPayment"> - <if-compare field="toPayment.statusId" operator="equals" value="PMNT_CONFIRMED"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingPaymentApplicationCannotRemovedWithConfirmedStatus"/> - </add-error> - </if-compare> - <check-errors/> - </if-not-empty> - <property-to-field resource="AccountingUiLabels" property="AccountingPaymentApplToPayment" field="toMessage"/> - <field-to-result field="paymentApplication.toPaymentId" result-name="toPaymentId"/> - </if-not-empty> - <!-- billing account --> - <if-not-empty field="paymentApplication.billingAccountId"> - <field-to-result field="paymentApplication.billingAccountId" result-name="billingAccountId"/> - <property-to-field resource="AccountingUiLabels" property="AccountingPaymentApplToBillingAccount" field="toMessage"/> - <entity-one entity-name="BillingAccount" value-field="billingAccount"> - <field-map field-name="billingAccountId" from-field="paymentApplication.billingAccountId"/> - </entity-one> - <set field="currencyUomId" from-field="billingAccount.accountCurrencyUomId"/> - </if-not-empty> - <!-- tax authority --> - <if-not-empty field="paymentApplication.taxAuthGeoId"> - <field-to-result field="paymentApplication.taxAuthGeoId" result-name="taxAuthGeoId"/> - <property-to-field resource="AccountingUiLabels" property="AccountingPaymentApplToTaxAuth" field="toMessage"/> - </if-not-empty> - <!-- finally delete application --> - <property-to-field resource="AccountingUiLabels" property="AccountingPaymentApplRemoved" field="successMessage"/> - <string-append field="successMessage" string=" ${toMessage}"/> - <remove-value value-field="paymentApplication"/> - </simple-method> - - <simple-method method-name="createInvoiceRole" short-description="Create a Invoice Role"> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - <make-value entity-name="InvoiceRole" value-field="newEntity"/> - <set-nonpk-fields map="parameters" value-field="newEntity"/> - <set-pk-fields map="parameters" value-field="newEntity"/> - <if-empty field="newEntity.datetimePerformed"><now-timestamp field="newEntity.datetimePerformed"/></if-empty> - <create-value value-field="newEntity"/> - </simple-method> - - <simple-method method-name="removeInvoiceRole" short-description="Remove existing Invoice Role"> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - <entity-one entity-name="InvoiceRole" value-field="lookedUpValue"/> - <remove-value value-field="lookedUpValue"/> - </simple-method> - - <simple-method method-name="setInvoiceStatus" short-description="Set The Invoice Status"> - <entity-one entity-name="Invoice" value-field="invoice"/> - <field-to-result field="invoice.statusId" result-name="oldStatusId"/> - <field-to-result field="invoice.invoiceTypeId" result-name="invoiceTypeId"/> - <if-compare-field field="invoice.statusId" to-field="parameters.statusId" operator="not-equals"> - <entity-one entity-name="StatusValidChange" value-field="statusChange" auto-field-map="false"> - <field-map field-name="statusId" from-field="invoice.statusId"/> - <field-map field-name="statusIdTo" from-field="parameters.statusId"/> - </entity-one> - <if-empty field="statusChange"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingPSInvalidStatusChange"/> - </add-error> - <log level="error" message="Cannot change from ${invoice.statusId} to ${parameters.statusId}"/> - <check-errors/> - <else> - <!-- if new status is paid check if the complete invoice is applied. --> - <if-compare field="parameters.statusId" operator="equals" value="INVOICE_PAID"> - <set field="notApplied" type="BigDecimal" value="${groovy:org.apache.ofbiz.accounting.invoice.InvoiceWorker.getInvoiceNotApplied(invoice)}"/> - <if-compare field="notApplied" operator="not-equals" value="0.00" type="BigDecimal"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceCannotChangeStatusToPaid"/> - </add-error> - <check-errors/> - </if-compare> - - <!-- if it's OK to mark invoice paid, use parameter for paidDate --> - <if-empty field="parameters.paidDate"> - <now-timestamp field="nowTimestamp"/> - <set from-field="nowTimestamp" field="invoice.paidDate"/> - <else> - <set from-field="parameters.paidDate" field="invoice.paidDate"/> - </else> - </if-empty> - </if-compare> - - <if-not-empty field="invoice.paidDate"> - <if-compare field="parameters.statusId" operator="equals" value="INVOICE_READY"> - <clear-field field="invoice.paidDate"/> - </if-compare> - </if-not-empty> - - <set from-field="parameters.statusId" field="invoice.statusId"/> - <store-value value-field="invoice"/> - - <set field="createInvoiceStatusMap.invoiceId" from-field="invoice.invoiceId"/> - <set field="createInvoiceStatusMap.statusId" from-field="invoice.statusId"/> - <set field="createInvoiceStatusMap.statusDate" from-field="parameters.statusDate"/> - <call-service service-name="createInvoiceStatus" in-map-name="createInvoiceStatusMap"/> - - <!-- if the invoice is a payrol invoice, create the payment in the not-paid status --> - <if-compare field="invoice.invoiceTypeId" operator="equals" value="PAYROL_INVOICE"> - <if> - <condition> - <or> - <if-compare field="parameters.statusId" operator="equals" value="INVOICE_APPROVED"/> - <if-compare field="parameters.statusId" operator="equals" value="INVOICE_READY"/> - </or> - </condition> - <then> - <!-- only generate payment if no application exist yet --> - <entity-and entity-name="PaymentApplication" list="paymentApplications"> - <field-map field-name="invoiceId" from-field="parameters.invoiceId"/> - </entity-and> - <if-empty field="paymentApplications"> - <set field="newp.partyIdFrom" from-field="invoice.partyId"/> - <set field="newp.partyIdTo" from-field="invoice.partyIdFrom"/> - <set field="newp.paymentMethodTypeId" value="COMPANY_CHECK"/> - <set field="newp.paymentTypeId" value="PAYROL_PAYMENT"/> - <set field="newp.statusId" value="PMNT_NOT_PAID"/> - <set field="newp.currencyUomId" from-field="invoice.currencyUomId"/> - <call-class-method class-name="org.apache.ofbiz.accounting.invoice.InvoiceWorker" method-name="getInvoiceTotal" ret-field="newp.amount"> - <field field="invoice" type="GenericValue"/> - </call-class-method> - <call-service service-name="createPayment" in-map-name="newp"> - <result-to-field result-name="paymentId" field="payment.paymentId"/> - </call-service> - <set field="payAppl.invoiceId" from-field="invoice.invoiceId"/> - <set field="payAppl.paymentId" from-field="payment.paymentId"/> - <set field="payAppl.amountApplied" from-field="newp.amount"/> - <call-service service-name="createPaymentApplication" in-map-name="payAppl"/> - </if-empty> - </then> - </if> - </if-compare> - </else> - </if-empty> - </if-compare-field> - </simple-method> - - <simple-method method-name="createInvoiceTerm" short-description="Create a Invoice Term"> - <call-simple-method method-name="checkInvoiceStatusInProgress"/> - - <make-value entity-name="InvoiceTerm" value-field="newEntity"/> - <set-nonpk-fields map="parameters" value-field="newEntity"/> - - <sequenced-id sequence-name="InvoiceTerm" field="newEntity.invoiceTermId"/> - <field-to-result field="newEntity.invoiceTermId" result-name="invoiceTermId"/> - - <create-value value-field="newEntity"/> - </simple-method> - - <simple-method method-name="copyInvoiceToTemplate" short-description="copy a invoice to a InvoiceType starting with 'template'"> - <set field="parameters.invoiceIdToCopyFrom" from-field="parameters.invoiceId"/> - <if-compare field="parameters.invoiceTypeId" operator="equals" value="SALES_INVOICE"> - <set field="parameters.invoiceTypeId" value="SALES_INV_TEMPLATE"/> - </if-compare> - <if-compare field="parameters.invoiceTypeId" operator="equals" value="PURCHASE_INVOICE"> - <set field="parameters.invoiceTypeId" value="PUR_INV_TEMPLATE"/> - </if-compare> - <call-simple-method method-name="copyInvoice"/> - </simple-method> - - <!-- ===============subroutine services =================--> - <simple-method method-name="checkInvoiceStatusInProgress" short-description="Check if the invoiceStatus is in progress"> - <!-- find the current header record --> - <entity-one entity-name="Invoice" value-field="headerValue"/> - <if-empty field="headerValue"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceNotFound"/> - </add-error> - <log level="info" message="Invoice not found, invoice Id: ${invoiceId}"/> - <check-errors/> - </if-empty> - <!-- check if the status is in progress... --> - <if-compare field="headerValue.statusId" operator="not-equals" value="INVOICE_IN_PROCESS"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceUpdateOnlyWithInProcessStatus"/> - </add-error> - <log level="info" message="Can only update Invoice, when status is in-process...is now: ${headerValue.statusId}"/> - </if-compare> - <check-errors/> - </simple-method> - - <simple-method method-name="autoGenerateInvoiceFromExistingInvoice" short-description="Scheduled service to generate Invoice from an existing Invoice"> - <entity-and entity-name="Invoice" list="invoices"> - <field-map field-name="recurrenceInfoId" from-field="parameters.recurrenceInfoId"/> - </entity-and> - <iterate list="invoices" entry="invoice"> - <set-service-fields service-name="copyInvoice" map="invoice" to-map="copyInvoiceCtx"/> - <set field="copyInvoiceCtx.invoiceIdToCopyFrom" from-field="invoice.invoiceId"/> - <call-service service-name="copyInvoice" in-map-name="copyInvoiceCtx"> - <result-to-field result-name="invoiceId" field="invoiceId"/> - </call-service> - <set-service-fields service-name="updateInvoice" map="invoice" to-map="updateInvoiceCtx"/> - <set field="updateInvoiceCtx.invoiceId" from-field="invoiceId"/> - <if-compare field="updateInvoiceCtx.invoiceTypeId" operator="equals" value="SALES_INV_TEMPLATE"> - <set field="updateInvoiceCtx.invoiceTypeId" value="SALES_INVOICE"/> - </if-compare> - <if-compare field="updateInvoiceCtx.invoiceTypeId" operator="equals" value="PUR_INV_TEMPLATE"> - <set field="updateInvoiceCtx.invoiceTypeId" value="PURCHASE_INVOICE"/> - </if-compare> - <clear-field field="invoice"/> - <clear-field field="parameters.invoiceIdToCopyFrom"/> - <clear-field field="updateInvoiceCtx.recurrenceInfoId"/> - <call-service service-name="updateInvoice" in-map-name="updateInvoiceCtx"/> - </iterate> - </simple-method> - - <simple-method method-name="cancelInvoice" short-description="Service to cancel the Invoices"> - <entity-one entity-name="Invoice" value-field="invoice"/> - <if-empty field="invoice"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingInvoiceNotFound"/> - </add-error> - <check-errors/> - </if-empty> - <get-related relation-name="PaymentApplication" value-field="invoice" list="paymentApplications"/> - <iterate list="paymentApplications" entry="paymentApplication"> - <get-related-one relation-name="Payment" value-field="paymentApplication" to-value-field="payment"/> - <if-compare field="payment.statusId" operator="equals" value="PMNT_CONFIRMED"> - <set field="paymentStatusMap.paymentId" from-field="payment.paymentId"/> - <set field="isReceipt" value="${groovy:org.apache.ofbiz.accounting.util.UtilAccounting.isReceipt(payment)}" type="Boolean"/> - <set field="isDisbursement" value="${groovy:org.apache.ofbiz.accounting.util.UtilAccounting.isDisbursement(payment)}" type="Boolean"/> - <if-compare field="isReceipt" operator="equals" value="true" type="Boolean"> - <set field="paymentStatusMap.statusId" value="PMNT_RECEIVED"/> - <else> - <if-compare field="isDisbursement" operator="equals" value="true" type="Boolean"> - <set field="paymentStatusMap.statusId" value="PMNT_SENT"/> - </if-compare> - </else> - </if-compare> - <call-service service-name="setPaymentStatus" in-map-name="paymentStatusMap"/> - </if-compare> - <set field="removePaymentApplicationCtx.paymentApplicationId" from-field="paymentApplication.paymentApplicationId"/> - <call-service service-name="removePaymentApplication" in-map-name="removePaymentApplicationCtx"/> - </iterate> - <field-to-result field="invoice.invoiceTypeId" result-name="invoiceTypeId"/> - </simple-method> - - <simple-method method-name="getInvoiceRunningTotal" short-description="calculate running total for Invoices"> - <set field="invoiceIds" from-field="parameters.invoiceIds"/> - <set field="runningTotal" type="BigDecimal" value="0"/> - <entity-condition entity-name="Invoice" list="invoiceList"> - <condition-expr field-name="invoiceId" operator="in" from-field="invoiceIds"/> - </entity-condition> - <iterate list="invoiceList" entry="invoice"> - <set field="getInvoicePaymentInfoListCtx.invoiceId" from-field="invoice.invoiceId"/> - <call-service service-name="getInvoicePaymentInfoList" in-map-name="getInvoicePaymentInfoListCtx"> - <result-to-field result-name="invoicePaymentInfoList"/> - </call-service> - <first-from-list list="invoicePaymentInfoList" entry="invoicePaymentInfo"/> - <set field="runningTotal" value="${runningTotal + invoicePaymentInfo.outstandingAmount}" type="BigDecimal"/> - </iterate> - <set-service-fields service-name="getPartyAccountingPreferences" map="parameters" to-map="getPartyAccountingPreferencesMap"/> - <call-service service-name="getPartyAccountingPreferences" in-map-name="getPartyAccountingPreferencesMap"> - <result-to-field result-name="partyAccountingPreference"/> - </call-service> - <set field="currencyUomId" from-field="partyAccountingPreference.baseCurrencyUomId"/> - <if-empty field="currencyUomId"> - <property-to-field resource="general" property="currency.uom.id.default" field="currencyUomId"/> - </if-empty> - <set field="invoiceRunningTotal" value="${groovy:org.apache.ofbiz.base.util.UtilFormatOut.formatCurrency(runningTotal, currencyUomId, parameters.locale)}"/> - <field-to-result field="invoiceRunningTotal"/> - </simple-method> - - <simple-method method-name="getInvoicesFilterByAssocType" short-description="Filter invoices by invoiceItemAssocTypeId"> - <set field="invoiceList" from-field="parameters.invoiceList"/> - <set field="invoiceItemAssocTypeId" from-field="parameters.invoiceItemAssocTypeId"/> - <iterate list="invoiceList" entry="invoice"> - <entity-and entity-name="InvoiceItemAssoc" list="invoiceItemAssocList" filter-by-date="true"> - <field-map field-name="invoiceIdFrom" from-field="invoice.invoiceId"/> - <field-map field-name="invoiceItemAssocTypeId"/> - </entity-and> - <if-empty field="invoiceItemAssocList"> - <field-to-list field="invoice" list="filteredInvoiceList"/> - </if-empty> - </iterate> - <field-to-result field="filteredInvoiceList"/> - </simple-method> - - <simple-method method-name="removeInvoiceItemAssocOnCancelInvoice" short-description="Remove invoiceItemAssoc record on cancel invoice"> - <entity-and entity-name="InvoiceItemAssoc" list="invoiceItemAssocs"> - <field-map field-name="invoiceIdTo" from-field="parameters.invoiceId"/> - </entity-and> - <iterate list="invoiceItemAssocs" entry="invoiceItemAssoc"> - <set-service-fields service-name="deleteInvoiceItemAssoc" map="invoiceItemAssoc" to-map="deleteInvoiceItemAssocMap"/> - <call-service service-name="deleteInvoiceItemAssoc" in-map-name="deleteInvoiceItemAssocMap"/> - <log level="info" message="Removed invoiceItemAssoc: ${invoiceItemAssoc}"/> - </iterate> - </simple-method> - - <simple-method method-name="resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice" - short-description="Reset OrderItemBilling and OrderAdjustmentBilling records on cancel invoice, so it is isn't considered invoiced any more by createInvoiceForOrder service"> - <entity-and entity-name="OrderItemBilling" list="orderItemBillings"> - <field-map field-name="invoiceId" from-field="parameters.invoiceId"/> - </entity-and> - <iterate list="orderItemBillings" entry="orderItemBilling"> - <set field="orderItemBilling.quantity" value="0" type="BigDecimal"/> - <store-value value-field="orderItemBilling"/> - </iterate> - - <entity-and entity-name="OrderAdjustmentBilling" list="orderAdjustmentBillings"> - <field-map field-name="invoiceId" from-field="parameters.invoiceId"/> - </entity-and> - <iterate list="orderAdjustmentBillings" entry="orderAdjustmentBilling"> - <set field="orderAdjustmentBilling.amount" value="0" type="BigDecimal"/> - <store-value value-field="orderAdjustmentBilling"/> - </iterate> - </simple-method> - - <simple-method method-name="massChangeInvoiceStatus" short-description="Service set status of Invoices in bulk."> - <iterate list="parameters.invoiceIds" entry="invoiceId"> - <set field="setInvoiceStatusMap.invoiceId" from-field="invoiceId"/> - <set field="setInvoiceStatusMap.statusId" from-field="parameters.statusId"/> - <call-service service-name="setInvoiceStatus" in-map-name="setInvoiceStatusMap"/> - <clear-field field="setInvoiceStatusMap"/> - </iterate> - </simple-method> - - <simple-method method-name="addtax" short-description="Set Parameter And Call Tax Calculate Service"> - <entity-one entity-name="Invoice" value-field="invoice"> - <field-map field-name="invoiceId" from-field="parameters.invoiceId"/> - </entity-one> - <entity-and entity-name="InvoiceItem" list="invoiceItems"> - <field-map field-name="invoiceId" from-field="invoice.invoiceId"/> - </entity-and> - <entity-and entity-name="PartyContactMechPurpose" list="contacts"> - <field-map field-name="partyId" from-field="invoice.partyId"/> - <field-map field-name="contactMechPurposeTypeId" value="SHIPPING_LOCATION"/> - </entity-and> - <if-empty field="contacts"> - <entity-and entity-name="PartyContactMechPurpose" list="contacts"> - <field-map field-name="partyId" from-field="invoice.partyId"/> - <field-map field-name="contactMechPurposeTypeId" value="GENERAL_LOCATION"/> - </entity-and> - </if-empty> - <if-empty field="contacts"> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingTaxCannotCalculate"/> - </add-error> - </if-empty> - <first-from-list list="contacts" entry="contactMech"/> - <entity-one entity-name="PostalAddress" value-field="postalAddress"> - <field-map field-name="contactMechId" from-field="contactMech.contactMechId"/> - </entity-one> - <if-compare field="invoice.invoiceTypeId" value="SALES_INVOICE" operator="equals"> - <set field="addtaxMap.billToPartyId" from-field="invoice.partyId"/> - </if-compare> - <if-compare field="invoice.invoiceTypeId" value="PURCHASE_INVOICE" operator="equals"> - <set field="addtaxMap.billToPartyId" from-field="invoice.partyIdFrom"/> - </if-compare> - <set field="addtaxMap.payToPartyId" from-field="invoice.partyIdFrom"/> - <iterate list="invoiceItems" entry="invoiceItem"> - <entity-and entity-name="Product" list="product"> - <field-map field-name="productId" from-field="invoiceItem.productId"/> - </entity-and> - <first-from-list list="product" entry="itemProduct"/> - <if-not-empty field="invoiceItem.productId"> - <entity-and entity-name="InvoiceItem" list="findinvoiceItems"> - <field-map field-name="invoiceId" from-field="invoice.invoiceId"/> - <field-map field-name="productId" from-field="invoiceItem.productId"/> - <field-map field-name="invoiceItemTypeId" value="ITM_PROMOTION_ADJ"/> - </entity-and> - <if-not-empty field="findinvoiceItems"> - <calculate field="total" decimal-scale="${roundingDecimals}" rounding-mode="${roundingMode}" type="BigDecimal"> - <calcop operator="multiply"> - <calcop operator="get" field="invoiceItem.quantity"/> - <calcop operator="get" field="invoiceItem.amount"/> - </calcop> - </calculate> - <set field="totalAmount" from-field="total" type="BigDecimal"/> - <calculate field="totalAmount" decimal-scale="${roundingDecimals}" rounding-mode="${roundingMode}" type="BigDecimal"> - <calcop operator="subtract"> - <calcop operator="get" field="totalAmount"/> - <calcop operator="get" field="invoiceItem.amount"/> - </calcop> - </calculate> - <else> - <calculate field="total" decimal-scale="${roundingDecimals}" rounding-mode="${roundingMode}" type="BigDecimal"> - <calcop operator="multiply"> - <calcop operator="get" field="invoiceItem.quantity"/> - <calcop operator="get" field="invoiceItem.amount"/> - </calcop> - </calculate> - <set field="totalAmount" from-field="total" type="BigDecimal"/> - </else> - </if-not-empty> - <else> - <set field="totalAmount" value="0" type="BigDecimal"/> - </else> - </if-not-empty> - <set field="itemAmount" from-field="totalAmount" type="BigDecimal"/> - <set field="itemPrice" from-field="invoiceItem.amount" type="BigDecimal"/> - <set field="addtaxMap.itemProductList[]" from-field="itemProduct"/> - <set field="addtaxMap.itemAmountList[]" from-field="itemAmount" type="BigDecimal"/> - <set field="addtaxMap.itemPriceList[]" from-field="itemPrice" type="BigDecimal"/> - <set field="addtaxMap.itemQuantityList[]" from-field="invoiceItem.quantity" type="BigDecimal"/> - <set field="addtaxMap.itemShippingList[]" type="BigDecimal" value="0"/> - </iterate> - <set field="addtaxMap.orderShippingAmount" type="BigDecimal" value="0"/> - <set field="addtaxMap.orderPromotionsAmount" type="BigDecimal" value="0"/> - <set field="addtaxMap.shippingAddress" from-field="postalAddress"/> - <if> - <condition> - <not><if-empty field="addtaxMap.itemProductList"></if-empty></not> - </condition> - <then> - <call-service service-name="calcTax" in-map-name="addtaxMap"> - <result-to-field result-name="itemAdjustments" field="itemAdjustments"/> - <result-to-field result-name="orderAdjustments" field="orderAdjustments"/> - </call-service> - <iterate list="invoiceItems" entry="findItem"> - <if> - <condition> - <not><if-empty field="findItem.productId"></if-empty></not> - </condition> - <then> - <set field="invoiceItemSeqId" from-field="findItem.invoiceItemSeqId"/> - <set field="productId" from-field="findItem.productId"/> - <set field="itemMap.itemSeqIdList[]" from-field="invoiceItemSeqId"/> - <set field="itemMap.productList[]" from-field="productId"/> - </then> - </if> - </iterate> - <set field="countItemId" value="-1" type="Long"/> - <iterate list="itemAdjustments" entry="itemAdjustment"> - <calculate field="countItemId"> - <calcop operator="add" field="countItemId"> - <number value="1"/> - </calcop> - </calculate> - <if-not-empty field="itemAdjustment"> - <iterate list="itemAdjustment" entry="orderAdjustment"> - <set field="createInvoiceItemContext.invoiceId" from-field="invoice.invoiceId"/> - <if-compare field="invoice.invoiceTypeId" value="PURCHASE_INVOICE" operator="equals"> - <set field="createInvoiceItemContext.invoiceItemTypeId" value="PITM_SALES_TAX"/> - <else> - <set field="createInvoiceItemContext.invoiceItemTypeId" value="ITM_SALES_TAX"/> - </else> - </if-compare> - <set field="createInvoiceItemContext.overrideGlAccountId" from-field="orderAdjustment.overrideGlAccountId"/> - <set field="createInvoiceItemContext.productId" from-field="itemMap.productList[countItemId]"/> - <set field="createInvoiceItemContext.taxAuthPartyId" from-field="orderAdjustment.taxAuthPartyId"/> - <set field="createInvoiceItemContext.taxAuthGeoId" from-field="orderAdjustment.taxAuthGeoId"/> - <set field="createInvoiceItemContext.amount" from-field="orderAdjustment.amount" type="BigDecimal"/> - <set field="createInvoiceItemContext.quantity" value="1"/> - <set field="createInvoiceItemContext.parentInvoiceItemSeqId" from-field="itemMap.itemSeqIdList[countItemId]"/> - <set field="createInvoiceItemContext.taxAuthorityRateSeqId" from-field="orderAdjustment.taxAuthorityRateSeqId"/> - <set field="createInvoiceItemContext.description" from-field="orderAdjustment.comments"/> - <!--call createInvoiceItem service for every ItemAdjustment--> - <call-service service-name="createInvoiceItem" in-map-name="createInvoiceItemContext"></call-service> - </iterate> - </if-not-empty> - </iterate> - <iterate list="orderAdjustments" entry="Adjustment"> - <if-not-empty field="Adjustment"> - <set field="InvoiceItemContext.invoiceId" from-field="invoice.invoiceId"/> - <if-compare field="invoice.invoiceTypeId" value="PURCHASE_INVOICE" operator="equals"> - <set field="InvoiceItemContext.invoiceItemTypeId" value="PITM_SALES_TAX"/> - <else> - <set field="InvoiceItemContext.invoiceItemTypeId" value="ITM_SALES_TAX"/> - </else> - </if-compare> - <set field="InvoiceItemContext.overrideGlAccountId" from-field="Adjustment.overrideGlAccountId"/> - <set field="InvoiceItemContext.taxAuthPartyId" from-field="Adjustment.taxAuthPartyId"/> - <set field="InvoiceItemContext.taxAuthGeoId" from-field="Adjustment.taxAuthGeoId"/> - <set field="InvoiceItemContext.amount" from-field="Adjustment.amount" type="BigDecimal"/> - <set field="InvoiceItemContext.quantity" value="1"/> - <set field="InvoiceItemContext.taxAuthorityRateSeqId" from-field="Adjustment.taxAuthorityRateSeqId"/> - <!-- call createInvoiceItem service for every orderAdjustment --> - <call-service service-name="createInvoiceItem" in-map-name="InvoiceItemContext"></call-service> - </if-not-empty> - </iterate> - </then> - <else> - <add-error> - <fail-property resource="AccountingUiLabels" property="AccountingTaxProductIdCannotCalculate"/> - </add-error> - <log level="error" message="Cannot call calcTax service, when don't have productId"/> - <check-errors/> - </else> - </if> - </simple-method> - - <simple-method method-name="createInvoiceFromOrder" short-description="Create an invoice from existing order when invoicePerShipment is N"> - <entity-one entity-name="OrderHeader" value-field="orderHeader"> - <field-map field-name="orderId" from-field="parameters.orderId"/> - </entity-one> - <set field="invoicePerShipment" from-field="orderHeader.invoicePerShipment"/> - <if-empty field="invoicePerShipment"> - <property-to-field resource="accounting" property="create.invoice.per.shipment" field="invoicePerShipment"/> - </if-empty> - <if-compare operator="equals" value="N" field="invoicePerShipment"> - <entity-and entity-name="OrderItemBilling" list="orderItemBilling"> - <field-map field-name="orderId" from-field="parameters.orderId"/> - </entity-and> - <if-empty field="orderItemBilling"> - <set field="createInvoiceContext.orderId" from-field="parameters.orderId"/> - <call-service service-name="createInvoiceForOrderAllItems" in-map-name="createInvoiceContext"> - <result-to-field result-name="invoiceId" field="invoiceId"/> - </call-service> - <else> - <entity-and list="orderItems" entity-name="OrderItem"> - <field-map field-name="orderId" from-field="parameters.orderId"/> - <order-by field-name="orderItemSeqId"/> - </entity-and> - <iterate list="orderItems" entry="orderItem"> - <entity-and list="checkOrderItem" entity-name="OrderItemBilling"> - <field-map field-name="orderId" from-field="parameters.orderId"/> - <field-map field-name="orderItemSeqId" from-field="orderItem.orderItemSeqId"/> - </entity-and> - <if-empty field="checkOrderItem"> - <field-to-list list="billItems" field="orderItem"/> - </if-empty> - <set field="createInvoiceContext.orderId" from-field="parameters.orderId"/> - <set field="createInvoiceContext.billItems" from-field="billItems"/> - </iterate> - <call-service service-name="createInvoiceForOrder" in-map-name="createInvoiceContext"> - <result-to-field result-name="invoiceId" field="invoiceId"/> - </call-service> - </else> - </if-empty> - <field-to-result field="invoiceId" result-name="invoiceId"/> - </if-compare> - </simple-method> - - <!-- InvoiceContent --> - <simple-method method-name="createInvoiceContent" short-description="Create Content For Invoice"> - <make-value entity-name="InvoiceContent" value-field="newEntity"/> - <set-pk-fields map="parameters" value-field="newEntity"/> - <set-nonpk-fields map="parameters" value-field="newEntity"/> - - <if-empty field="newEntity.fromDate"> - <now-timestamp field="nowTimestamp"/> - <set field="newEntity.fromDate" from-field="nowTimestamp"/> - </if-empty> - - <create-value value-field="newEntity"/> - - <set-service-fields service-name="updateContent" map="parameters" to-map="updateContent"/> - <call-service service-name="updateContent" in-map-name="updateContent"/> - - <field-to-result field="newEntity.contentId" result-name="contentId"/> - <field-to-result field="newEntity.invoiceId" result-name="invoiceId"/> - <field-to-result field="newEntity.invoiceContentTypeId" result-name="invoiceContentTypeId"/> - </simple-method> - <simple-method method-name="updateInvoiceContent" short-description="Update Content For Invoice"> - <make-value entity-name="InvoiceContent" value-field="lookupPKMap"/> - <set-pk-fields map="parameters" value-field="lookupPKMap"/> - <find-by-primary-key map="lookupPKMap" value-field="lookedUpValue"/> - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> - <store-value value-field="lookedUpValue"/> - - <set-service-fields service-name="updateContent" map="parameters" to-map="updateContent"/> - <call-service service-name="updateContent" in-map-name="updateContent"/> - </simple-method> - - <simple-method method-name="createSimpleTextContentForInvoice" short-description="Create Simple Text Content For Invoice"> - <set-service-fields service-name="createInvoiceContent" map="parameters" to-map="createInvoiceContentMap"/> - <set-service-fields service-name="createSimpleTextContent" map="parameters" to-map="createSimpleTextMap"/> - <call-service service-name="createSimpleTextContent" in-map-name="createSimpleTextMap"> - <result-to-field result-name="contentId" field="createInvoiceContentMap.contentId"/> - </call-service> - <call-service service-name="createInvoiceContent" in-map-name="createInvoiceContentMap"/> - </simple-method> - <simple-method method-name="updateSimpleTextContentForInvoice" short-description="Update Simple Text Content For Invoice"> - <set-service-fields service-name="updateInvoiceContent" map="parameters" to-map="updateInvoiceContent"/> - <call-service service-name="updateInvoiceContent" in-map-name="updateInvoiceContent"/> - <set-service-fields service-name="updateSimpleTextContent" map="parameters" to-map="updateSimpleText"/> - <call-service service-name="updateSimpleTextContent" in-map-name="updateSimpleText"/> - </simple-method> - - <simple-method method-name="isInvoiceInForeignCurrency" short-description="check if a invoice is in a foreign currency related to the accounting company."> - <entity-one entity-name="InvoiceAndType" value-field="invoice"> - <field-map field-name="invoiceId" from-field="parameters.invoiceId"/> - </entity-one> - <if-empty field="invoice"> - <log level="error" message="Invoice not found"/> - <return/> - </if-empty> - <set field="isPurchaseInvoice" value="${groovy: org.apache.ofbiz.entity.util.EntityTypeUtil.hasParentType(delegator, 'InvoiceType', 'invoiceTypeId', invoice.getString('invoiceTypeId'), 'parentTypeId', 'PURCHASE_INVOICE')}" type="Boolean"/> - <set field="isSalesInvoice" value="${groovy: org.apache.ofbiz.entity.util.EntityTypeUtil.hasParentType(delegator, 'InvoiceType', 'invoiceTypeId', invoice.getString('invoiceTypeId'), 'parentTypeId', 'SALES_INVOICE')}" type="Boolean"/> - <if-compare field="isPurchaseInvoice" operator="equals" value="true" type="Boolean"> - <set field="pref.organizationPartyId" from-field="invoice.partyId"/> - </if-compare> - <if-compare field="isSalesInvoice" operator="equals" value="true" type="Boolean"> - <set field="pref.organizationPartyId" from-field="invoice.partyIdFrom"/> - </if-compare> - <call-service service-name="getPartyAccountingPreferences" in-map-name="pref"> - <result-to-field result-name="partyAccountingPreference"/> - </call-service> - <if-compare-field field="invoice.currencyUomId" operator="equals" to-field="partyAccountingPreference.baseCurrencyUomId"> - <set field="isForeign" value="false" type="Boolean"/> - <else> - <set field="isForeign" value="true" type="Boolean"/> - </else> - </if-compare-field> - <field-to-result field="isForeign"/> - </simple-method> -</simple-methods> diff --git a/applications/accounting/servicedef/services_invoice.xml b/applications/accounting/servicedef/services_invoice.xml index 4843691a02..bdfd7215f6 100644 --- a/applications/accounting/servicedef/services_invoice.xml +++ b/applications/accounting/servicedef/services_invoice.xml @@ -29,8 +29,8 @@ under the License. location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="getNextInvoiceId"> <description>Get the Next Invoice ID According to Settings on the PartyAcctgPreference Entity for the given Party</description> <implements service="createInvoice"/> - <attribute name="partyId" type="String" mode="IN" optional="false"/> - <attribute name="invoiceId" type="String" mode="OUT" optional="false"/> + <attribute name="partyId" type="String" mode="IN"/> + <attribute name="invoiceId" type="String" mode="OUT"/> </service> <service name="invoiceSequenceEnforced" engine="groovy" @@ -47,59 +47,68 @@ under the License. </service> <!-- Invoice services --> - <service name="createInvoice" engine="simple" default-entity-name="Invoice" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createInvoice"> + <service name="createInvoice" engine="groovy" default-entity-name="Invoice" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="createInvoice"> <description>Create Invoice Record</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="CREATE"/> <auto-attributes mode="INOUT" include="pk" optional="true"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> - <override name="invoiceTypeId" mode="IN" optional="false"/> - <override name="partyIdFrom" mode = "IN" optional="false"/> - <override name="partyId" mode = "IN" optional="false"/> + <override name="invoiceTypeId" mode="IN"/> + <override name="partyIdFrom" mode = "IN"/> + <override name="partyId" mode = "IN"/> <override name="description" allow-html="safe"/> <override name="invoiceMessage" allow-html="safe"/> + <override name="invoiceDate" default-value="${date:nowTimestamp()}"/> + <override name="statusId" default-value="INVOICE_IN_PROCESS"/> </service> - <service name="copyInvoice" engine="simple" default-entity-name="Invoice" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="copyInvoice"> + <service name="copyInvoice" engine="groovy" default-entity-name="Invoice" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="copyInvoice"> <description>Create Invoice Record/items from an existing invoice</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="CREATE"/> <auto-attributes mode="INOUT" include="pk" optional="true"/> - <attribute name="invoiceIdToCopyFrom" type="String" mode="IN" optional="false"/> + <attribute name="invoiceIdToCopyFrom" type="String" mode="IN"/> </service> - <service name="getInvoice" engine="simple" default-entity-name="Invoice" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="getInvoice"> + <service name="getInvoice" engine="groovy" default-entity-name="Invoice" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="getInvoice"> <description>Retrieve an existing Invoice/Items</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="VIEW"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <auto-attributes mode="IN" include="pk"/> <attribute name="invoice" type="org.apache.ofbiz.entity.GenericValue" mode="OUT"/> <attribute name="invoiceItems" type="List" mode="OUT"/><!-- list of invoiceItem GenericValues --> </service> - <service name="updateInvoice" engine="simple" default-entity-name="Invoice" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="updateInvoice"> + <service name="updateInvoice" engine="groovy" default-entity-name="Invoice" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="updateInvoice"> <description>Update an existing Invoice Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="IN" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> <override name="description" allow-html="safe"/> <override name="invoiceMessage" allow-html="safe"/> </service> - <service name="setInvoiceStatus" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="setInvoiceStatus"> + <service name="setInvoiceStatus" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="setInvoiceStatus"> <description>Set the Invoice Status</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> - <attribute name="statusId" type="String" mode="IN" optional="false"/> - <attribute name="statusDate" type="Timestamp" mode="IN" optional="true"/> + <attribute name="invoiceId" type="String" mode="IN"/> + <attribute name="statusId" type="String" mode="IN"/> + <attribute name="statusDate" type="Timestamp" mode="IN" default-value="${date:nowTimestamp()}"/> <attribute name="paidDate" type="Timestamp" mode="IN" optional="true"/> <!-- only relevant for changes to PAID --> <attribute name="invoiceTypeId" type="String" mode="OUT" optional="true"/> <attribute name="oldStatusId" type="String" mode="OUT" optional="true"/> </service> - <service name="copyInvoiceToTemplate" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="copyInvoiceToTemplate"> - <description>Save a Invoice data to a template .</description> + <service name="copyInvoiceToTemplate" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="copyInvoiceToTemplate"> + <description>Save a Invoice data to a template.</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="CREATE"/> - <attribute name="invoiceId" type="String" mode="INOUT" optional="false"/> - <attribute name="invoiceTypeId" type="String" mode="IN" optional="false"/> + <attribute name="invoiceId" type="String" mode="INOUT"/> + <attribute name="invoiceTypeId" type="String" mode="IN"/> + </service> + <service name="checkInvoiceStatusInProgress" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="checkInvoiceStatusInProgress"> + <description>Check if the invoiceStatus is in progress</description> + <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> + <implements service="permissionInterface"/> + <attribute name="invoiceId" type="String" mode="IN"/> </service> <!-- @@ -110,66 +119,64 @@ under the License. creating an issue with return-wide adjustments: How do we know that such an adjustment is to be taxed or not? Because of this problem, we will continue to have null taxableFlags for awhile yet, which is why the mandatory taxableFlag of this method was taken out. --> - <service name="createInvoiceItem" engine="simple" default-entity-name="InvoiceItem" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createInvoiceItem"> + <service name="createInvoiceItem" engine="groovy" default-entity-name="InvoiceItem" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="createInvoiceItem"> <description>Create a new Invoice Item Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="IN" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> <override name="invoiceItemSeqId" mode="INOUT" optional="true"/><!-- will optionally be assigned by the system --> <override name="description" allow-html="safe"/> </service> - <service name="updateInvoiceItem" engine="simple" default-entity-name="InvoiceItem" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="updateInvoiceItem"> + <service name="updateInvoiceItem" engine="groovy" default-entity-name="InvoiceItem" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="updateInvoiceItem"> <description>Update existing Invoice Item Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="INOUT" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="INOUT" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> <override name="description" allow-html="safe"/> </service> - <service name="removeInvoiceItem" engine="simple" default-entity-name="InvoiceItem" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="removeInvoiceItem"> + <service name="removeInvoiceItem" engine="groovy" default-entity-name="InvoiceItem" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="removeInvoiceItem"> <description>Remove an existing Invoice Item Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="IN" include="pk"/> </service> <service name="createInvoiceStatus" engine="entity-auto" default-entity-name="InvoiceStatus" invoke="create" auth="true"> <description>Create a Invoice Status Record</description> - <auto-attributes mode="IN" include="pk" optional="false"/> - <override name="statusDate" mode="IN" optional="true"/> + <auto-attributes mode="IN" include="pk"/> + <override name="statusDate" mode="IN" default-value="${date:nowTimestamp()}"/> </service> - <service name="createInvoiceRole" engine="simple" default-entity-name="InvoiceRole" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createInvoiceRole"> + <service name="createInvoiceRole" engine="entity-auto" default-entity-name="InvoiceRole" invoke="create"> <description>Create a new Invoice Role Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="IN" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> + <override name="datetimePerformed" default-value="${date:nowTimestamp()}"/> </service> - <service name="removeInvoiceRole" engine="simple" default-entity-name="InvoiceRole" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="removeInvoiceRole"> + <service name="removeInvoiceRole" engine="entity-auto" default-entity-name="InvoiceRole" invoke="remove"> <description>Remove an existing Invoice Role Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="IN" include="pk"/> </service> - <service name="createInvoiceTerm" engine="simple" default-entity-name="InvoiceTerm" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createInvoiceTerm"> + <service name="createInvoiceTerm" engine="entity-auto" default-entity-name="InvoiceTerm" invoke="create"> <description>Create Invoice (Item) Term Record</description> - <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="OUT" include="pk" optional="false"/> + <permission-service service-name="checkInvoiceStatusInProgress"/> + <auto-attributes mode="OUT" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> </service> <service name="updateInvoiceTerm" engine="entity-auto" default-entity-name="InvoiceTerm" invoke="update"> <description>Update Invoice (Item) Term Record</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <auto-attributes mode="IN" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> </service> <service name="deleteInvoiceTerm" engine="entity-auto" default-entity-name="InvoiceTerm" invoke="delete"> <description>Delete Invoice (Item) Term Record</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="DELETE"/> - <auto-attributes mode="IN" include="pk" optional="false"/> + <auto-attributes mode="IN" include="pk"/> </service> <service name="createInvoiceForOrderAllItems" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="createInvoiceForOrderAllItems"> @@ -177,7 +184,7 @@ under the License. Create an invoice from existing order using all order items orderId = The orderId to associate the invoice with </description> - <attribute name="orderId" type="String" mode="IN" optional="false"/> + <attribute name="orderId" type="String" mode="IN"/> <attribute name="invoiceId" type="String" mode="OUT" optional="true"/> </service> <service name="createInvoiceForOrder" engine="java" @@ -187,8 +194,8 @@ under the License. orderId = The orderId to associate the invoice with billItems = List of ItemIssuance records to use for creating the invoice </description> - <attribute name="orderId" type="String" mode="IN" optional="false"/> - <attribute name="billItems" type="List" mode="IN" optional="false"/> + <attribute name="orderId" type="String" mode="IN"/> + <attribute name="billItems" type="List" mode="IN"/> <attribute name="eventDate" type="Timestamp" mode="IN" optional="true"/> <attribute name="invoiceId" type="String" mode="INOUT" optional="true"/> <attribute name="invoiceTypeId" type="String" mode="OUT" optional="true"/> @@ -200,7 +207,7 @@ under the License. returnId = The returnId to associate the invoice with billItems = List of ShipmentReceipts (for sales return) or ItemIssuance (for purchase return) to use for creating the invoice </description> - <attribute name="returnId" type="String" mode="IN" optional="false"/> + <attribute name="returnId" type="String" mode="IN"/> <attribute name="billItems" type="List" mode="IN" optional="true"/> <attribute name="invoiceId" type="String" mode="OUT" optional="true"/> </service> @@ -213,7 +220,7 @@ under the License. salesRepresentative: the invoice partyIdFrom </description> <attribute name="partyIds" type="List" mode="IN" optional="true"/> - <attribute name="invoiceIds" type="List" mode="IN" optional="false"/> + <attribute name="invoiceIds" type="List" mode="IN"/> <attribute name="invoicesCreated" type="List" mode="OUT" optional="true"/> </service> <service name="sampleInvoiceAffiliateCommission" engine="simple" @@ -223,15 +230,15 @@ under the License. and invoice for it on behalf of the affiliate, ie an invoice from the affiliate to the company that can then be paid by the company to balance it. </description> - <attribute name="paymentId" type="String" mode="IN" optional="false"/> - <attribute name="invoiceId" type="String" mode="OUT" optional="false"/> + <attribute name="paymentId" type="String" mode="IN"/> + <attribute name="invoiceId" type="String" mode="OUT"/> </service> <service name="readyInvoices" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="readyInvoices"> <description> Sets status of each invoice in the list of invoices to INVOICE_READY. </description> - <attribute name="invoicesCreated" type="List" mode="IN" optional="false"/> + <attribute name="invoicesCreated" type="List" mode="IN"/> </service> <service name="createInvoicesFromShipment" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="createInvoicesFromShipment"> @@ -241,14 +248,14 @@ under the License. one invoice for each order in the shipment will be created. invoicesCreated = List of invoiceIds which were created by this service </description> - <attribute name="shipmentId" type="String" mode="IN" optional="false"/> + <attribute name="shipmentId" type="String" mode="IN"/> <attribute name="eventDate" type="Timestamp" mode="IN" optional="true"/> <attribute name="invoicesCreated" type="List" mode="OUT" optional="true"/> </service> <service name="setInvoicesToReadyFromShipment" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="setInvoicesToReadyFromShipment"> <description>Set invoice(s) to Ready from Shipment</description> - <attribute name="shipmentId" type="String" mode="IN" optional="false"/> + <attribute name="shipmentId" type="String" mode="IN"/> </service> <service name="createSalesInvoicesFromDropShipment" engine="java" @@ -257,7 +264,7 @@ under the License. Create sales invoice(s) from a drop shipment by wrapping a call to createInvoicesFromShipments with the createSalesInvoicesForDropShipments parameter </description> - <attribute name="shipmentId" type="String" mode="IN" optional="false"/> + <attribute name="shipmentId" type="String" mode="IN"/> <attribute name="invoicesCreated" type="List" mode="OUT" optional="true"/> </service> <service name="createInvoicesFromShipments" engine="java" @@ -271,7 +278,7 @@ under the License. will be controlled by the createSalesInvoicesForDropShipments parameter (purchase by default). invoicesCreated = List of invoiceIds which were created by this service </description> - <attribute name="shipmentIds" type="List" mode="IN" optional="false"/> + <attribute name="shipmentIds" type="List" mode="IN"/> <attribute name="createSalesInvoicesForDropShipments" type="Boolean" mode="IN" optional="true"/> <attribute name="eventDate" type="Timestamp" mode="IN" optional="true"/> <attribute name="invoicesCreated" type="List" mode="OUT" optional="true"/> @@ -282,15 +289,15 @@ under the License. Create invoice(s) from a return Shipment invoicesCreated = List of invoiceIds which were created by this service </description> - <attribute name="shipmentId" type="String" mode="IN" optional="false"/> + <attribute name="shipmentId" type="String" mode="IN"/> <attribute name="invoicesCreated" type="List" mode="OUT" optional="true"/> </service> - <service name="sendInvoicePerEmail" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="sendInvoicePerEmail"> + <service name="sendInvoicePerEmail" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="sendInvoicePerEmail"> <description>Send an invoice per email</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> - <attribute name="sendFrom" type="String" mode="IN" optional="false"/> - <attribute name="sendTo" type="String" mode="IN" optional="false"/> + <attribute name="invoiceId" type="String" mode="IN"/> + <attribute name="sendFrom" type="String" mode="IN"/> + <attribute name="sendTo" type="String" mode="IN"/> <attribute name="sendCc" type="String" mode="IN" optional="true"/> <attribute name="subject" type="String" mode="IN" optional="true"/> <attribute name="bodyText" type="String" mode="IN" optional="true" allow-html="any"/> @@ -299,159 +306,163 @@ under the License. <service name="checkInvoicePaymentApplications" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="checkInvoicePaymentApplications"> <description>Checks to see if the payments applied to an invoice total up to the invoice total; if so sets to PAID</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> + <attribute name="invoiceId" type="String" mode="IN"/> </service> <service name="createInvoiceContactMech" engine="entity-auto" invoke="create" default-entity-name="InvoiceContactMech"> <description>Create a ContactMech for an invoice</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="CREATE"/> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <service name="deleteInvoiceContactMech" engine="entity-auto" invoke="delete" default-entity-name="InvoiceContactMech"> <description>Delete a ContactMech for an invoice</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="DELETE"/> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <service name="calculateInvoicedAdjustmentTotal" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="calculateInvoicedAdjustmentTotal"> <description>Calculate the previously invoiced amount for an OrderAdjustment</description> - <attribute name="orderAdjustment" type="org.apache.ofbiz.entity.GenericValue" mode="IN" optional="false"/> - <attribute name="invoicedTotal" type="BigDecimal" mode="OUT" optional="false"/> + <attribute name="orderAdjustment" type="org.apache.ofbiz.entity.GenericValue" mode="IN"/> + <attribute name="invoicedTotal" type="BigDecimal" mode="OUT"/> </service> <service name="updateInvoiceItemType" default-entity-name="InvoiceItemType" engine="entity-auto" invoke="update"> <description>Update Invoice Item Type Record</description> - <auto-attributes mode="IN" include="pk" optional="false"/> + <auto-attributes mode="IN" include="pk"/> <auto-attributes mode="IN" include="nonpk" optional="true"/> </service> <!-- Auto generate Invoice for fixed period --> - <service name="autoGenerateInvoiceFromExistingInvoice" engine="simple" location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="autoGenerateInvoiceFromExistingInvoice"> + <service name="autoGenerateInvoiceFromExistingInvoice" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="autoGenerateInvoiceFromExistingInvoice"> <description>Scheduled service to generate Invoice from an existing Invoice</description> - <attribute name="recurrenceInfoId" mode="IN" type="String" optional="false"/> + <attribute name="recurrenceInfoId" mode="IN" type="String"/> </service> - <service name="cancelInvoice" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="cancelInvoice"> + <service name="cancelInvoice" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="cancelInvoice"> <description>Cancel Invoice</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> - <attribute name="invoiceTypeId" type="String" mode="OUT" optional="false"/> + <attribute name="invoiceId" type="String" mode="IN"/> + <attribute name="invoiceTypeId" type="String" mode="OUT"/> </service> - <service name="getInvoiceRunningTotal" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="getInvoiceRunningTotal" auth="true"> + <service name="getInvoiceRunningTotal" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="getInvoiceRunningTotal"> <description>calculate running total for selected Invoices</description> - <attribute name="invoiceIds" type="List" mode="IN" optional="false"/> + <attribute name="invoiceIds" type="List" mode="IN"/> <attribute name="organizationPartyId" type="String" mode="IN" optional="true"/> - <attribute name="invoiceRunningTotal" type="String" mode="OUT" optional="false"/> + <attribute name="invoiceRunningTotal" type="String" mode="OUT"/> </service> - <service name="addtax" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="addtax"> + <service name="addTaxOnInvoice" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="addTaxOnInvoice"> <description>Call Tax Calculate Service</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> + <attribute name="invoiceId" type="String" mode="IN"/> </service> - <service name="getInvoicesFilterByAssocType" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="getInvoicesFilterByAssocType" auth="true"> + <service name="getInvoicesFilterByAssocType" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="getInvoicesFilterByAssocType"> <description>Filter invoices by invoiceItemAssocTypeId</description> - <attribute name="invoiceList" type="List" mode="IN" optional="false"/> - <attribute name="invoiceItemAssocTypeId" type="String" mode="IN" optional="false"/> + <attribute name="invoiceList" type="List" mode="IN"/> + <attribute name="invoiceItemAssocTypeId" type="String" mode="IN"/> <attribute name="filteredInvoiceList" type="List" mode="OUT" optional="true"/> </service> <!-- Invoice Association Services --> <service name="createInvoiceItemAssoc" default-entity-name="InvoiceItemAssoc" engine="entity-auto" invoke="create" auth="true"> <description>Create a InvoiceItemAssoc</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> <override name="fromDate" optional="true"/> </service> <service name="updateInvoiceItemAssoc" default-entity-name="InvoiceItemAssoc" engine="entity-auto" invoke="update" auth="true"> <description>Update a InvoiceItemAssoc</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceItemAssoc" default-entity-name="InvoiceItemAssoc" engine="entity-auto" invoke="delete" auth="true"> <description>Delete a InvoiceItemAssoc</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> - <service name="removeInvoiceItemAssocOnCancelInvoice" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="removeInvoiceItemAssocOnCancelInvoice" auth="true"> + <service name="removeInvoiceItemAssocOnCancelInvoice" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="removeInvoiceItemAssocOnCancelInvoice"> <description>Remove invoiceItemAssoc record on cancel invoice</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> + <attribute name="invoiceId" type="String" mode="IN"/> </service> - <service name="resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice" auth="true"> + <service name="resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice"> <description>Reset OrderItemBilling and OrderAdjustmentBilling records on cancel invoice, so it is isn't considered invoiced any more by createInvoiceForOrder service</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> + <attribute name="invoiceId" type="String" mode="IN"/> </service> - <service name="massChangeInvoiceStatus" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="massChangeInvoiceStatus" auth="true"> + <service name="massChangeInvoiceStatus" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="massChangeInvoiceStatus"> <description>Set status of invoices in bulk.</description> - <attribute name="invoiceIds" type="List" mode="IN" optional="false"/> - <attribute name="statusId" type="String" mode="IN" optional="false"/> - <attribute name="errorMessage" type="String" optional="true" mode="OUT"/> + <attribute name="invoiceIds" type="List" mode="IN"/> + <attribute name="statusId" type="String" mode="IN"/> </service> - <service name="createInvoiceFromOrder" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createInvoiceFromOrder"> + <service name="createInvoiceFromOrder" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="createInvoiceFromOrder"> <description>Create an invoice from existing order when invoicePerShipment is N</description> - <attribute name="orderId" type="String" mode="IN" optional="false"/> + <attribute name="orderId" type="String" mode="IN"/> <attribute name="invoiceId" type="String" mode="OUT" optional="true"/> </service> <!-- Invoice content services --> - <service name="createInvoiceContent" default-entity-name="InvoiceContent" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createInvoiceContent" auth="true"> + <service name="createInvoiceContent" default-entity-name="InvoiceContent" engine="entity-auto" invoke="create" auth="true"> <description>Add Content To Invoice</description> - <auto-attributes include="pk" mode="INOUT" optional="false"/> + <auto-attributes include="pk" mode="INOUT"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> - <auto-attributes entity-name="Content" include="nonpk" mode="IN" optional="true"/> <override name="fromDate" optional="true"/> - <!--<override name="contentId" optional="true" mode="INOUT"/>--> </service> - <service name="updateInvoiceContent" default-entity-name="InvoiceContent" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="updateInvoiceContent" auth="true"> + <service name="updateInvoiceContent" default-entity-name="InvoiceContent" engine="entity-auto" invoke="update" auth="true"> <description>Update Content To Invoice</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> - <auto-attributes entity-name="Content" include="nonpk" mode="IN" optional="true"/> </service> <service name="removeInvoiceContent" default-entity-name="InvoiceContent" engine="entity-auto" invoke="delete" auth="true"> <description>Remove Content From Invoice</description> - <auto-attributes include="pk" mode="IN" optional="false"/> - </service> - - <service name="createSimpleTextContentForInvoice" default-entity-name="InvoiceContent" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="createSimpleTextContentForInvoice" auth="true"> - <auto-attributes include="pk" mode="IN" optional="false"/> - <auto-attributes include="nonpk" mode="IN" optional="true"/> - <auto-attributes entity-name="Content" include="nonpk" mode="IN" optional="true"/> - <attribute name="text" type="String" mode="IN" optional="false" allow-html="safe"/> - <override name="contentId" optional="true"/> - <override name="fromDate" optional="true"/> + <auto-attributes include="pk" mode="IN"/> </service> - <service name="updateSimpleTextContentForInvoice" default-entity-name="InvoiceContent" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="updateSimpleTextContentForInvoice" auth="true"> - <auto-attributes include="pk" mode="IN" optional="false"/> - <auto-attributes include="nonpk" mode="IN" optional="true"/> - <auto-attributes mode="IN" entity-name="Content" optional="true"/> - <attribute name="textDataResourceId" type="String" mode="IN" optional="true"/> - <attribute name="text" type="String" mode="IN" optional="true" allow-html="safe"/> + <service name="createInvoiceContentAndUpdateContent" engine="group" auth="true"> + <description>Add Content To Invoice and update the content</description> + <group> + <invoke name="createInvoiceContent"/> + <invoke name="updateContent"/> + </group> + </service> + <service name="updateInvoiceContentAndContent" engine="group" auth="true"> + <description>update the content Invoice link and the content</description> + <group> + <invoke name="updateInvoiceContent"/> + <invoke name="updateContent"/> + </group> + </service> + <service name="createSimpleTextContentForInvoice" engine="group" auth="true"> + <group> + <invoke name="createSimpleTextContent" result-to-context="true"/> + <invoke name="createInvoiceContentAndUpdateContent"/> + </group> + </service> + <service name="updateSimpleTextContentForInvoice" engine="group" auth="true"> + <group> + <invoke name="updateSimpleTextContent"/> + <invoke name="updateInvoiceContentAndContent"/> + </group> </service> - <service name="isInvoiceInForeignCurrency" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="isInvoiceInForeignCurrency" auth="true"> - <description>check if a invoice is in a foreign currency related to the accounting company.</description> - <attribute name="invoiceId" type="String" mode="IN" optional="false"/> - <attribute name="isForeign" type="Boolean" mode="OUT" optional="false"/> + + <service name="isInvoiceInForeignCurrency" engine="groovy" auth="true" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy" invoke="isInvoiceInForeignCurrency"> + <description>check if an invoice is in a foreign currency related to the accounting company.</description> + <attribute name="invoiceId" type="String" mode="IN"/> + <attribute name="isForeign" type="Boolean" mode="OUT"/> </service> <service name="importInvoice" engine="java" location="org.apache.ofbiz.accounting.invoice.InvoiceServices" invoke="importInvoice" auth="true"> - <description>Import an invoice with invoiceitems in csv format</description> + <description>Import an invoice with invoice items in csv format</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="CREATE"/> - <attribute mode="INOUT" name="organizationPartyId" type="String" optional="false"/> + <attribute mode="INOUT" name="organizationPartyId" type="String"/> <attribute mode="IN" name="uploadedFile" type="java.nio.ByteBuffer" optional="true" /> </service> <service name="createInvoiceItemAttribute" default-entity-name="InvoiceItemAttribute" engine="entity-auto" invoke="create" auth="true"> @@ -502,16 +513,16 @@ under the License. <service name="createInvoiceAttribute" default-entity-name="InvoiceAttribute" engine="entity-auto" invoke="create" auth="true"> <description>Create a InvoiceAttribute</description> <auto-attributes include="nonpk" mode="IN" optional="true"/> - <auto-attributes include="pk" mode="INOUT" optional="false"/> + <auto-attributes include="pk" mode="INOUT"/> </service> <service name="updateInvoiceAttribute" default-entity-name="InvoiceAttribute" engine="entity-auto" invoke="update" auth="true"> <description>Update a InvoiceAttribute</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceAttribute" default-entity-name="InvoiceAttribute" engine="entity-auto" invoke="delete" auth="true"> <description>Delete a InvoiceAttribute</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <!-- InvoiceItemAssocType services --> @@ -522,23 +533,23 @@ under the License. </service> <service name="updateInvoiceItemAssocType" default-entity-name="InvoiceItemAssocType" engine="entity-auto" invoke="update" auth="true"> <description>Update a InvoiceItemAssocType</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceItemAssocType" default-entity-name="InvoiceItemAssocType" engine="entity-auto" invoke="delete" auth="true"> <description>Delete a InvoiceItemAssocType</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <!-- InvoiceNote services --> <service name="createInvoiceNote" default-entity-name="InvoiceNote" engine="entity-auto" invoke="create" auth="true"> <description>Create a InvoiceNote</description> <auto-attributes include="nonpk" mode="IN" optional="true"/> - <auto-attributes include="pk" mode="INOUT" optional="false"/> + <auto-attributes include="pk" mode="INOUT"/> </service> <service name="deleteInvoiceNote" default-entity-name="InvoiceNote" engine="entity-auto" invoke="delete" auth="true"> <description>Delete a InvoiceNote</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <service name="createInvoiceContentType" default-entity-name="InvoiceContentType" engine="entity-auto" invoke="create" auth="true"> @@ -548,43 +559,43 @@ under the License. </service> <service name="updateInvoiceContentType" default-entity-name="InvoiceContentType" engine="entity-auto" invoke="update" auth="true"> <description>Update a InvoiceContentType</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceContentType" default-entity-name="InvoiceContentType" engine="entity-auto" invoke="delete" auth="true"> <description>Delete a InvoiceContentType</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <!-- InvoiceItemTypeAttr services --> <service name="createInvoiceItemTypeAttr" default-entity-name="InvoiceItemTypeAttr" engine="entity-auto" invoke="create" auth="true"> <description>Create InvoiceItemTypeAttr</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="updateInvoiceItemTypeAttr" default-entity-name="InvoiceItemTypeAttr" engine="entity-auto" invoke="update" auth="true"> <description>Update InvoiceItemTypeAttr</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceItemTypeAttr" default-entity-name="InvoiceItemTypeAttr" engine="entity-auto" invoke="delete" auth="true"> <description>Delete InvoiceItemTypeAttr</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <service name="createInvoiceItemTypeMap" default-entity-name="InvoiceItemTypeMap" engine="entity-auto" invoke="create" auth="true"> <description>Create InvoiceItemTypeMap</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="updateInvoiceItemTypeMap" default-entity-name="InvoiceItemTypeMap" engine="entity-auto" invoke="update" auth="true"> <description>Update InvoiceItemTypeMap</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceItemTypeMap" default-entity-name="InvoiceItemTypeMap" engine="entity-auto" invoke="delete" auth="true"> <description>Delete InvoiceItemTypeMap</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> <service name="createInvoiceType" default-entity-name="InvoiceType" engine="entity-auto" invoke="create" auth="true"> @@ -594,11 +605,11 @@ under the License. </service> <service name="updateInvoiceType" default-entity-name="InvoiceType" engine="entity-auto" invoke="update" auth="true"> <description>Update a InvoiceType</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> <auto-attributes include="nonpk" mode="IN" optional="true"/> </service> <service name="deleteInvoiceType" default-entity-name="InvoiceType" engine="entity-auto" invoke="delete" auth="true"> <description>Delete a InvoiceType</description> - <auto-attributes include="pk" mode="IN" optional="false"/> + <auto-attributes include="pk" mode="IN"/> </service> </services> diff --git a/applications/accounting/servicedef/services_payment.xml b/applications/accounting/servicedef/services_payment.xml index 842929a0db..c566f01485 100644 --- a/applications/accounting/servicedef/services_payment.xml +++ b/applications/accounting/servicedef/services_payment.xml @@ -100,8 +100,8 @@ under the License. <attribute name="invoiceProcessing" type="String" mode="IN" optional="true"/> <override name="paymentId" optional="false"/> </service> - <service name="removePaymentApplication" default-entity-name="PaymentApplication" engine="simple" - location="component://accounting/minilang/invoice/InvoiceServices.xml" invoke="removePaymentApplication"> + <service name="removePaymentApplication" default-entity-name="PaymentApplication" engine="groovy" + location="component://accounting/src/main/groovy/org/apache/ofbiz/accounting/payment/PaymentServices.groovy" invoke="removePaymentApplication"> <description>Delete a paymentApplication record.</description> <permission-service service-name="acctgInvoicePermissionCheck" main-action="UPDATE"/> <auto-attributes mode="IN" include="pk" optional="false"/> diff --git a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/AutoAcctgInvoiceTests.groovy b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/AutoAcctgInvoiceTests.groovy index ca9af5fcf6..f42a401cc4 100644 --- a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/AutoAcctgInvoiceTests.groovy +++ b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/AutoAcctgInvoiceTests.groovy @@ -39,7 +39,7 @@ class AutoAcctgInvoiceTests extends OFBizTestCase { fromDate: UtilDateTime.nowTimestamp(), userLogin: userLogin ] - Map serviceResult = dispatcher.runSync('createInvoiceContent', serviceCtx) + Map serviceResult = dispatcher.runSync('createInvoiceContentAndUpdateContent', serviceCtx) assert ServiceUtil.isSuccess(serviceResult) GenericValue invoiceContent = from('InvoiceContent') @@ -53,7 +53,6 @@ class AutoAcctgInvoiceTests extends OFBizTestCase { void testCreateSimpleTextContentForInvoice() { Map serviceCtx = [ invoiceId: '1009', - contentId: '1001', contentTypeId: 'DOCUMENT', invoiceContentTypeId: 'COMMENTS', text: 'Content for invoice # 1009', @@ -65,7 +64,6 @@ class AutoAcctgInvoiceTests extends OFBizTestCase { GenericValue invoiceContent = from('InvoiceContent') .where('invoiceId', '1009', - 'contentId', '1001', 'invoiceContentTypeId', 'COMMENTS') .queryFirst() @@ -141,7 +139,8 @@ class AutoAcctgInvoiceTests extends OFBizTestCase { void testCreateInvoiceItem() { Map serviceCtx = [ invoiceId: '1003', - invoiceTypeId: 'PINV_FXASTPRD_ITEM', + invoiceItemTypeId: 'PINV_FXASTPRD_ITEM', + amount: 1, userLogin: userLogin ] Map serviceResult = dispatcher.runSync('createInvoiceItem', serviceCtx) diff --git a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/InvoicePerShipmentTests.groovy b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/InvoicePerShipmentTests.groovy index b4baa323b3..dae3ada723 100644 --- a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/InvoicePerShipmentTests.groovy +++ b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/accounting/InvoicePerShipmentTests.groovy @@ -135,7 +135,7 @@ class InvoicePerShipmentTests extends OFBizTestCase { // Step 3 GenericValue orderHeader = from('OrderHeader').where('orderTypeId', 'SALES_ORDER').orderBy('-entryDate').queryFirst() - logInfo('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx : ' + orderHeader) + logInfo('===== >>> orderHeader : ' + orderHeader) if (invoicePerShipment) { // if this value is available that means we need to set this on the order diff --git a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy index 19543f01e1..47ede9c29b 100644 --- a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy +++ b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/invoice/InvoiceServicesScript.groovy @@ -18,16 +18,23 @@ */ package org.apache.ofbiz.accounting.invoice +import org.apache.ofbiz.accounting.util.UtilAccounting import org.apache.ofbiz.base.util.Debug import org.apache.ofbiz.base.util.UtilDateTime +import org.apache.ofbiz.base.util.UtilFormatOut import org.apache.ofbiz.base.util.UtilValidate import org.apache.ofbiz.entity.GenericValue +import org.apache.ofbiz.entity.condition.EntityCondition +import org.apache.ofbiz.entity.condition.EntityConditionBuilder +import org.apache.ofbiz.entity.util.EntityTypeUtil +import org.apache.ofbiz.entity.util.EntityUtil +import org.apache.ofbiz.entity.util.EntityUtilProperties import org.apache.ofbiz.service.ServiceUtil import java.sql.Timestamp Map getNextInvoiceId() { - result = success() + Map result = success() // try to find PartyAcctgPreference for parameters.partyId, see if we need any special invoice number sequencing GenericValue partyAcctgPreference = from('PartyAcctgPreference').where(parameters).queryOne() @@ -85,7 +92,7 @@ Map getNextInvoiceId() { } Map invoiceSequenceEnforced() { - result = success() + Map result = success() logInfo('In createInvoice sequence enum Enforced') GenericValue partyAcctgPreference = parameters.partyAcctgPreference @@ -103,8 +110,6 @@ Map invoiceSequenceEnforced() { } Map invoiceSequenceRestart() { - result = success() - logInfo('In createInvoice sequence enum Enforced') GenericValue partyAcctgPreference = parameters.partyAcctgPreference //this is sequential sequencing, we can't skip a number, also it must be a unique sequence per partyIdFrom @@ -134,3 +139,520 @@ Map invoiceSequenceRestart() { return success(invoiceId: "${curYearString}-${partyAcctgPreference.lastInvoiceNumber}") } +/** + * Create a new Invoice + * @return Success response containing the invoiceId, error response otherwise. + */ +Map createInvoice() { + if (!parameters.invoiceId) { + Map serviceResult = run service: 'getNextInvoiceId', with: [*: parameters, + partyId: parameters.partyIdFrom] + parameters.invoiceId = serviceResult.invoiceId + } + GenericValue party = from('Party').where(parameters).queryOne() + if (party?.preferredCurrencyUomId) { + parameters.currencyUomId = party.preferredCurrencyUomId + } + GenericValue invoice = makeValue('Invoice', parameters) + invoice.create() + run service: 'createInvoiceStatus', with: parameters + return success([invoiceId: invoice.invoiceId]) +} + +/** + * Retrieve an invoice and the items + * @return Success response containing the invoice and items, failure response otherwise. + */ +Map getInvoice() { + GenericValue invoice = from('Invoice').where(parameters).queryOne() + if (!invoice) { + return failure(label('AccountingUiLabels', 'AccountingInvoiceNotFound', parameters)) + } + return success([invoice: invoice, + invoiceItems: invoice.getRelated('InvoiceItem', null, null, false)]) +} + +/** + * Update the header of an existing Invoice + * @return Success response if invoice updated, error response otherwise. + */ +Map updateInvoice() { + GenericValue invoice = from('Invoice').where(parameters).queryOne() + if (!invoice) { + return error(label('AccountingUiLabels', 'AccountingInvoiceNotFound', parameters)) + } + if (invoice.statusId != 'INVOICE_IN_PROCESS') { + return error(label('AccountingUiLabels', 'AccountingInvoiceUpdateOnlyWithInProcessStatus', [statustId: invoice.statusId])) + } + + // only save if something has changed, do not update status here + // update all non status and key fields + GenericValue lookedInvoice = invoice.clone() + invoice.setNonPKFields([*: parameters, statustId: 'INVOICE_IN_PROCESS'], false) + if (lookedInvoice != invoice) { + invoice.store() + } + + // check if there is a requested status change if yes call invoice status update service + if (parameters.statusId && parameters.statusId != 'INVOICE_IN_PROCESS') { + run service: 'setInvoiceStatus', with: [invoiceId: invoice.invoiceId, + statustId: parameters.statustId] + } + return success() +} + +/** + * Create a new Invoice from an existing invoice + * @return Success response containing the invoiceId, error response otherwise. + */ +Map copyInvoice() { + Map serviceResult = run service: 'getInvoice', with: [invoiceId: parameters.invoiceIdToCopyFrom] + GenericValue invoice = serviceResult.invoice + List<GenericValue> invoiceItems = serviceResult.invoiceItems + invoice.invoiceTypeId = parameters.invoiceTypeId ?: invoice.invoiceTypeId + serviceResult = run service: 'createInvoice', with: [*: invoice.getAllFields(), + invoiceId: null] + String newInvoiceId = serviceResult.invoiceId + invoiceItems.each { + run service: 'createInvoiceItem', with: [*: it.getAllFields(), + invoiceId: newInvoiceId] + } + return success([invoiceId: newInvoiceId]) +} + +/** + * Copy a invoice to a InvoiceType starting with 'template' + * @return Success response containing the invoiceId, error response otherwise. + */ +Map copyInvoiceToTemplate() { + String invoiceTypeId = parameters.invoiceTypeId + Map switchType = [SALES_INVOICE: 'SALES_INV_TEMPLATE', + PURCHASE_INVOICE: 'PUR_INV_TEMPLATE'] + run service: 'copyInvoice', with: [*: parameters, + invoiceIdToCopyFrom: parameters.invoiceId, + invoiceTypeId: switchType.get(invoiceTypeId) ?: invoiceTypeId] +} + +/** + * Set The Invoice Status + * @return Success response after status stored, error response otherwise. + */ +Map setInvoiceStatus() { + GenericValue invoice = from('Invoice').where(parameters).queryOne() + if (!invoice) { + return error(label('AccountingUiLabels', 'AccountingInvoiceNotFound', parameters)) + } + String oldStatusId = invoice.statusId + String invoiceTypeId = invoice.invoiceTypeId + Map returnResult = [oldStatusId: oldStatusId, invoiceTypeId: invoiceTypeId] + if (oldStatusId == parameters.statusId) { + return success(returnResult) + } + + if (from('StatusValidChange') + .where(statusId: oldStatusId, statusIdTo: parameters.statusId) + .queryCount() == 0) { + return error(label('AccountingUiLabels', 'AccountingPSInvalidStatusChange')) + } + + // if new status is paid check if the complete invoice is applied + if (parameters.statusId == 'INVOICE_PAID') { + BigDecimal notApplied = InvoiceWorker.getInvoiceNotApplied(invoice) + if (notApplied != 0) { + return error(label('AccountingUiLabels', 'AccountingInvoiceCannotChangeStatusToPaid')) + } + } + + // if it's OK to mark invoice paid, use parameters for paidDate + invoice.paidDate = parameters.paidDate ?: UtilDateTime.nowTimestamp() + + if (parameters.statusId == 'INVOICE_READY' && invoice.paidDate) { + invoice.paidDate = null + } + invoice.statusId = parameters.statusId + invoice.store() + + run service: 'createInvoiceStatus', with: [invoiceId: invoice.invoiceId, + statusId: invoice.statusId, + statusDate: parameters.statusDate] + + // if the invoice is a payrol invoice, create the payment in the not-paid status + // TODO the next part need to move on dedicate service + if (invoiceTypeId == 'PAYROL_INVOICE' && + ['INVOICE_APPROVED', 'INVOICE_READY'].contains(invoice.statusId)) { + // only generate payment if no application exist yet + List paymentApplications = invoice.getRelated('PaymentApplication', null, null, false) + if (!paymentApplications) { + BigDecimal amount = InvoiceWorker.getInvoiceTotal(invoice) + Map serviceResult = run service: 'createPayment', with: [partyIdFrom: invoice.partyId, + partyIdTo: invoice.partyIdFrom, + paymentMethodTypeId: 'COMPANY_CHECK', + paymentTypeId: 'PAYROL_PAYMENT', + statusId: 'PMNT_NOT_PAID', + currencyUomId: invoice.currencyUomId, + amount: amount] + run service: 'createPaymentApplication', with: [invoiceId: invoice.invoiceId, + paymentId: serviceResult.paymentId, + amountApplied: amount] + } + } + return success(returnResult) +} + +/** + * Check if the invoiceStatus is in progress + * @return Success response containing hasPermission to edit, error response otherwise. + */ +Map checkInvoiceStatusInProgress() { + GenericValue invoice = from('Invoice').where(parameters).cache().queryOne() + boolean hasPermission = invoice && invoice.statusId == 'INVOICE_IN_PROCESS' + return success([hasPermission: hasPermission]) +} + +/** + * Service run after cancel an invoice + * @return Success response containing the invoiceTypeId cancelled, error response otherwise. + */ +Map cancelInvoice() { + GenericValue invoice = from('Invoice').where(parameters).cache().queryOne() + if (!invoice) { + return error(label('AccountingUiLabels', 'AccountingInvoiceNotFound', parameters)) + } + invoice.getRelated('PaymentApplication', null, null, false).each { + GenericValue payment = it.getRelatedOne('Payment', false) + if (payment.statusId == 'PMNT_CONFIRMED') { + run service: 'setPaymentStatus', with: [paymentId: payment.paymentId, + statusId: UtilAccounting.isReceipt(payment) ? 'PMNT_RECEIVED' : 'PMNT_SENT'] + } + run service: 'removePaymentApplication', with: [paymentApplicationId: it.paymentApplicationId] + } + return success([invoiceTypeId: invoice.invoiceTypeId]) +} + +/** + * Send an invoice per Email + * @return Success response + */ +Map sendInvoicePerEmail() { + Map emailParams = dispatcher.getDispatchContext() + .makeValidContext([*: parameters, + xslfoAttachScreenLocation: 'component://accounting/widget/AccountingPrintScreens.xml#InvoicePDF', + bodyParameters: [invoiceId: parameters.invoiceId, + userLogin: parameters.userLogin, + other: parameters.other] //to print in 'other currency' + ]) + dispatcher.runAsync('sendMailFromScreen', emailParams) + return success(label('AccountingUiLabels', 'AccountingEmailScheduledToSend')) +} + +/** + * Create a new Invoice Item + * @return Success response containing the invoiceItemSeqId, error response otherwise. + */ +Map createInvoiceItem() { + GenericValue invoiceItem = makeValue('InvoiceItem', parameters) + if (!invoiceItem.invoiceItemSeqId) { + delegator.setNextSubSeqId(invoiceItem, 'invoiceItemSeqId', 5, 1) + } + // if there is no amount and a productItem is supplied fill the amount(price) and description from the product record + // TODO: there are return adjustments now that make this code very broken. The check for price was added as a quick fix. + if (invoiceItem.productId) { + invoiceItem.quantity = invoiceItem.quantity ?: 1 + if (!invoiceItem.amount) { + GenericValue product = from('Product').where(parameters).cache().queryOne() + invoiceItem.description = product.description + Map serviceResult = run service: 'calculateProductPrice', with: [product: product] + invoiceItem.amount = serviceResult.price + } + } + if (invoiceItem.amount == null) { // accept 0 + return error(label('AccountingUiLabels', 'AccountingInvoiceAmountIsMandatory')) + } + invoiceItem.create() + return success([invoiceId: invoiceItem.invoiceId, + invoiceItemSeqId: invoiceItem.invoiceItemSeqId]) +} + +/** + * Update an existing Invoice Item + * @return Success response after updated, error response otherwise. + */ +Map updateInvoiceItem() { + GenericValue invoiceItem = from('InvoiceItem').where(parameters).queryOne() + if (!invoiceItem) { + return error(label('AccountingUiLabels', 'AccountingInvoiceItemNotFound', parameters)) + } + GenericValue lookedInvoiceItem = invoiceItem.clone() + invoiceItem.setNonPKFields(parameters, false) + + // check if the productNumber is updated, when yes retrieve product description and price + if (lookedInvoiceItem.productId != invoiceItem.productId) { + GenericValue product = from('Product').where(parameters).cache().queryOne() + invoiceItem.description = product.description + Map serviceResult = run service: 'calculateProductPrice', with: [product: product] + invoiceItem.amount = serviceResult.price + if (invoiceItem.amount == null) { + return error(label('AccountingUiLabels', 'AccountingInvoiceAmountIsMandatory')) + } + } + if (lookedInvoiceItem != invoiceItem) { + invoiceItem.store() + } + return success([invoiceId: invoiceItem.invoiceId, + invoiceItemSeqId: invoiceItem.invoiceItemSeqId]) +} + +/** + * Remove an existing Invoice Item + * @return Success response after remove, error response otherwise. + */ +Map removeInvoiceItem() { + GenericValue invoiceItem = from('InvoiceItem').where(parameters).queryOne() + if (!invoiceItem) { + return error(label('AccountingUiLabels', 'AccountingInvoiceItemNotFound', parameters)) + } + // check if there are specific item paymentApplications when yes remove those + invoiceItem.removeRelated('PaymentApplication') + invoiceItem.remove() + return success() +} + +/** + * Scheduled service to generate Invoice from an existing Invoice + */ +Map autoGenerateInvoiceFromExistingInvoice() { + Map switchType = [SALES_INV_TEMPLATE: 'SALES_INVOICE', + PUR_INV_TEMPLATE: 'PURCHASE_INVOICE'] + from('Invoice') + .where(recurrenceInfoId: parameters.recurrenceInfoId) + .queryList() + .each { + Map serviceResult = run service: 'copyInvoice', with: [*: it.getAllFields(), + invoiceIdToCopyFrom: it.invoiceId] + if (switchType.containsKey(it.invoiceTypeId)) { + String invoiceId = serviceResult.invoiceId + run service: 'updateInvoice', with: [invoiceId: invoiceId, + recurrenceInfoId: null, + invoiceTypeId: switchType(it.invoiceTypeId)] + } + } + return success() +} + +/** + * Calculate running total for Invoices + * @return Success response containing the invoiceRunningTotal, error response otherwise. + */ +Map getInvoiceRunningTotal() { + BigDecimal runningTotal = 0 + parameters.invoiceIds.each { + Map serviceResult = run service: 'getInvoicePaymentInfoList', with: [invoiceId: it] + if (serviceResult.invoicePaymentInfoList) { + runningTotal += serviceResult.invoicePaymentInfoList[0].outstandingAmount + } + } + Map serviceResult = run service: 'getPartyAccountingPreferences', with: parameters + Map partyAccountingPreference = serviceResult.partyAccountingPreference + String currencyUomId = partyAccountingPreference.baseCurrencyUomId ?: + EntityUtilProperties.getPropertyValue('general', 'currency.uom.id.default', 'USD', delegator) + return success([invoiceRunningTotal: UtilFormatOut.formatCurrency(runningTotal, currencyUomId, parameters.locale)]) +} + +/** + * Filter invoices by invoiceItemAssocTypeId + * @return Success response containing filteredInvoiceList, error response otherwise. + */ +Map getInvoicesFilterByAssocType() { + EntityCondition condition = new EntityConditionBuilder().AND { + EQUALS(invoiceItemAssocTypeId: parameters.invoiceItemAssocTypeId) + IN(invoiceIdFrom: parameters.invoiceList*.invoiceId) + } + List invoiceIds = from('InvoiceItemAssoc') + .where(condition) + .distinct() + .filterByDate() + .getFieldList('invoiceIdFrom') + return success([filteredInvoiceList: parameters.invoiceList.findAll { invoiceIds.contains(it.invoiceId) }]) +} + +/** + * Remove invoiceItemAssoc record on cancel invoice + * @return Success response after remove, error response otherwise. + */ +Map removeInvoiceItemAssocOnCancelInvoice() { + from('InvoiceItemAssoc') + .where(invoiceIdTo: parameters.invoiceId) + .queryList() + .each { + run service: 'deleteInvoiceItemAssoc', with: it.getAllFields() + } + return success() +} + +/** + * Reset OrderItemBilling and OrderAdjustmentBilling records on cancel invoice, + * so it is isn't considered invoiced any more by createInvoiceForOrder service + * @return Success response + */ +Map resetOrderItemBillingAndOrderAdjustmentBillingOnCancelInvoice() { + from('OrderItemBilling') + .where(invoiceId: parameters.invoiceId) + .queryList() + .each { + it.quantity = 0 + it.store() + } + from('OrderAdjustmentBilling') + .where(invoiceId: parameters.invoiceId) + .queryList() + .each { + it.amount = 0 + it.store() + } + return success() +} + +/** + * Service set status of Invoices in bulk. + * @return Success response + */ +Map massChangeInvoiceStatus() { + parameters.invoiceIds.each { + run service: 'setInvoiceStatus', with: [invoiceId: it, + statusId: parameters.statusId] + } + return success() +} + +/** + * Set Parameter And Call Tax Calculate Service + * @return Success response + */ +Map addTaxOnInvoice() { + GenericValue invoice = from('Invoice').where(parameters).cache().queryOne() + if (!invoice) { + return error(label('AccountingUiLabels', 'AccountingInvoiceNotFound', parameters)) + } + GenericValue shippingContact = from('PartyContactMechPurpose') + .where(partyId: invoice.partyId, + contactMechPurposeTypeId: 'SHIPPING_LOCATION') + .queryFirst() ?: + from('PartyContactMechPurpose') + .where(partyId: invoice.partyId, + contactMechPurposeTypeId: 'GENERAL_LOCATION') + .queryFirst() + if (!shippingContact) { + return error(label('AccountingUiLabels', 'AccountingTaxCannotCalculate')) + } + GenericValue postalAddress = from('PostalAddress').where(contactMechId: shippingContact.contactMechId).cache().queryOne() + Map addTaxMap = [billToPartyId: invoice.invoiceTypeId == 'SALES_INVOICE' ? invoice.partyId : invoice.partyIdFrom, + payToPartyId: invoice.partyIdFrom, + orderPromotionsAmount: 0, + orderShippingAmount: 0, + shippingAddress: postalAddress, + itemProductList: [], + itemAmountList: [], + itemPriceList: [], + itemQuantityList: [], + itemShippingList: []] + List invoiceItems = invoice.getRelated('InvoiceItem', null, null, false) + invoiceItems.each { + BigDecimal totalAmount = 0 + if (it.productId) { + addTaxMap.itemProductList << from('Product').where(productId: it.productId).cache().queryOne() + List promoAdjs = EntityUtil.filterByAnd(invoiceItems, + [productId: it.productId, + invoiceItemTypeId: 'ITM_PROMOTION_ADJ']) + totalAmount = it.amount * it.quantity + if (promoAdjs) { + totalAmount -= it.amount + } + } + addTaxMap.itemAmountList << totalAmount + addTaxMap.itemPriceList << it.amount + addTaxMap.itemQuantityList << it.quantity + addTaxMap.itemShippingList << 0 + } + if (!addTaxMap.itemProductList) { + return error(label('AccountingUiLabels', 'AccountingTaxProductIdCannotCalculate')) + } + Map serviceResult = run service: 'calcTax', with: addTaxMap + Map itemMap = [itemSeqIdList: [], + productList: []] + invoiceItems.findAll { it.productId }.each { + itemMap.itemSeqIdList << it.invoiceItemSeqId + itemMap.productList << it.productId + } + Long countItemId = -1 + serviceResult.itemAdjustments.each { + countItemId ++ + if (it) { + it.each { + run service: 'createInvoiceItem', with: [invoiceItemTypeId: invoice.invoiceTypeId == 'PURCHASE_INVOICE' ? + 'PITM_SALES_TAX' : 'ITM_SALES_TAX', + invoiceId: invoice.invoiceId, + overrideGlAccountId: it.overrideGlAccountId, + productId: itemMap.productList[countItemId], + taxAuthPartyId: it.taxAuthPartyId, + taxAuthGeoId: it.taxAuthGeoId, + amount: it.amount, + quantity: 1, + parentInvoiceItemSeqId: itemMap.itemSeqIdList[countItemId], + taxAuthorityRateSeqId: it.taxAuthorityRateSeqId, + description: it.comments] + } + } + } + serviceResult.orderAdjustments.each { + run service: 'createInvoiceItem', with: [invoiceItemTypeId: invoice.invoiceTypeId == 'PURCHASE_INVOICE' ? + 'PITM_SALES_TAX' : 'ITM_SALES_TAX', + invoiceId: invoice.invoiceId, + overrideGlAccountId: it.overrideGlAccountId, + taxAuthPartyId: it.taxAuthPartyId, + taxAuthGeoId: it.taxAuthGeoId, + amount: it.amount, + quantity: 1, + taxAuthorityRateSeqId: it.taxAuthorityRateSeqId, + description: it.comments] + } + return success() +} + +/** + * Create an invoice from existing order when invoicePerShipment is N + * @return Success response + */ +Map createInvoiceFromOrder() { + GenericValue order = from('OrderHeader').where(parameters).queryOne() + String invoicePerShipment = order?.invoicePerShipment ?: + EntityUtilProperties.getPropertyValue('accounting', 'create.invoice.per.shipment', 'N', delegator) + if (invoicePerShipment == 'N') { + List orderItemBillingItemsSeqIds = from('OrderItemBilling').where(orderId: order.orderId).getFieldList('orderItemSeqId') + if (!orderItemBillingItemsSeqIds) { + Map serviceResult = run service: 'createInvoiceForOrderAllItems', with: [orderId: order.orderId] + return serviceResult + } + List orderItems = from('OrderItem').where(orderId: order.orderId).queryList() + orderItems = orderItems.findAll { !orderItemBillingItemsSeqIds.contains(it.orderItemSeqId) } + Map serviceResult = run service: 'createInvoiceForOrder', with: [orderId: order.orderId, + billItems: orderItems] + return serviceResult + } + return success() +} + +/** + * check if a invoice is in a foreign currency related to the accounting company. + * @return Success response + */ +Map isInvoiceInForeignCurrency() { + GenericValue invoice = from('Invoice').where(parameters).cache().queryOne() + if (!invoice) { + return error(label('AccountingUiLabels', 'AccountingInvoiceNotFound', parameters)) + } + String partyId = EntityTypeUtil.hasParentType(delegator, 'InvoiceType', 'invoiceTypeId', + invoice.invoiceTypeId, 'parentTypeId', 'PURCHASE_INVOICE') ? + invoice.partyId : invoice.partyIdFrom + Map serviceResult = run service: 'getPartyAccountingPreferences', with: [organizationPartyId: partyId] + return success([isForeign: invoice.currencyUomId == serviceResult.baseCurrencyUomId]) +} diff --git a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/payment/PaymentServices.groovy b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/payment/PaymentServices.groovy index 11d3b3cd93..8e536328b7 100644 --- a/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/payment/PaymentServices.groovy +++ b/applications/accounting/src/main/groovy/org/apache/ofbiz/accounting/payment/PaymentServices.groovy @@ -960,3 +960,63 @@ Map createMatchingPaymentApplication() { } return success() } + +/** + * Remove an existing payment application + * @return Success response after remove, error response otherwise. + */ +Map removePaymentApplication() { + GenericValue paymentApplication = from('PaymentApplication').where(parameters).queryOne() + if (!paymentApplication) { + return error(label('AccountingUiLabels', 'AccountingPaymentApplicationNotFound', parameters)) + } + Map paymentApplicationFields = paymentApplication.getAllFields() + + String toMessage = '' + // check payment + if (paymentApplication.paymentId) { + GenericValue payment = from('Payment').where(paymentId: paymentApplication.paymentId).queryOne() + if (payment.statusId == 'PMNT_CONFIRMED') { + return error(label('AccountingUiLabels', 'AccountingPaymentApplicationCannotRemovedWithConfirmedStatus')) + } + } + + // check invoice + if (paymentApplication.invoiceId) { + // if the invoice is already PAID, then set it back to READY and clear out the paidDate + GenericValue invoice = from('Invoice').where(invoiceId: paymentApplication.invoiceId).queryOne() + if (invoice.statusId == 'INVOICE_PAID') { + run service: 'setInvoiceStatus', with: [invoiceId: paymentApplication.invoiceId, + statustId: 'INVOICE_READY'] + } + toMessage = label('AccountingUiLabels', 'AccountingPaymentApplToInvoice', paymentApplicationFields) + } + + // check invoice item + if (paymentApplication.invoiceItemSeqId) { + toMessage = label('AccountingUiLabels', 'AccountingApplicationToInvoiceItem', paymentApplicationFields) + } + + // check toPayment + if (paymentApplication.toPaymentId) { + GenericValue toPayment = from('Payment').where(paymentId: paymentApplication.toPaymentId).queryOne() + if (toPayment.statusId == 'PMNT_CONFIRMED') { + return error(label('AccountingUiLabels', 'AccountingPaymentApplicationCannotRemovedWithConfirmedStatus')) + } + toMessage = label('AccountingUiLabels', 'AccountingPaymentApplToPayment', paymentApplicationFields) + } + + // check billing account + if (paymentApplication.billingAccountId) { + toMessage = label('AccountingUiLabels', 'AccountingPaymentApplToBillingAccount', paymentApplicationFields) + } + + // check tax authority + if (paymentApplication.taxAuthGeoId) { + toMessage = label('AccountingUiLabels', 'AccountingPaymentApplToTaxAuth', paymentApplicationFields) + } + + // finally delete application + paymentApplication.remove() + return success(label('AccountingUiLabels', 'AccountingPaymentApplRemoved') + ' ' + toMessage, paymentApplicationFields) +} diff --git a/applications/accounting/webapp/accounting/WEB-INF/controller.xml b/applications/accounting/webapp/accounting/WEB-INF/controller.xml index 67ab3dd672..717abfdad3 100644 --- a/applications/accounting/webapp/accounting/WEB-INF/controller.xml +++ b/applications/accounting/webapp/accounting/WEB-INF/controller.xml @@ -2546,7 +2546,7 @@ under the License. <!--Add Tax Settings --> <request-map uri="addtax"> <security auth="true" https="true"/> - <event type="service" invoke="addtax"/> + <event type="service" invoke="addTaxOnInvoice"/> <response name="success" type="view" value="ViewInvoice"/> <response name="error" type="view" value="ViewInvoice"/> </request-map>