Fixed issue 39617: Allows Automatic Invoice from Goods Shipment
authorNono Carballo <nonofce@gmail.com>
Thu, 04 Oct 2018 15:59:12 -0400
changeset 34964 a3bda4f3376a
parent 34962 6323b569fcbb
child 34965 f2c342521137
Fixed issue 39617: Allows Automatic Invoice from Goods Shipment

- A new field was added to "Request Process" pop up window. The field is only
visible in Goods Shipment window if the selected document is in draft status.
- A new class was created for automatically creating invoices from Goods
Shipment, considering the invoice terms of the order linked to the shipment
lines, when exists.
- The ProcessGoods process was modified to invoke the new API after complete the
document, if the field in the pop up window is checked.
- A new button was added to Goods Shipment window to allow generate invoice
from Goods Shipment. The button is only visible if the document is in status
"CO" and is not completely invoiced.
- Automated tests were created.
src-db/database/model/tables/M_INOUT.xml
src-db/database/sourcedata/AD_COLUMN.xml
src-db/database/sourcedata/AD_ELEMENT.xml
src-db/database/sourcedata/AD_FIELD.xml
src-db/database/sourcedata/AD_MESSAGE.xml
src-db/database/sourcedata/AD_TEXTINTERFACES.xml
src-db/database/sourcedata/OBUIAPP_PROCESS.xml
src-test/src/org/openbravo/test/AllAntTaskTests.java
src-test/src/org/openbravo/test/materialMgmt/invoiceFromShipment/InvoiceFromShipmentTest.java
src-test/src/org/openbravo/test/materialMgmt/invoiceFromShipment/TestUtils.java
src/org/openbravo/common/actionhandler/InvoiceFromShipmentActionHandler.java
src/org/openbravo/erpCommon/ad_actionButton/DocAction.html
src/org/openbravo/erpCommon/ad_actionButton/ProcessGoods.java
src/org/openbravo/materialmgmt/ShipmentProcessor.java
--- a/src-db/database/model/tables/M_INOUT.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/model/tables/M_INOUT.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -265,6 +265,10 @@
         <default><![CDATA[N]]></default>
         <onCreateDefault><![CDATA['Y']]></onCreateDefault>
       </column>
+      <column name="INVOICEFROMSHIPMENT" primaryKey="false" required="false" type="CHAR" size="1" autoIncrement="false">
+        <default/>
+        <onCreateDefault/>
+      </column>
       <foreign-key foreignTable="M_FREIGHTCATEGORY" name="M_FREIGHTCATEGORY_M_INOUT">
         <reference local="M_FREIGHTCATEGORY_ID" foreign="M_FREIGHTCATEGORY_ID"/>
       </foreign-key>
--- a/src-db/database/sourcedata/AD_COLUMN.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/sourcedata/AD_COLUMN.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -356602,6 +356602,45 @@
 <!--BF04DD653CA1489DABA8CB2BBD788C78-->  <ALLOWED_CROSS_ORG_LINK><![CDATA[N]]></ALLOWED_CROSS_ORG_LINK>
 <!--BF04DD653CA1489DABA8CB2BBD788C78--></AD_COLUMN>
 
+<!--BF2DF59DAC32474692434F5A21FB0C27--><AD_COLUMN>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_COLUMN_ID><![CDATA[BF2DF59DAC32474692434F5A21FB0C27]]></AD_COLUMN_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <NAME><![CDATA[Invoicefromshipment]]></NAME>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <DESCRIPTION><![CDATA[Generate Invoice from Shipment]]></DESCRIPTION>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <HELP><![CDATA[Generate Invoice from Shipment considering invoice terms of orders linked to shipment lines.]]></HELP>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <COLUMNNAME><![CDATA[Invoicefromshipment]]></COLUMNNAME>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_TABLE_ID><![CDATA[319]]></AD_TABLE_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_REFERENCE_ID><![CDATA[28]]></AD_REFERENCE_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <FIELDLENGTH><![CDATA[1]]></FIELDLENGTH>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISKEY><![CDATA[N]]></ISKEY>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISPARENT><![CDATA[N]]></ISPARENT>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISMANDATORY><![CDATA[N]]></ISMANDATORY>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISUPDATEABLE><![CDATA[Y]]></ISUPDATEABLE>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISIDENTIFIER><![CDATA[N]]></ISIDENTIFIER>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <SEQNO><![CDATA[500]]></SEQNO>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISTRANSLATED><![CDATA[N]]></ISTRANSLATED>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISENCRYPTED><![CDATA[N]]></ISENCRYPTED>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISSELECTIONCOLUMN><![CDATA[N]]></ISSELECTIONCOLUMN>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_ELEMENT_ID><![CDATA[175283CDAAA34A78BF8A7E6BD069D2B3]]></AD_ELEMENT_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISSESSIONATTR><![CDATA[N]]></ISSESSIONATTR>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISSECONDARYKEY><![CDATA[N]]></ISSECONDARYKEY>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISDESENCRYPTABLE><![CDATA[N]]></ISDESENCRYPTABLE>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <DEVELOPMENTSTATUS><![CDATA[RE]]></DEVELOPMENTSTATUS>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <POSITION><![CDATA[68]]></POSITION>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISTRANSIENT><![CDATA[N]]></ISTRANSIENT>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISAUTOSAVE><![CDATA[Y]]></ISAUTOSAVE>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <VALIDATEONNEW><![CDATA[Y]]></VALIDATEONNEW>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <IMAGESIZEVALUESACTION><![CDATA[N]]></IMAGESIZEVALUESACTION>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ISUSEDSEQUENCE><![CDATA[N]]></ISUSEDSEQUENCE>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ALLOWSORTING><![CDATA[Y]]></ALLOWSORTING>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ALLOWFILTERING><![CDATA[Y]]></ALLOWFILTERING>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <ALLOWED_CROSS_ORG_LINK><![CDATA[N]]></ALLOWED_CROSS_ORG_LINK>
+<!--BF2DF59DAC32474692434F5A21FB0C27-->  <EM_OBUIAPP_PROCESS_ID><![CDATA[62250E8866EA4D96A66C309878DC039E]]></EM_OBUIAPP_PROCESS_ID>
+<!--BF2DF59DAC32474692434F5A21FB0C27--></AD_COLUMN>
+
 <!--BF75CF4CF9CC4AE3A5D42DAF00C42CDD--><AD_COLUMN>
 <!--BF75CF4CF9CC4AE3A5D42DAF00C42CDD-->  <AD_COLUMN_ID><![CDATA[BF75CF4CF9CC4AE3A5D42DAF00C42CDD]]></AD_COLUMN_ID>
 <!--BF75CF4CF9CC4AE3A5D42DAF00C42CDD-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/src-db/database/sourcedata/AD_ELEMENT.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/sourcedata/AD_ELEMENT.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -21650,6 +21650,20 @@
 <!--17485BBD94A447C2A0C823181EF0F066-->  <ISGLOSSARY><![CDATA[N]]></ISGLOSSARY>
 <!--17485BBD94A447C2A0C823181EF0F066--></AD_ELEMENT>
 
+<!--175283CDAAA34A78BF8A7E6BD069D2B3--><AD_ELEMENT>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <AD_ELEMENT_ID><![CDATA[175283CDAAA34A78BF8A7E6BD069D2B3]]></AD_ELEMENT_ID>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <COLUMNNAME><![CDATA[Invoicefromshipment]]></COLUMNNAME>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <NAME><![CDATA[Generate Invoice from Shipment]]></NAME>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <PRINTNAME><![CDATA[Generate Invoice from Shipment]]></PRINTNAME>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <DESCRIPTION><![CDATA[Generate Invoice from Shipment]]></DESCRIPTION>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <HELP><![CDATA[Generate Invoice from Shipment considering invoice terms of orders linked to shipment lines.]]></HELP>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3-->  <ISGLOSSARY><![CDATA[N]]></ISGLOSSARY>
+<!--175283CDAAA34A78BF8A7E6BD069D2B3--></AD_ELEMENT>
+
 <!--1781EBA322894DF58835305F5D6B26DA--><AD_ELEMENT>
 <!--1781EBA322894DF58835305F5D6B26DA-->  <AD_ELEMENT_ID><![CDATA[1781EBA322894DF58835305F5D6B26DA]]></AD_ELEMENT_ID>
 <!--1781EBA322894DF58835305F5D6B26DA-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/src-db/database/sourcedata/AD_FIELD.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/sourcedata/AD_FIELD.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -313551,6 +313551,35 @@
 <!--EE0FACACA9D34C06946E1EEC0C194079-->  <EM_OBUIAPP_SHOWSUMMARY><![CDATA[N]]></EM_OBUIAPP_SHOWSUMMARY>
 <!--EE0FACACA9D34C06946E1EEC0C194079--></AD_FIELD>
 
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78--><AD_FIELD>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <AD_FIELD_ID><![CDATA[EE3B8A7F9CE540CF87CE22CDA6E23A78]]></AD_FIELD_ID>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <NAME><![CDATA[Generate Invoice from Shipment]]></NAME>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <DESCRIPTION><![CDATA[Generate Invoice from Shipment]]></DESCRIPTION>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <HELP><![CDATA[Generate Invoice from Shipment considering invoice terms of orders linked to shipment lines.]]></HELP>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISCENTRALLYMAINTAINED><![CDATA[Y]]></ISCENTRALLYMAINTAINED>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <AD_TAB_ID><![CDATA[257]]></AD_TAB_ID>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <AD_COLUMN_ID><![CDATA[BF2DF59DAC32474692434F5A21FB0C27]]></AD_COLUMN_ID>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <IGNOREINWAD><![CDATA[N]]></IGNOREINWAD>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISDISPLAYED><![CDATA[Y]]></ISDISPLAYED>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <DISPLAYLOGIC><![CDATA[@DocStatus@='CO' & @Iscompletelyinvoiced@='N']]></DISPLAYLOGIC>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <DISPLAYLENGTH><![CDATA[60]]></DISPLAYLENGTH>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISREADONLY><![CDATA[N]]></ISREADONLY>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <SEQNO><![CDATA[2060]]></SEQNO>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISSAMELINE><![CDATA[N]]></ISSAMELINE>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISFIELDONLY><![CDATA[N]]></ISFIELDONLY>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISENCRYPTED><![CDATA[N]]></ISENCRYPTED>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <SHOWINRELATION><![CDATA[N]]></SHOWINRELATION>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISFIRSTFOCUSEDFIELD><![CDATA[N]]></ISFIRSTFOCUSEDFIELD>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <STARTINODDCOLUMN><![CDATA[N]]></STARTINODDCOLUMN>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <STARTNEWLINE><![CDATA[N]]></STARTNEWLINE>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <ISSHOWNINSTATUSBAR><![CDATA[N]]></ISSHOWNINSTATUSBAR>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78-->  <EM_OBUIAPP_SHOWSUMMARY><![CDATA[N]]></EM_OBUIAPP_SHOWSUMMARY>
+<!--EE3B8A7F9CE540CF87CE22CDA6E23A78--></AD_FIELD>
+
 <!--EE42FF358039451A8E1DBB610AE46537--><AD_FIELD>
 <!--EE42FF358039451A8E1DBB610AE46537-->  <AD_FIELD_ID><![CDATA[EE42FF358039451A8E1DBB610AE46537]]></AD_FIELD_ID>
 <!--EE42FF358039451A8E1DBB610AE46537-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/src-db/database/sourcedata/AD_MESSAGE.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/sourcedata/AD_MESSAGE.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -20959,6 +20959,18 @@
 <!--659D3B84D0AF4B2396F02889BF7F9914-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--659D3B84D0AF4B2396F02889BF7F9914--></AD_MESSAGE>
 
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6--><AD_MESSAGE>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <AD_MESSAGE_ID><![CDATA[659DCCF7ACF5482DBFAA1370BEF88FD6]]></AD_MESSAGE_ID>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <VALUE><![CDATA[NewInvoiceGenerated]]></VALUE>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <MSGTEXT><![CDATA[New Invoice generated with document number : %s]]></MSGTEXT>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <MSGTYPE><![CDATA[S]]></MSGTYPE>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--659DCCF7ACF5482DBFAA1370BEF88FD6--></AD_MESSAGE>
+
 <!--65C05BD368ED471CB1E6AE97DD911EDF--><AD_MESSAGE>
 <!--65C05BD368ED471CB1E6AE97DD911EDF-->  <AD_MESSAGE_ID><![CDATA[65C05BD368ED471CB1E6AE97DD911EDF]]></AD_MESSAGE_ID>
 <!--65C05BD368ED471CB1E6AE97DD911EDF-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
@@ -27188,6 +27200,18 @@
 <!--E180D66331CC42218EE3A46A682D29BD-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
 <!--E180D66331CC42218EE3A46A682D29BD--></AD_MESSAGE>
 
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF--><AD_MESSAGE>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <AD_MESSAGE_ID><![CDATA[E1AE98E11AAB4AA5A10DB6A6DA66E3BF]]></AD_MESSAGE_ID>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <VALUE><![CDATA[NoInvoiceGenerated]]></VALUE>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <MSGTEXT><![CDATA[No invoice has been generated.]]></MSGTEXT>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <MSGTYPE><![CDATA[I]]></MSGTYPE>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF-->  <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N>
+<!--E1AE98E11AAB4AA5A10DB6A6DA66E3BF--></AD_MESSAGE>
+
 <!--E2619EAE728A409797BC6D9D7C7FC741--><AD_MESSAGE>
 <!--E2619EAE728A409797BC6D9D7C7FC741-->  <AD_MESSAGE_ID><![CDATA[E2619EAE728A409797BC6D9D7C7FC741]]></AD_MESSAGE_ID>
 <!--E2619EAE728A409797BC6D9D7C7FC741-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/src-db/database/sourcedata/AD_TEXTINTERFACES.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/sourcedata/AD_TEXTINTERFACES.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -20649,6 +20649,17 @@
 <!--A5DF7BC1C6C440048652EE5AEE8E55D2-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
 <!--A5DF7BC1C6C440048652EE5AEE8E55D2--></AD_TEXTINTERFACES>
 
+<!--A6A80F585A4E45098630A85CDC0594A0--><AD_TEXTINTERFACES>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <AD_TEXTINTERFACES_ID><![CDATA[A6A80F585A4E45098630A85CDC0594A0]]></AD_TEXTINTERFACES_ID>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <TEXT><![CDATA[Invoice if possible]]></TEXT>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <FILENAME><![CDATA[/org/openbravo/erpCommon/ad_actionButton/DocAction.html]]></FILENAME>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <ISUSED><![CDATA[Y]]></ISUSED>
+<!--A6A80F585A4E45098630A85CDC0594A0-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--A6A80F585A4E45098630A85CDC0594A0--></AD_TEXTINTERFACES>
+
 <!--A6A9B93641B042399A708A1445DD5EFE--><AD_TEXTINTERFACES>
 <!--A6A9B93641B042399A708A1445DD5EFE-->  <AD_TEXTINTERFACES_ID><![CDATA[A6A9B93641B042399A708A1445DD5EFE]]></AD_TEXTINTERFACES_ID>
 <!--A6A9B93641B042399A708A1445DD5EFE-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/src-db/database/sourcedata/OBUIAPP_PROCESS.xml	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-db/database/sourcedata/OBUIAPP_PROCESS.xml	Thu Oct 04 15:59:12 2018 -0400
@@ -341,6 +341,26 @@
 <!--5F7C5316CB7E4598898150AC88061B1B-->  <ISCANADDRECORDSTOSELECTOR><![CDATA[N]]></ISCANADDRECORDSTOSELECTOR>
 <!--5F7C5316CB7E4598898150AC88061B1B--></OBUIAPP_PROCESS>
 
+<!--62250E8866EA4D96A66C309878DC039E--><OBUIAPP_PROCESS>
+<!--62250E8866EA4D96A66C309878DC039E-->  <OBUIAPP_PROCESS_ID><![CDATA[62250E8866EA4D96A66C309878DC039E]]></OBUIAPP_PROCESS_ID>
+<!--62250E8866EA4D96A66C309878DC039E-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
+<!--62250E8866EA4D96A66C309878DC039E-->  <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID>
+<!--62250E8866EA4D96A66C309878DC039E-->  <ISACTIVE><![CDATA[Y]]></ISACTIVE>
+<!--62250E8866EA4D96A66C309878DC039E-->  <VALUE><![CDATA[InvoiceFromShipment]]></VALUE>
+<!--62250E8866EA4D96A66C309878DC039E-->  <NAME><![CDATA[Invoice From Shipment]]></NAME>
+<!--62250E8866EA4D96A66C309878DC039E-->  <DESCRIPTION><![CDATA[Generate Invoice from Goods Shipment]]></DESCRIPTION>
+<!--62250E8866EA4D96A66C309878DC039E-->  <HELP><![CDATA[Generate Invoice from Goods Shipment considering the Invoice Terms of Order linked to shipment lines]]></HELP>
+<!--62250E8866EA4D96A66C309878DC039E-->  <ACCESSLEVEL><![CDATA[1]]></ACCESSLEVEL>
+<!--62250E8866EA4D96A66C309878DC039E-->  <CLASSNAME><![CDATA[org.openbravo.common.actionhandler.InvoiceFromShipmentActionHandler]]></CLASSNAME>
+<!--62250E8866EA4D96A66C309878DC039E-->  <ISBACKGROUND><![CDATA[N]]></ISBACKGROUND>
+<!--62250E8866EA4D96A66C309878DC039E-->  <AD_MODULE_ID><![CDATA[0]]></AD_MODULE_ID>
+<!--62250E8866EA4D96A66C309878DC039E-->  <UIPATTERN><![CDATA[OBUIAPP_PickAndExecute]]></UIPATTERN>
+<!--62250E8866EA4D96A66C309878DC039E-->  <ISMULTIRECORD><![CDATA[N]]></ISMULTIRECORD>
+<!--62250E8866EA4D96A66C309878DC039E-->  <IS_EXPLICIT_ACCESS><![CDATA[N]]></IS_EXPLICIT_ACCESS>
+<!--62250E8866EA4D96A66C309878DC039E-->  <ISGRIDLEGACY><![CDATA[N]]></ISGRIDLEGACY>
+<!--62250E8866EA4D96A66C309878DC039E-->  <ISCANADDRECORDSTOSELECTOR><![CDATA[N]]></ISCANADDRECORDSTOSELECTOR>
+<!--62250E8866EA4D96A66C309878DC039E--></OBUIAPP_PROCESS>
+
 <!--653F9E5D2CCB48E081D98D000EE7CBCF--><OBUIAPP_PROCESS>
 <!--653F9E5D2CCB48E081D98D000EE7CBCF-->  <OBUIAPP_PROCESS_ID><![CDATA[653F9E5D2CCB48E081D98D000EE7CBCF]]></OBUIAPP_PROCESS_ID>
 <!--653F9E5D2CCB48E081D98D000EE7CBCF-->  <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID>
--- a/src-test/src/org/openbravo/test/AllAntTaskTests.java	Tue Nov 13 09:24:05 2018 +0100
+++ b/src-test/src/org/openbravo/test/AllAntTaskTests.java	Thu Oct 04 15:59:12 2018 -0400
@@ -73,6 +73,7 @@
 import org.openbravo.test.expression.OBBindingsTest;
 import org.openbravo.test.generalsetup.enterprise.organization.ADOrgPersistInfoTestSuite;
 import org.openbravo.test.inventoryStatus.InventoryStatusTest;
+import org.openbravo.test.materialMgmt.invoiceFromShipment.InvoiceFromShipmentTest;
 import org.openbravo.test.materialMgmt.iscompletelyinvoicedshipment.IsCompletelyInvoicedShipment;
 import org.openbravo.test.model.ClassLoaderTest;
 import org.openbravo.test.model.DBModifiedTest;
@@ -313,7 +314,10 @@
     ReferencedInventoryTestSuite.class,
 
     // AD_Org Persist Information
-    ADOrgPersistInfoTestSuite.class
+    ADOrgPersistInfoTestSuite.class,
+    
+    // Automatic Invoice from Goods Shipment
+    InvoiceFromShipmentTest.class
 
 })
 public class AllAntTaskTests {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src-test/src/org/openbravo/test/materialMgmt/invoiceFromShipment/InvoiceFromShipmentTest.java	Thu Oct 04 15:59:12 2018 -0400
@@ -0,0 +1,796 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html 
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License. 
+ * The Original Code is Openbravo ERP. 
+ * The Initial Developer of the Original Code is Openbravo SLU 
+ * All portions are Copyright (C) 2018 Openbravo SLU
+ * All Rights Reserved. 
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+
+package org.openbravo.test.materialMgmt.invoiceFromShipment;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.math.BigDecimal;
+
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.hibernate.query.Query;
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.base.secureApp.VariablesSecureApp;
+import org.openbravo.base.weld.WeldUtils;
+import org.openbravo.base.weld.test.WeldBaseTest;
+import org.openbravo.client.kernel.RequestContext;
+import org.openbravo.common.actionhandler.createlinesfromprocess.CreateInvoiceLinesFromProcess;
+import org.openbravo.dal.core.DalUtil;
+import org.openbravo.dal.core.OBContext;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.dal.service.OBQuery;
+import org.openbravo.erpCommon.utility.SequenceIdData;
+import org.openbravo.erpCommon.utility.Utility;
+import org.openbravo.materialmgmt.ShipmentProcessor;
+import org.openbravo.model.common.invoice.Invoice;
+import org.openbravo.model.common.invoice.InvoiceLine;
+import org.openbravo.model.common.order.Order;
+import org.openbravo.model.common.order.OrderLine;
+import org.openbravo.model.common.plm.Product;
+import org.openbravo.model.materialmgmt.transaction.ShipmentInOut;
+import org.openbravo.model.materialmgmt.transaction.ShipmentInOutLine;
+import org.openbravo.service.db.DalConnectionProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test class for Automatic Invoice From Goods Shipment test cases
+ *
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class InvoiceFromShipmentTest extends WeldBaseTest {
+
+  private static final Logger log = LoggerFactory.getLogger(InvoiceFromShipmentTest.class);
+
+  private static final String CLIENT_ID = "4028E6C72959682B01295A070852010D"; // QA Testing
+  private static final String ORG_ID = "357947E87C284935AD1D783CF6F099A1"; // Spain
+  private static final String USER_ID = "100"; // Openbravo
+  private static final String ROLE_ID = "4028E6C72959682B01295A071429011E"; // QA Testing Admin
+
+  private static final String GOODS_SHIPMENT_ID = "8BEAC8CAFFCE444FA15D0170F897B641";
+  private static final String SALES_ORDER = "5B29AF263D004CD3830D4F9B23C17DFD";
+  private static final String SALES_INVOICE = "B859F1D34CD348998F4D54B571010C8F";
+  private static final String T_SHIRTS_PRODUCT_ID = "0CF7C882B8BD4D249F3BCC8727A736D1";
+  private static final String DO_NOT_INVOICE = "N";
+  private static final String IMMEDIATE = "I";
+  private static final String AFTER_DELIVERY = "D";
+  private static final String AFTER_ORDER_DELIVERY = "O";
+
+  @Before
+  public void initialize() {
+    log.info("Initializing Invoice From Shipment Tests ...");
+    OBContext.setOBContext(USER_ID, ROLE_ID, CLIENT_ID, ORG_ID);
+    final OBContext obContext = OBContext.getOBContext();
+    final VariablesSecureApp vars = new VariablesSecureApp(obContext.getUser().getId(), obContext
+        .getCurrentClient().getId(), obContext.getCurrentOrganization().getId(), obContext
+        .getRole().getId(), obContext.getLanguage().getLanguage());
+    RequestContext.get().setVariableSecureApp(vars);
+  }
+
+  /**
+   * Generating invoice from a Goods Shipment linked to a Sales Order with invoice term
+   * "After Delivery"
+   * <ol>
+   * <li>Create a Sales Order with invoice term "After Delivery".</li>
+   * <li>Adds two lines of product. Book the order.</li>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Adds just one line from the previous order.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify an invoice was created and processed containing the line from Goods Shipment.</li>
+   * </ol>
+   */
+  @Test
+  public void invoiceFromShipment_001() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product product = TestUtils
+          .cloneProduct(T_SHIRTS_PRODUCT_ID, "InvoiceFromShipment_001");
+      final Order salesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_001", AFTER_DELIVERY);
+      final OrderLine orderLine = getOrderLineByLineNo(salesOrder, 10L);
+      setProductInOrderLine(orderLine, product);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(salesOrder);
+
+      final ShipmentInOut shipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_001");
+      final ShipmentInOutLine shipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(shipmentLine, product);
+      setOrderLineInShipmentLine(shipmentLine, orderLine);
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertGeneratedInvoiceLine(invoice, product, new BigDecimal(12));
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Generating invoice from a Goods Shipment linked to a Sales Order with invoice term
+   * "After Order Delivery"
+   * <ol>
+   * <li>Create a Sales Order with invoice term "After Order Delivery".</li>
+   * <li>Adds two lines of product. Book the order.</li>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Adds the first line from the previous order.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify no invoice was created.</li>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Adds the second line from the previous order.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify an invoice was created and processed containing the two lines from Sales Order.</li>
+   * </ol>
+   */
+
+  @Test
+  public void invoiceFromShipment_002() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product productOne = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_002");
+      final Product productTwo = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_002");
+
+      final Order salesOrder = createAfterOrderDeliveredOrder(SALES_ORDER,
+          "InvoiceFromShipment_002");
+      final OrderLine firstLine = getOrderLineByLineNo(salesOrder, 10L);
+      setProductInOrderLine(firstLine, productOne);
+      final OrderLine secondLine = getOrderLineByLineNo(salesOrder, 20L);
+      setProductInOrderLine(secondLine, productTwo);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(salesOrder);
+
+      final ShipmentInOut shipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_002");
+      final ShipmentInOutLine shipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(shipmentLine, productOne);
+      setOrderLineInShipmentLine(shipmentLine, firstLine);
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().flush();
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertNoInvoiceWasGenerated(invoice);
+
+      final ShipmentInOut secondShipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_002");
+      final ShipmentInOutLine secondShipmentLine = getShipmentLineByLineNo(secondShipment, 10L);
+      setProductInShipmentLine(secondShipmentLine, productTwo);
+      setOrderLineInShipmentLine(secondShipmentLine, secondLine);
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(secondShipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice secondInvoice = new ShipmentProcessor(secondShipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertGeneratedInvoiceLine(secondInvoice, productOne, new BigDecimal(12));
+      assertGeneratedInvoiceLine(secondInvoice, productTwo, new BigDecimal(12));
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Generating invoice from Goods Shipment not linked to a Sales Order
+   * <ol>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Adds two lines of product.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify an invoice was created and processed containing the lines from Goods Shipment.</li>
+   * </ol>
+   */
+
+  @Test
+  public void invoiceFromShipment_003() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product productOne = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_003");
+      final Product productTwo = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_003");
+
+      final ShipmentInOut shipment = createShipmentReceiptWithTwoLines(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_003");
+
+      final ShipmentInOutLine firstShipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(firstShipmentLine, productOne);
+      ShipmentInOutLine secondShipmentLine = getShipmentLineByLineNo(shipment, 20L);
+      setProductInShipmentLine(secondShipmentLine, productTwo);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertGeneratedInvoiceLine(invoice, productOne, new BigDecimal(12));
+      assertGeneratedInvoiceLine(invoice, productTwo, new BigDecimal(12));
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Generating invoice from Goods Shipment with lines linked to Sales Order with invoice term
+   * “After Delivery” and “After Order Delivery”.
+   * <ol>
+   * <li>Create a Sales Order with invoice term “After Delivery”.</li>
+   * <li>Add one line of product. Book the order.</li>
+   * <li>Create a second Sales Order with invoice term “After Order Delivery”.</li>
+   * <li>Add two lines of product. Book the order.</li>
+   * <li>Create a Goods Shipment</li>
+   * <li>Add the line from the first order</li>
+   * <li>Add the first line from the second order</li>
+   * <li>Add a line manually</li>
+   * <li>Complete the document invoicing if possible</li>
+   * <li>Verify an invoice was created with the line from the first order and the one added
+   * manually.</li>
+   * <li>Create a second Goods Shipment</li>
+   * <li>Add the second line from the second order</li>
+   * <li>Complete the document invoicing if possible</li>
+   * <li>Verify an invoice was created containing both lines from the second order.</li>
+   * </ol>
+   */
+
+  @Test
+  public void invoiceFromShipment_004() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product productOne = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_004");
+      final Product productTwo = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_004");
+      final Product productThree = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_004");
+      final Product productFour = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_004");
+
+      final Order firstSalesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_004", AFTER_DELIVERY);
+      final OrderLine firstLine = getOrderLineByLineNo(firstSalesOrder, 10L);
+      setProductInOrderLine(firstLine, productOne);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(firstSalesOrder);
+
+      final Order secondSalesOrder = createAfterOrderDeliveredOrder(SALES_ORDER,
+          "InvoiceFromShipment_004");
+      final OrderLine secondLine = getOrderLineByLineNo(secondSalesOrder, 10L);
+      setProductInOrderLine(secondLine, productTwo);
+      final OrderLine thirdLine = getOrderLineByLineNo(secondSalesOrder, 20L);
+      setProductInOrderLine(thirdLine, productThree);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(secondSalesOrder);
+
+      final ShipmentInOut shipment = createShipmentReceiptWithTwoLines(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_004");
+      final ShipmentInOutLine firstShipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(firstShipmentLine, productOne);
+      setOrderLineInShipmentLine(firstShipmentLine, firstLine);
+      final ShipmentInOutLine secondShipmentLine = getShipmentLineByLineNo(shipment, 20L);
+      setProductInShipmentLine(secondShipmentLine, productTwo);
+      setOrderLineInShipmentLine(secondShipmentLine, secondLine);
+      final ShipmentInOutLine thirdShipmentLine = addLineToShipment(shipment);
+      setProductInShipmentLine(thirdShipmentLine, productFour);
+      setOrderLineInShipmentLine(thirdShipmentLine, null);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertInvoiceLineNumber(invoice, 2);
+      assertGeneratedInvoiceLine(invoice, productOne, new BigDecimal(12));
+      assertGeneratedInvoiceLine(invoice, productFour, new BigDecimal(12));
+
+      final ShipmentInOut secondShipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_004");
+      final ShipmentInOutLine fourthShipmentLine = getShipmentLineByLineNo(secondShipment, 10L);
+      setProductInShipmentLine(fourthShipmentLine, productThree);
+      setOrderLineInShipmentLine(fourthShipmentLine, thirdLine);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(secondShipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice secondInvoice = new ShipmentProcessor(secondShipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertInvoiceLineNumber(secondInvoice, 2);
+      assertGeneratedInvoiceLine(secondInvoice, productTwo, new BigDecimal(12));
+      assertGeneratedInvoiceLine(secondInvoice, productThree, new BigDecimal(12));
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Generating invoice from Goods Shipment with incomplete delivery
+   * <ol>
+   * <li>Create a Sales Order win invoice term “After Delivery”.</li>
+   * <li>Adds one line of product. Book the order.</li>
+   * <li>Create a second Sales Order with invoice term “After Order Delivery”.</li>
+   * <li>Adds one line of product. Book the order.</li>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Adds the line from the first order. Set movement quantity less than the proposed value.</li>
+   * <li>Adds the line from the second order. Set movement quantity less than the proposed value.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify an invoice was generated containing just the line from the first order</li>
+   * </ol>
+   */
+
+  @Test
+  public void invoiceFromShipment_005() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product productOne = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_005");
+      final Product productTwo = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_005");
+
+      final Order firstSalesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_005", AFTER_DELIVERY);
+      final OrderLine firstLine = getOrderLineByLineNo(firstSalesOrder, 10L);
+      setProductInOrderLine(firstLine, productOne);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(firstSalesOrder);
+
+      final Order secondSalesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_005", AFTER_ORDER_DELIVERY);
+      final OrderLine secondLine = getOrderLineByLineNo(secondSalesOrder, 10L);
+      setProductInOrderLine(secondLine, productTwo);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(secondSalesOrder);
+
+      final ShipmentInOut shipment = createShipmentReceiptWithTwoLines(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_005");
+      final ShipmentInOutLine firstShipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(firstShipmentLine, productOne);
+      setOrderLineInShipmentLine(firstShipmentLine, firstLine);
+      updateMovementQuantity(firstShipmentLine, BigDecimal.TEN);
+      final ShipmentInOutLine secondShipmentLine = getShipmentLineByLineNo(shipment, 20L);
+      setProductInShipmentLine(secondShipmentLine, productTwo);
+      setOrderLineInShipmentLine(secondShipmentLine, secondLine);
+      updateMovementQuantity(secondShipmentLine, BigDecimal.TEN);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertInvoiceLineNumber(invoice, 1);
+      assertGeneratedInvoiceLine(invoice, productOne, BigDecimal.TEN);
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Generating invoice from Goods Shipment with lines linked to Sales Order with invoice terms
+   * “Immediate” and “Do not invoice”
+   * <ol>
+   * <li>Create a Sales Order with invoice term “Immediate”</li>
+   * <li>Add one line of product. Book the order.</li>
+   * <li>Create a Sales Order with invoice term “Do not invoice”.</li>
+   * <li>Add one line to the order. Book the order.</li>
+   * <li>Create a Goods Shipment with the lines from the two orders.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify an invoice was created containing a line linked to the shipment line from
+   * "Immediate" Sales Order</li>
+   * </ol>
+   */
+
+  @Test
+  public void invoiceFromShipment_006() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product productOne = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_006");
+      final Product productTwo = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_006");
+
+      final Order firstSalesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_006", IMMEDIATE);
+      final OrderLine firstLine = getOrderLineByLineNo(firstSalesOrder, 10L);
+      setProductInOrderLine(firstLine, productOne);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(firstSalesOrder);
+
+      final Order secondSalesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_006", DO_NOT_INVOICE);
+      final OrderLine secondLine = getOrderLineByLineNo(secondSalesOrder, 10L);
+      setProductInOrderLine(secondLine, productTwo);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(secondSalesOrder);
+
+      final ShipmentInOut shipment = createShipmentReceiptWithTwoLines(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_006");
+      final ShipmentInOutLine firstShipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(firstShipmentLine, productOne);
+      setOrderLineInShipmentLine(firstShipmentLine, firstLine);
+      final ShipmentInOutLine secondShipmentLine = getShipmentLineByLineNo(shipment, 20L);
+      setProductInShipmentLine(secondShipmentLine, productTwo);
+      setOrderLineInShipmentLine(secondShipmentLine, secondLine);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertInvoiceLineNumber(invoice, 1);
+      assertGeneratedInvoiceLine(invoice, productOne, new BigDecimal(12));
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Generating invoice from Goods Shipment with lines partially invoiced from an order with invoice
+   * term “After Order Delivery”
+   * <ol>
+   * <li>Create a Sales Order with invoice term “After Order Delivery”.</li>
+   * <li>Add two lines of product. Book the order.</li>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Add the first order line.</li>
+   * <li>Complete the document without invoicing.</li>
+   * <li>Create a second Goods Shipment.</li>
+   * <li>Add the second order line.</li>
+   * <li>Complete the document without invoicing.</li>
+   * <li>Create a Sales Invoice.</li>
+   * <li>Add the line for the first Goods Shipment.</li>
+   * <li>Invoice a quantity less than the movement quantity.</li>
+   * <li>Complete the document.</li>
+   * <li>Select the second Goods Shipment in Goods Shipment window.</li>
+   * <li>Generate invoice from shipment using the button.</li>
+   * <li>Verify a new invoice was created containing:</li>
+   * <ol>
+   * <li>A line with the product of the first Goods Shipment, and invoiced quantity as the
+   * difference between the movement quantity and the invoiced quantity of the Sales Invoice.</li>
+   * <li>A line with the product of the second Goods Shipment with invoiced quantity as the movement
+   * quantity</li>
+   * </ol>
+   * </ol>
+   */
+  @Test
+  public void invoiceFromShipment_007() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product productOne = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_007");
+      final Product productTwo = TestUtils.cloneProduct(T_SHIRTS_PRODUCT_ID,
+          "InvoiceFromShipment_007");
+
+      final Order salesOrder = createAfterOrderDeliveredOrder(SALES_ORDER,
+          "InvoiceFromShipment_007");
+      final OrderLine firstLine = getOrderLineByLineNo(salesOrder, 10L);
+      setProductInOrderLine(firstLine, productOne);
+      final OrderLine secondLine = getOrderLineByLineNo(salesOrder, 20L);
+      setProductInOrderLine(secondLine, productTwo);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(salesOrder);
+
+      final ShipmentInOut firstShipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_007");
+      final ShipmentInOutLine firstShipmentLine = getShipmentLineByLineNo(firstShipment, 10L);
+      setProductInShipmentLine(firstShipmentLine, productOne);
+      setOrderLineInShipmentLine(firstShipmentLine, firstLine);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(firstShipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = createInvoiceFromShipment(firstShipment, SALES_INVOICE);
+      TestUtils.processInvoice(invoice);
+
+      final ShipmentInOut secondShipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_007");
+      final ShipmentInOutLine secondShipmentLine = getShipmentLineByLineNo(secondShipment, 10L);
+      setProductInShipmentLine(secondShipmentLine, productTwo);
+      setOrderLineInShipmentLine(secondShipmentLine, secondLine);
+
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(secondShipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice secondInvoice = new ShipmentProcessor(secondShipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertInvoiceLineNumber(secondInvoice, 2);
+      assertGeneratedInvoiceLine(secondInvoice, productOne, new BigDecimal(2));
+      assertGeneratedInvoiceLine(secondInvoice, productTwo, new BigDecimal(12));
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  /**
+   * Verify no invoice is generated when processing a Goods Shipment after being previously
+   * processed
+   * <ol>
+   * <li>Create a Sales Order with invoice term "After Delivery".</li>
+   * <li>Adds two lines of product. Book the order.</li>
+   * <li>Create a Goods Shipment.</li>
+   * <li>Adds just one line from the previous order.</li>
+   * <li>Complete the document invoicing if possible.</li>
+   * <li>Verify an invoice was created and processed containing the line from Goods Shipment.</li>
+   * <li>Process the shipment a second time</li>
+   * <li>Verify no invoice was generated</li>
+   * </ol>
+   */
+
+  @Test
+  public void invoiceFromShipment_008() {
+    OBContext.setAdminMode();
+    try {
+
+      final Product product = TestUtils
+          .cloneProduct(T_SHIRTS_PRODUCT_ID, "InvoiceFromShipment_008");
+      final Order salesOrder = createSalesOrderWithInvoiceTerm(SALES_ORDER,
+          "InvoiceFromShipment_008", AFTER_DELIVERY);
+      final OrderLine orderLine = getOrderLineByLineNo(salesOrder, 10L);
+      setProductInOrderLine(orderLine, product);
+      OBDal.getInstance().flush();
+      TestUtils.processOrder(salesOrder);
+
+      final ShipmentInOut shipment = TestUtils.cloneReceiptShipment(GOODS_SHIPMENT_ID,
+          "InvoiceFromShipment_008");
+      final ShipmentInOutLine shipmentLine = getShipmentLineByLineNo(shipment, 10L);
+      setProductInShipmentLine(shipmentLine, product);
+      setOrderLineInShipmentLine(shipmentLine, orderLine);
+      OBDal.getInstance().flush();
+      TestUtils.processShipmentReceipt(shipment);
+      OBDal.getInstance().commitAndClose();
+
+      final Invoice invoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertInvoiceLineNumber(invoice, 1);
+      assertGeneratedInvoiceLine(invoice, product, new BigDecimal(12));
+
+      final Invoice secondIinvoice = new ShipmentProcessor(shipment.getId())
+          .createAndProcessInvoiceConsideringInvoiceTerms();
+      assertNoInvoiceWasGenerated(secondIinvoice);
+
+    } catch (Exception e) {
+      log.error(e.getMessage(), e);
+      throw new OBException(e);
+    } finally {
+      OBContext.restorePreviousMode();
+    }
+  }
+
+  private Order createSalesOrderWithInvoiceTerm(String salesOrderId, String docNno,
+      String invoiceTerm) {
+    final Order salesOrder = TestUtils.cloneOrder(salesOrderId, docNno);
+    salesOrder.setInvoiceTerms(invoiceTerm);
+    return salesOrder;
+  }
+
+  private Order createAfterOrderDeliveredOrder(String salesOrderWithOneLineId, String docNo) {
+    final Order salesOrder = TestUtils.cloneOrder(salesOrderWithOneLineId, docNo);
+    salesOrder.setInvoiceTerms(AFTER_ORDER_DELIVERY);
+    final OrderLine orderLine = salesOrder.getOrderLineList().get(0);
+    final OrderLine newOrderLine = TestUtils.cloneOrderLine(orderLine, salesOrder);
+    newOrderLine.setLineNo(orderLine.getLineNo() + 10);
+    OBDal.getInstance().flush();
+    return salesOrder;
+  }
+
+  private void setProductInOrderLine(final OrderLine orderLine, final Product product) {
+    orderLine.setProduct(product);
+  }
+
+  private ShipmentInOut createShipmentReceiptWithTwoLines(String goodsShipmentId, String docNo) {
+    final ShipmentInOut shipment = TestUtils.cloneReceiptShipment(goodsShipmentId, docNo);
+    final ShipmentInOutLine shipmentLine = shipment.getMaterialMgmtShipmentInOutLineList().get(0);
+    final ShipmentInOutLine newShipmentLine = TestUtils.cloneReceiptShipmentLine(shipmentLine,
+        shipment);
+    newShipmentLine.setLineNo(shipmentLine.getLineNo() + 10);
+    OBDal.getInstance().flush();
+    return shipment;
+  }
+
+  private void setProductInShipmentLine(final ShipmentInOutLine shipmentLine, final Product product) {
+    shipmentLine.setProduct(product);
+  }
+
+  private void setOrderLineInShipmentLine(final ShipmentInOutLine shipmentLine,
+      final OrderLine orderLine) {
+    shipmentLine.setSalesOrderLine(orderLine);
+  }
+
+  private void updateMovementQuantity(final ShipmentInOutLine shipmentLine,
+      final BigDecimal movementQuantity) {
+    shipmentLine.setMovementQuantity(movementQuantity);
+  }
+
+  private void assertInvoiceLineNumber(final Invoice invoice, final int numLines) {
+    assertThat("Invoice should have " + numLines + " lines", invoice.getInvoiceLineList().size(),
+        equalTo(numLines));
+  }
+
+  private void assertNoInvoiceWasGenerated(final Invoice invoice) {
+    assertThat("Invoice should be null", invoice == null, equalTo(true));
+  }
+
+  private void assertGeneratedInvoiceLine(final Invoice invoice, final Product product,
+      final BigDecimal quantity) {
+    assertThat("Invoice should not be null", invoice == null, equalTo(false));
+    final InvoiceLine invoiceLine = getInvoiceLineByProductQuantity(invoice, product, quantity);
+    assertThat("Invoice Line should have the product " + product, invoiceLine == null,
+        equalTo(false));
+  }
+
+  private ShipmentInOutLine addLineToShipment(final ShipmentInOut shipment) {
+    int numberOfLines = shipment.getMaterialMgmtShipmentInOutLineList().size();
+    final ShipmentInOutLine shipmentLine = shipment.getMaterialMgmtShipmentInOutLineList().get(
+        numberOfLines - 1);
+    final ShipmentInOutLine newShipmentLine = TestUtils.cloneReceiptShipmentLine(shipmentLine,
+        shipment);
+    newShipmentLine.setLineNo(getMaxLineNo(shipment) + 10);
+    OBDal.getInstance().flush();
+    return newShipmentLine;
+  }
+
+  private Long getMaxLineNo(final ShipmentInOut shipment) {
+    final String hql = "select coalesce(max(sl.lineNo), 0) from MaterialMgmtShipmentInOutLine as sl where sl.shipmentReceipt.id = :shipmentId";
+    final Query<Long> query = OBDal.getInstance().getSession().createQuery(hql, Long.class);
+    query.setParameter("shipmentId", shipment.getId());
+    final Long maxLineNo = query.uniqueResult();
+    if (maxLineNo != null) {
+      return maxLineNo;
+    }
+    return 0L;
+  }
+
+  private OrderLine getOrderLineByLineNo(final Order salesOrder, long lineNo) {
+    final String hql = "as ol where ol.salesOrder.id = :salesOrderId and ol.lineNo = :lineNo";
+    final OBQuery<OrderLine> query = OBDal.getInstance().createQuery(OrderLine.class, hql);
+    query.setNamedParameter("salesOrderId", salesOrder.getId());
+    query.setNamedParameter("lineNo", lineNo);
+    query.setMaxResult(1);
+    return query.uniqueResult();
+  }
+
+  private ShipmentInOutLine getShipmentLineByLineNo(final ShipmentInOut shipment, long lineNo) {
+    final String hql = "as sl where sl.shipmentReceipt.id = :shipmentId and sl.lineNo = :lineNo";
+    final OBQuery<ShipmentInOutLine> query = OBDal.getInstance().createQuery(
+        ShipmentInOutLine.class, hql);
+    query.setNamedParameter("shipmentId", shipment.getId());
+    query.setNamedParameter("lineNo", lineNo);
+    query.setMaxResult(1);
+    return query.uniqueResult();
+  }
+
+  private InvoiceLine getInvoiceLineByProductQuantity(final Invoice invoice, final Product product,
+      BigDecimal quantity) {
+    final String hql = "as il where il.invoice.id = :invoiceId and il.product.id =:productId and il.invoicedQuantity = :invoicedQuantity";
+    final OBQuery<InvoiceLine> query = OBDal.getInstance().createQuery(InvoiceLine.class, hql);
+    query.setNamedParameter("invoiceId", invoice.getId());
+    query.setNamedParameter("productId", product.getId());
+    query.setNamedParameter("invoicedQuantity", quantity);
+    query.setMaxResult(1);
+    return query.uniqueResult();
+  }
+
+  private Invoice createInvoiceFromShipment(final ShipmentInOut shipment,
+      final String salesInvoiceId) {
+    final Invoice invoice = OBDal.getInstance().get(Invoice.class, salesInvoiceId);
+    final Invoice newInvoice = (Invoice) DalUtil.copy(invoice, false);
+    newInvoice.setId(SequenceIdData.getUUID());
+    newInvoice.setNewOBObject(true);
+    newInvoice.setAccountingDate(shipment.getAccountingDate());
+    newInvoice.setInvoiceDate(shipment.getMovementDate());
+    final String documentNo = Utility.getDocumentNo(OBDal.getInstance().getConnection(false),
+        new DalConnectionProvider(false), RequestContext.get().getVariablesSecureApp(), "",
+        Invoice.TABLE_NAME, newInvoice.getTransactionDocument() == null ? "" : newInvoice
+            .getTransactionDocument().getId(), newInvoice.getDocumentType() == null ? ""
+            : newInvoice.getDocumentType().getId(), false, true);
+    newInvoice.setDocumentNo(documentNo);
+    OBDal.getInstance().save(newInvoice);
+    OBDal.getInstance().flush();
+
+    final ShipmentInOutLine shipmentInOutLine = shipment.getMaterialMgmtShipmentInOutLineList()
+        .get(0);
+    WeldUtils.getInstanceFromStaticBeanManager(CreateInvoiceLinesFromProcess.class)
+        .createInvoiceLinesFromDocumentLines(
+            getShipmentLineToBeInvoiced(shipmentInOutLine, BigDecimal.TEN), newInvoice,
+            ShipmentInOutLine.class);
+
+    OBDal.getInstance().flush();
+    return newInvoice;
+  }
+
+  private JSONArray getShipmentLineToBeInvoiced(final ShipmentInOutLine shipmentInOutLine,
+      final BigDecimal invoicedQuantity) {
+
+    final JSONArray lines = new JSONArray();
+    try {
+      final JSONObject line = new JSONObject();
+      line.put("uOM", shipmentInOutLine.getUOM().getId());
+      line.put("uOM$_identifier", shipmentInOutLine.getUOM().getIdentifier());
+      line.put("product", shipmentInOutLine.getProduct().getId());
+      line.put("product$_identifier", shipmentInOutLine.getProduct().getIdentifier());
+      line.put("lineNo", shipmentInOutLine.getLineNo());
+      line.put("movementQuantity", invoicedQuantity.toString());
+      line.put("operativeQuantity",
+          shipmentInOutLine.getOperativeQuantity() == null ? shipmentInOutLine
+              .getMovementQuantity().toString() : shipmentInOutLine.getOperativeQuantity()
+              .toString());
+      line.put("id", shipmentInOutLine.getId());
+      line.put("operativeUOM", shipmentInOutLine.getOperativeUOM() == null ? shipmentInOutLine
+          .getUOM().getId() : shipmentInOutLine.getOperativeUOM().getId());
+      line.put("operativeUOM$_identifier",
+          shipmentInOutLine.getOperativeUOM() == null ? shipmentInOutLine.getUOM().getIdentifier()
+              : shipmentInOutLine.getOperativeUOM().getIdentifier());
+      line.put("orderQuantity", "");
+      lines.put(line);
+    } catch (JSONException e) {
+      log.error(e.getMessage());
+    }
+    return lines;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src-test/src/org/openbravo/test/materialMgmt/invoiceFromShipment/TestUtils.java	Thu Oct 04 15:59:12 2018 -0400
@@ -0,0 +1,299 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html 
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License. 
+ * The Original Code is Openbravo ERP. 
+ * The Initial Developer of the Original Code is Openbravo SLU 
+ * All portions are Copyright (C) 2018 Openbravo SLU
+ * All Rights Reserved. 
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+package org.openbravo.test.materialMgmt.invoiceFromShipment;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import org.hibernate.criterion.Restrictions;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.dal.core.DalUtil;
+import org.openbravo.dal.service.OBCriteria;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.erpCommon.utility.SequenceIdData;
+import org.openbravo.model.common.invoice.Invoice;
+import org.openbravo.model.common.order.Order;
+import org.openbravo.model.common.order.OrderLine;
+import org.openbravo.model.common.plm.Product;
+import org.openbravo.model.materialmgmt.transaction.ShipmentInOut;
+import org.openbravo.model.materialmgmt.transaction.ShipmentInOutLine;
+import org.openbravo.model.pricing.pricelist.ProductPrice;
+import org.openbravo.service.db.CallStoredProcedure;
+
+public class TestUtils {
+
+  private static final String COMPLETE_ACTION = "CO";
+  private static final String DRAFT_STATUS = "DR";
+
+  /**
+   * Returns a new Product based on the given one. It is a clone of the first one but with different
+   * name and value
+   * 
+   * @param productId
+   *          Id of the original Product
+   * @param name
+   *          Name of the original Product
+   * @return A new Product clone based on the original one
+   */
+  public static Product cloneProduct(final String productId, final String name) {
+    final Product oldProduct = OBDal.getInstance().get(Product.class, productId);
+    final Product newProduct = (Product) DalUtil.copy(oldProduct, false);
+    int numberOfProductsWithSameName = getNumberOfProducts(name) + 1;
+
+    newProduct.setSearchKey(name + "-" + numberOfProductsWithSameName);
+    newProduct.setName(name + "-" + numberOfProductsWithSameName);
+    newProduct.setId(SequenceIdData.getUUID());
+    newProduct.setNewOBObject(true);
+
+    OBDal.getInstance().save(newProduct);
+
+    // Clone Prices
+    final List<ProductPrice> oldPrices = oldProduct.getPricingProductPriceList();
+    final List<ProductPrice> newPrices = new ArrayList<>();
+    for (ProductPrice productPrice : oldPrices) {
+      final ProductPrice newProductPrice = (ProductPrice) DalUtil.copy(productPrice, false);
+      newProductPrice.setNewOBObject(true);
+      newProductPrice.setId(SequenceIdData.getUUID());
+      newProductPrice.setProduct(newProduct);
+      OBDal.getInstance().save(newProductPrice);
+      newPrices.add(newProductPrice);
+    }
+    newProduct.setPricingProductPriceList(newPrices);
+    OBDal.getInstance().flush();
+
+    return newProduct;
+  }
+
+  /**
+   * Returns the number of products with same Product name
+   */
+  public static int getNumberOfProducts(final String name) {
+    try {
+      final OBCriteria<Product> criteria = OBDal.getInstance().createCriteria(Product.class);
+      criteria.add(Restrictions.like(Product.PROPERTY_NAME, name + "-%"));
+      return criteria.count();
+    } catch (Exception e) {
+      throw new OBException(e);
+    }
+  }
+
+  /**
+   * Returns a new Order Line based on the given one. It is a clone of the first one but without
+   * being invoiced or delivered
+   * 
+   * @param orderLine
+   *          Order Line to be cloned
+   * @param newOrder
+   *          new Order (a clone of the original one)
+   * @return A new Order Line clone based on the original one
+   */
+  public static Order cloneOrder(final String orderId, final String docNo) {
+    final Order oldOrder = OBDal.getInstance().get(Order.class, orderId);
+    final Order newOrder = (Order) DalUtil.copy(oldOrder, false);
+    int numberOfOrdersWithSameDocNo = getNumberOfOrders(docNo) + 1;
+
+    newOrder.setId(SequenceIdData.getUUID());
+    newOrder.setDocumentNo(docNo + "-" + numberOfOrdersWithSameDocNo);
+    newOrder.setProcessed(false);
+    newOrder.setDocumentStatus(DRAFT_STATUS);
+    newOrder.setDocumentAction(COMPLETE_ACTION);
+    newOrder.setCancelled(false);
+    newOrder.setOrderDate(Calendar.getInstance().getTime());
+    newOrder.setScheduledDeliveryDate(Calendar.getInstance().getTime());
+    newOrder.setNewOBObject(true);
+
+    OBDal.getInstance().save(newOrder);
+
+    for (OrderLine orderLine : oldOrder.getOrderLineList()) {
+      cloneOrderLine(orderLine, newOrder);
+    }
+
+    OBDal.getInstance().flush();
+
+    return newOrder;
+  }
+
+  /**
+   * Returns the number of orders with same Document Number
+   */
+  public static int getNumberOfOrders(final String docNo) {
+    try {
+      final OBCriteria<Order> criteria = OBDal.getInstance().createCriteria(Order.class);
+      criteria.add(Restrictions.like(Order.PROPERTY_DOCUMENTNO, docNo + "-%"));
+      return criteria.list().size();
+    } catch (Exception e) {
+      throw new OBException(e);
+    }
+  }
+
+  /**
+   * Returns a new Order Line based on the given one. It is a clone of the first one but without
+   * being invoiced or delivered
+   * 
+   * @param orderLine
+   *          Order Line to be cloned
+   * @param newOrder
+   *          new Order (a clone of the original one)
+   * @return A new Order Line clone based on the original one
+   */
+  public static OrderLine cloneOrderLine(final OrderLine oldLine, final Order newOrder) {
+
+    // Skip discount lines
+    if (oldLine.getOrderDiscount() != null) {
+      return null;
+    }
+
+    final OrderLine newLine = (OrderLine) DalUtil.copy(oldLine, false);
+
+    newLine.setId(SequenceIdData.getUUID());
+    newLine.setSalesOrder(newOrder);
+    newLine.setDeliveredQuantity(BigDecimal.ZERO);
+    newLine.setInvoicedQuantity(BigDecimal.ZERO);
+    newLine.setReservedQuantity(BigDecimal.ZERO);
+    newLine.setNewOBObject(true);
+
+    OBDal.getInstance().save(newLine);
+    newOrder.getOrderLineList().add(newLine);
+
+    return newLine;
+  }
+
+  /**
+   * Calls C_Order_Post Database Function to complete the given Order
+   * 
+   * @param order
+   *          Order to be completed
+   * @throws OBException
+   */
+  public static void processOrder(final Order order) throws OBException {
+    final List<Object> parameters = new ArrayList<Object>();
+    parameters.add(null);
+    parameters.add(order.getId());
+    final String procedureName = "c_order_post1";
+    CallStoredProcedure.getInstance().call(procedureName, parameters, null, true, false);
+  }
+
+  /**
+   * Returns a new Goods Receipt/Shipment based on the given one. It is a clone of the first one but
+   * in a not completed status
+   * 
+   * @param mInoutId
+   *          Id of original Goods Receipt/Shipment to clone
+   * @param docNo
+   *          docNo to set to the new Goods Receipt/Shipment
+   * @return a Goods Receipt/Shipment not completed
+   */
+  public static ShipmentInOut cloneReceiptShipment(final String mInoutId, final String docNo) {
+    final ShipmentInOut oldInOut = OBDal.getInstance().get(ShipmentInOut.class, mInoutId);
+    final ShipmentInOut newInOut = (ShipmentInOut) DalUtil.copy(oldInOut, false);
+    int numberOfShipmentsWithSameDocNo = getNumberOfShipments(docNo) + 1;
+
+    newInOut.setId(SequenceIdData.getUUID());
+    newInOut.setDocumentNo(docNo + "-" + numberOfShipmentsWithSameDocNo);
+    newInOut.setDocumentStatus(DRAFT_STATUS);
+    newInOut.setDocumentAction(COMPLETE_ACTION);
+    newInOut.setProcessed(false);
+    newInOut.setMovementDate(new Date());
+    newInOut.setOrderDate(new Date());
+    newInOut.setNewOBObject(true);
+    newInOut.setSalesOrder(null);
+
+    OBDal.getInstance().save(newInOut);
+
+    for (ShipmentInOutLine line : oldInOut.getMaterialMgmtShipmentInOutLineList()) {
+      cloneReceiptShipmentLine(line, newInOut);
+    }
+
+    OBDal.getInstance().flush();
+    return newInOut;
+  }
+
+  /**
+   * Returns the number of Goods Receipts/Shipments with same Document Number
+   */
+  public static int getNumberOfShipments(final String docNo) {
+    try {
+      final OBCriteria<ShipmentInOut> criteria = OBDal.getInstance().createCriteria(
+          ShipmentInOut.class);
+      criteria.add(Restrictions.like(ShipmentInOut.PROPERTY_DOCUMENTNO, docNo + "-%"));
+      return criteria.list().size();
+    } catch (Exception e) {
+      throw new OBException(e);
+    }
+  }
+
+  /**
+   * Returns a new Goods Receipt/Shipment Line based on the given one. It is a clone of the first
+   * one but with different product
+   * 
+   * @param line
+   *          Original Goods Receipt/Shipment
+   * @param newInOut
+   *          new Goods Receipt/Shipment (a clone of the original one)
+   * @return A new Goods Receipt/Shipment Line clone based on the original one
+   */
+  public static ShipmentInOutLine cloneReceiptShipmentLine(final ShipmentInOutLine oldLine,
+      final ShipmentInOut newInOut) {
+    final ShipmentInOutLine newLine = (ShipmentInOutLine) DalUtil.copy(oldLine, false);
+
+    newLine.setId(SequenceIdData.getUUID());
+    newLine.setShipmentReceipt(newInOut);
+    newLine.setNewOBObject(true);
+    newLine.setSalesOrderLine(null);
+
+    OBDal.getInstance().save(newLine);
+    newInOut.getMaterialMgmtShipmentInOutLineList().add(newLine);
+
+    return newLine;
+  }
+
+  /**
+   * Calls M_Inout_Post Database Function to complete the given Shipment/Receipt
+   * 
+   * @param shipmentReceipt
+   *          Shipment or Receipt to be completed
+   * @throws OBException
+   */
+  public static void processShipmentReceipt(final ShipmentInOut shipmentReceipt) throws OBException {
+    final List<Object> parameters = new ArrayList<Object>();
+    parameters.add(null);
+    parameters.add(shipmentReceipt.getId());
+    final String procedureName = "m_inout_post";
+    CallStoredProcedure.getInstance().call(procedureName, parameters, null, true, false);
+  }
+
+  /**
+   * Calls the C_INVOICE_POST stored procedure
+   * 
+   * @param invoice
+   *          The Invoice.
+   * @throws Exception
+   */
+  public static void processInvoice(final Invoice invoice) throws Exception {
+    if (invoice != null) {
+      final List<Object> parameters = new ArrayList<>();
+      parameters.add(null); // Process Instance parameter
+      parameters.add(invoice.getId());
+      CallStoredProcedure.getInstance().call("C_INVOICE_POST", parameters, null, true, false);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openbravo/common/actionhandler/InvoiceFromShipmentActionHandler.java	Thu Oct 04 15:59:12 2018 -0400
@@ -0,0 +1,95 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html 
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License. 
+ * The Original Code is Openbravo ERP. 
+ * The Initial Developer of the Original Code is Openbravo SLU 
+ * All portions are Copyright (C) 2018 Openbravo SLU 
+ * All Rights Reserved. 
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+package org.openbravo.common.actionhandler;
+
+import java.util.Map;
+
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.openbravo.client.application.process.BaseProcessActionHandler;
+import org.openbravo.erpCommon.utility.OBMessageUtils;
+import org.openbravo.materialmgmt.ShipmentProcessor;
+import org.openbravo.model.common.invoice.Invoice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class InvoiceFromShipmentActionHandler extends BaseProcessActionHandler {
+  private static final Logger log = LoggerFactory.getLogger(InvoiceFromShipmentActionHandler.class);
+
+  private static final String TEXT = "text";
+  private static final String TITLE = "title";
+  private static final String SEVERITY = "severity";
+  private static final String MESSAGE = "message";
+
+  @Override
+  protected JSONObject doExecute(Map<String, Object> parameters, String content) {
+
+    Invoice invoice;
+    JSONObject message = new JSONObject();
+    try {
+      JSONObject request = new JSONObject(content);
+      String shipmentId = request.getString("M_InOut_ID");
+
+      invoice = new ShipmentProcessor(shipmentId).createAndProcessInvoiceConsideringInvoiceTerms();
+      message.put(MESSAGE, getSuccessMessage(invoice));
+
+    } catch (Exception e) {
+      try {
+        message.put(MESSAGE, getErrorMessage(e));
+      } catch (JSONException e1) {
+        log.error(e.getMessage());
+      }
+    }
+
+    return message;
+  }
+
+  private JSONObject getErrorMessage(Exception e) {
+    JSONObject errorMessage = new JSONObject();
+    try {
+      errorMessage.put(SEVERITY, "error");
+      errorMessage.put(TITLE, OBMessageUtils.messageBD("Error"));
+      errorMessage.put(TEXT, e.getMessage());
+    } catch (JSONException ex) {
+      log.error(e.getMessage());
+    }
+    return errorMessage;
+  }
+
+  protected JSONObject getSuccessMessage(Invoice invoice) {
+    JSONObject successMessage = new JSONObject();
+    try {
+      successMessage.put(SEVERITY, "success");
+      successMessage.put(TITLE, OBMessageUtils.messageBD("Success"));
+      if (invoice != null) {
+        successMessage
+            .put(
+                TEXT,
+                String.format(OBMessageUtils.messageBD("NewInvoiceGenerated"),
+                    invoice.getDocumentNo()));
+      } else {
+        successMessage.put(TEXT, OBMessageUtils.messageBD("NoInvoiceGenerated"));
+      }
+    } catch (JSONException e) {
+      log.error(e.getMessage());
+    }
+    return successMessage;
+  }
+
+}
--- a/src/org/openbravo/erpCommon/ad_actionButton/DocAction.html	Tue Nov 13 09:24:05 2018 +0100
+++ b/src/org/openbravo/erpCommon/ad_actionButton/DocAction.html	Thu Oct 04 15:59:12 2018 -0400
@@ -11,7 +11,7 @@
 * under the License. 
 * The Original Code is Openbravo ERP. 
 * The Initial Developer of the Original Code is Openbravo SLU 
-* All portions are Copyright (C) 2001-2017 Openbravo SLU 
+* All portions are Copyright (C) 2001-2018 Openbravo SLU 
 * All Rights Reserved. 
 * Contributor(s):  ______________________________________.
 ************************************************************************
@@ -84,6 +84,8 @@
       setWindowElementFocus('firstElement');
 
       applyVoidDateDisplayLogic();
+      
+      applyInvoiceIfPossibleDisplayLogic();
     }
 
     function onResizeDo() {}
@@ -165,6 +167,15 @@
       displayLogicElement('voidedDocumentDateRow', displayVoidDates && (purchaseInvoiceWindow === currentWindowId || goodsReceiptWindow === currentWindowId));
       displayLogicElement('voidedDocumentDateAcctRow', displayVoidDates && (purchaseInvoiceWindow === currentWindowId || goodsReceiptWindow === currentWindowId));
     }
+    
+    function applyInvoiceIfPossibleDisplayLogic() {
+      var frm = document.frmMain,
+          goodsShipmentWindow = '169',
+          currentWindowId = frm.inpwindowId.value,
+          documentIsInDraftStatus = (frm.inpdocstatus.value === 'DR');
+      
+      displayLogicElement('invoiceIfPossible', documentIsInDraftStatus && currentWindowId === goodsShipmentWindow);
+    }
     </script>
 </head>
 
@@ -440,7 +451,16 @@
                   </table>
                 </td>
               </tr>
-
+              
+              <tr id="invoiceIfPossible">
+              	<td class="TitleCell"><span id="lblInvoiceIfPossible" class="LabelText">Invoice if possible</span></td>
+              	<td class="Radio_Check_ContentCell">
+              	  <span class="Checkbox_container_NOT_Focused">
+              	    <input type="checkbox" id="paramInvoiceIfPossible" name="inpInvoiceIfPossible">
+              	  </span>
+              	</td>
+              </tr>
+			
               <tr><td height="20px"></td></tr>
 
               <tr>
--- a/src/org/openbravo/erpCommon/ad_actionButton/ProcessGoods.java	Tue Nov 13 09:24:05 2018 +0100
+++ b/src/org/openbravo/erpCommon/ad_actionButton/ProcessGoods.java	Thu Oct 04 15:59:12 2018 -0400
@@ -34,6 +34,7 @@
 
 import org.apache.commons.lang.StringUtils;
 import org.hibernate.query.Query;
+import org.openbravo.base.exception.OBException;
 import org.openbravo.base.filter.IsIDFilter;
 import org.openbravo.base.provider.OBProvider;
 import org.openbravo.base.secureApp.HttpSecureAppServlet;
@@ -48,6 +49,7 @@
 import org.openbravo.erpCommon.utility.OBError;
 import org.openbravo.erpCommon.utility.Utility;
 import org.openbravo.materialmgmt.InventoryCountProcess;
+import org.openbravo.materialmgmt.ShipmentProcessor;
 import org.openbravo.model.ad.process.ProcessInstance;
 import org.openbravo.model.ad.ui.Process;
 import org.openbravo.model.materialmgmt.onhandquantity.StorageDetail;
@@ -158,6 +160,8 @@
     final String strTabId = vars.getGlobalVariable("inpTabId", "ProcessGoods|Tab_ID",
         IsIDFilter.instance);
     final String strM_Inout_ID = vars.getGlobalVariable("inpKey", strWindowId + "|M_Inout_ID", "");
+    final boolean invoiceIfPossible = StringUtils.equalsIgnoreCase(
+        vars.getStringParameter("inpInvoiceIfPossible"), "on");
 
     OBError myMessage = null;
     try {
@@ -208,6 +212,10 @@
       log4j.debug(myMessage.getMessage());
       vars.setMessage(strTabId, myMessage);
 
+      if (invoiceIfPossible && !"Error".equalsIgnoreCase(myMessage.getType())) {
+        new ShipmentProcessor(goods.getId()).createAndProcessInvoiceConsideringInvoiceTerms();
+      }
+
       String strWindowPath = Utility.getTabURL(strTabId, "R", true);
       if (strWindowPath.equals("")) {
         strWindowPath = strDefaultServlet;
@@ -222,6 +230,13 @@
       } else {
         vars.setMessage(strTabId, myMessage);
       }
+    } catch (final OBException e) {
+      if (e.getCause() != null) {
+        throw new OBException(Utility
+            .translateError(this, vars, vars.getLanguage(), e.getMessage()).getMessage());
+      } else {
+        throw e;
+      }
     }
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openbravo/materialmgmt/ShipmentProcessor.java	Thu Oct 04 15:59:12 2018 -0400
@@ -0,0 +1,313 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.0  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License.
+ * The Original Code is Openbravo ERP.
+ * The Initial Developer of the Original Code is Openbravo SLU
+ * All portions are Copyright (C) 2018 Openbravo SLU
+ * All Rights Reserved.
+ * Contributor(s):  ______________________________________.
+ *************************************************************************
+ */
+package org.openbravo.materialmgmt;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.query.Query;
+import org.openbravo.base.exception.OBException;
+import org.openbravo.base.model.Entity;
+import org.openbravo.base.model.ModelProvider;
+import org.openbravo.base.provider.OBProvider;
+import org.openbravo.base.weld.WeldUtils;
+import org.openbravo.client.kernel.RequestContext;
+import org.openbravo.common.actionhandler.createlinesfromprocess.CreateInvoiceLinesFromProcess;
+import org.openbravo.dal.service.OBDal;
+import org.openbravo.erpCommon.utility.Utility;
+import org.openbravo.model.common.enterprise.DocumentType;
+import org.openbravo.model.common.invoice.Invoice;
+import org.openbravo.model.common.invoice.InvoiceLine;
+import org.openbravo.model.common.order.Order;
+import org.openbravo.model.common.order.OrderLine;
+import org.openbravo.model.materialmgmt.transaction.ShipmentInOut;
+import org.openbravo.model.materialmgmt.transaction.ShipmentInOutLine;
+import org.openbravo.service.db.CallStoredProcedure;
+import org.openbravo.service.db.DalConnectionProvider;
+import org.openbravo.service.db.DbUtility;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class to process Goods Shipments
+ *
+ */
+public class ShipmentProcessor {
+
+  private static final String C_INVOICE_TABLE_ID = "318";
+  private static final Logger log = LoggerFactory.getLogger(ShipmentProcessor.class);
+  private ShipmentInOut shipment;
+  Invoice invoice;
+  private CreateInvoiceLinesFromProcess createInvoiceLineProcess;
+
+  private static final String AFTER_ORDER_DELIVERY = "O";
+  private static final String AFTER_DELIVERY = "D";
+  private static final String IMMEDIATE = "I";
+
+  public ShipmentProcessor(String shipmentId) {
+    this.shipment = OBDal.getInstance().get(ShipmentInOut.class, shipmentId);
+    this.createInvoiceLineProcess = WeldUtils
+        .getInstanceFromStaticBeanManager(CreateInvoiceLinesFromProcess.class);
+  }
+
+  /**
+   * Creates and process an Invoice from Goods Shipment, considering the invoice terms of orders
+   * linked to shipment lines.
+   * 
+   * @return The invoice created
+   */
+  public Invoice createAndProcessInvoiceConsideringInvoiceTerms() {
+    try {
+      createInvoiceConsideringInvoiceTerms();
+      if (invoice != null) {
+        processInvoice();
+      }
+
+    } catch (OBException e) {
+      executeRollBack();
+      throw new OBException(e.getMessage());
+    } catch (Exception e1) {
+      executeRollBack();
+      Throwable e3 = DbUtility.getUnderlyingSQLException(e1);
+      throw new OBException(e3);
+    }
+
+    return invoice;
+  }
+
+  private Invoice createInvoiceConsideringInvoiceTerms() {
+    HashSet<String> ordersAlreadyInvoiced = new HashSet<>();
+    try (ScrollableResults scrollShipmentLines = getShipmentLines()) {
+      while (scrollShipmentLines.next()) {
+        final ShipmentInOutLine shipmentLine = OBDal.getInstance().get(ShipmentInOutLine.class,
+            scrollShipmentLines.get()[0]);
+
+        final OrderLine orderLine = shipmentLine.getSalesOrderLine();
+        boolean shipmentLineIsLinkedToSalesOrderLine = orderLine != null;
+        final Order order = shipmentLineIsLinkedToSalesOrderLine ? orderLine.getSalesOrder() : null;
+        final String invoiceTerms = order != null ? order.getInvoiceTerms() : null;
+        final Long deliveryStatus = order != null ? order.getDeliveryStatus() : null;
+
+        if (AFTER_DELIVERY.equals(invoiceTerms) || IMMEDIATE.equals(invoiceTerms)
+            || !shipmentLineIsLinkedToSalesOrderLine) {
+          invoiceShimpentLineIfNotYetInvoiced(shipmentLine);
+
+        } else if (AFTER_ORDER_DELIVERY.equals(invoiceTerms) && deliveryStatus == 100
+            && !ordersAlreadyInvoiced.contains(order.getId())) {
+
+          inovoiceAllShipmentLinesNotFullyInvoicedLinkedToOrder(order);
+          ordersAlreadyInvoiced.add(order.getId());
+        }
+      }
+      OBDal.getInstance().flush();
+    }
+    return invoice;
+  }
+
+  private ScrollableResults getShipmentLines() {
+    final String shipmentLinesHQLQuery = "select iol.id " //
+        + "from " + ShipmentInOutLine.ENTITY_NAME + " iol " //
+        + "where " + ShipmentInOutLine.PROPERTY_SHIPMENTRECEIPT + ".id = :shipmentId ";
+
+    final Session session = OBDal.getInstance().getSession();
+    final Query<String> query = session.createQuery(shipmentLinesHQLQuery, String.class);
+    query.setParameter("shipmentId", shipment.getId());
+
+    return query.scroll(ScrollMode.FORWARD_ONLY);
+  }
+
+  protected void invoiceShimpentLineIfNotYetInvoiced(final ShipmentInOutLine shipmentLine) {
+    final BigDecimal totalInvoiced = getTotalInvoicedForShipmentLine(shipmentLine);
+    if (totalInvoiced.compareTo(shipmentLine.getMovementQuantity()) != 0) {
+      invoiceShipmentLine(shipmentLine);
+    }
+  }
+
+  private BigDecimal getTotalInvoicedForShipmentLine(final ShipmentInOutLine iol) {
+    final String invoiceLinesHqlQuery = "select coalesce(sum(il. "
+        + InvoiceLine.PROPERTY_INVOICEDQUANTITY + "), 0) " //
+        + "from " + InvoiceLine.ENTITY_NAME + " il " //
+        + "where il." + InvoiceLine.PROPERTY_GOODSSHIPMENTLINE + ".id = :shipmentLineId ";
+
+    final Session sessionInvoiceLines = OBDal.getInstance().getSession();
+    final Query<BigDecimal> queryInvoiceLines = sessionInvoiceLines.createQuery(
+        invoiceLinesHqlQuery, BigDecimal.class);
+    queryInvoiceLines.setParameter("shipmentLineId", iol.getId());
+
+    return queryInvoiceLines.uniqueResult();
+  }
+
+  private void invoiceShipmentLine(final ShipmentInOutLine shipmentLine) {
+    createInvoiceShipmentLine(shipmentLine, shipmentLine.getMovementQuantity());
+
+  }
+
+  private void createInvoiceShipmentLine(final ShipmentInOutLine shipmentLine,
+      final BigDecimal invoicedQuantity) {
+    createInvoiceLineProcess.createInvoiceLinesFromDocumentLines(
+        getShipmentLineToBeInvoiced(shipmentLine, invoicedQuantity), getInvoiceHeader(),
+        ShipmentInOutLine.class);
+  }
+
+  private JSONArray getShipmentLineToBeInvoiced(final ShipmentInOutLine shipmentInOutLine,
+      final BigDecimal invoicedQuantity) {
+
+    final JSONArray lines = new JSONArray();
+    try {
+      final JSONObject line = new JSONObject();
+      line.put("uOM", shipmentInOutLine.getUOM().getId());
+      line.put("uOM$_identifier", shipmentInOutLine.getUOM().getIdentifier());
+      line.put("product", shipmentInOutLine.getProduct().getId());
+      line.put("product$_identifier", shipmentInOutLine.getProduct().getIdentifier());
+      line.put("lineNo", shipmentInOutLine.getLineNo());
+      line.put("movementQuantity", invoicedQuantity.toString());
+      line.put("operativeQuantity",
+          shipmentInOutLine.getOperativeQuantity() == null ? shipmentInOutLine
+              .getMovementQuantity().toString() : shipmentInOutLine.getOperativeQuantity()
+              .toString());
+      line.put("id", shipmentInOutLine.getId());
+      line.put("operativeUOM", shipmentInOutLine.getOperativeUOM() == null ? shipmentInOutLine
+          .getUOM().getId() : shipmentInOutLine.getOperativeUOM().getId());
+      line.put("operativeUOM$_identifier",
+          shipmentInOutLine.getOperativeUOM() == null ? shipmentInOutLine.getUOM().getIdentifier()
+              : shipmentInOutLine.getOperativeUOM().getIdentifier());
+      line.put("orderQuantity", "");
+      lines.put(line);
+    } catch (JSONException e) {
+      log.error(e.getMessage());
+    }
+    return lines;
+  }
+
+  private void inovoiceAllShipmentLinesNotFullyInvoicedLinkedToOrder(final Order order) {
+    try (ScrollableResults scrollOrderShipmentLines = getShipmentLinesLinkedToASalesOrder(order)) {
+      while (scrollOrderShipmentLines.next()) {
+
+        final ShipmentInOutLine iol = OBDal.getInstance().get(ShipmentInOutLine.class,
+            (String) scrollOrderShipmentLines.get()[0]);
+        final BigDecimal invoicedQuantity = getTotalInvoicedForShipmentLine(iol);
+        if (invoicedQuantity.compareTo(iol.getMovementQuantity()) != 0) {
+          createInvoiceShipmentLine(iol, iol.getMovementQuantity().subtract(invoicedQuantity));
+        }
+      }
+    }
+  }
+
+  private ScrollableResults getShipmentLinesLinkedToASalesOrder(final Order order) {
+    final String orderLinesHqlQuery = "select iol.id " //
+        + "from " + ShipmentInOutLine.ENTITY_NAME + " iol " //
+        + "join iol." + ShipmentInOutLine.PROPERTY_SALESORDERLINE + " ol " //
+        + "where ol." + OrderLine.PROPERTY_SALESORDER + ".id = :orderId ";
+
+    final Session sessionOrderLines = OBDal.getInstance().getSession();
+    final Query<String> queryOrderLines = sessionOrderLines.createQuery(orderLinesHqlQuery,
+        String.class);
+    queryOrderLines.setParameter("orderId", order.getId());
+
+    return queryOrderLines.scroll(ScrollMode.FORWARD_ONLY);
+  }
+
+  private Invoice getInvoiceHeader() {
+    if (invoice == null) {
+      invoice = createInvoiceHeader();
+    }
+    return invoice;
+  }
+
+  private Invoice createInvoiceHeader() {
+    final Entity invoiceEntity = ModelProvider.getInstance().getEntity(Invoice.class);
+    final Invoice newInvoice = OBProvider.getInstance().get(Invoice.class);
+
+    newInvoice.setClient(shipment.getClient());
+    newInvoice.setOrganization(shipment.getOrganization());
+    final DocumentType invoiceDocumentType = getInvoiceDocumentType();
+    newInvoice.setDocumentType(invoiceDocumentType);
+    newInvoice.setTransactionDocument(invoiceDocumentType);
+    String documentNo = Utility.getDocumentNo(OBDal.getInstance().getConnection(false),
+        new DalConnectionProvider(false), RequestContext.get().getVariablesSecureApp(), "",
+        invoiceEntity.getTableName(), newInvoice.getTransactionDocument() == null ? "" : newInvoice
+            .getTransactionDocument().getId(), newInvoice.getDocumentType() == null ? ""
+            : newInvoice.getDocumentType().getId(), false, true);
+    newInvoice.setDocumentNo(documentNo);
+    newInvoice.setDocumentAction("CO");
+    newInvoice.setDocumentStatus("DR");
+    newInvoice.setAccountingDate(shipment.getAccountingDate());
+    newInvoice.setInvoiceDate(shipment.getMovementDate());
+    newInvoice.setTaxDate(shipment.getMovementDate());
+    newInvoice.setSalesTransaction(true);
+    newInvoice.setBusinessPartner(shipment.getBusinessPartner());
+    newInvoice.setPartnerAddress(shipment.getPartnerAddress());
+    newInvoice.setPriceList(shipment.getBusinessPartner().getPriceList());
+    newInvoice.setCurrency((shipment.getBusinessPartner().getPriceList() == null) ? null : shipment
+        .getBusinessPartner().getPriceList().getCurrency());
+    newInvoice.setSummedLineAmount(BigDecimal.ZERO);
+    newInvoice.setGrandTotalAmount(BigDecimal.ZERO);
+    newInvoice.setWithholdingamount(BigDecimal.ZERO);
+    newInvoice.setPaymentMethod(shipment.getBusinessPartner().getPaymentMethod());
+    newInvoice.setPaymentTerms(shipment.getBusinessPartner().getPaymentTerms());
+    OBDal.getInstance().save(newInvoice);
+    return newInvoice;
+  }
+
+  private DocumentType getInvoiceDocumentType() {
+    String hql = "from DocumentType dt where dt.salesTransaction = true" //
+        + " and dt.default = true and dt.table.id = :cInvoiceTableId" //
+        + " and Ad_Isorgincluded(:invoiceOrgId, dt.organization.id, :clientId) <> -1";
+
+    final Query<DocumentType> query = OBDal.getInstance().getSession()
+        .createQuery(hql.toString(), DocumentType.class);
+    query.setParameter("cInvoiceTableId", C_INVOICE_TABLE_ID);
+    query.setParameter("invoiceOrgId", this.shipment.getOrganization().getId());
+    query.setParameter("clientId", this.shipment.getClient().getId());
+    query.setMaxResults(1);
+
+    final DocumentType invoiceDocumentType = query.uniqueResult();
+
+    if (invoiceDocumentType == null) {
+      throw new OBException("There is no Document type for Sales Invoice defined");
+    }
+    return invoiceDocumentType;
+  }
+
+  private void processInvoice() throws Exception {
+    if (invoice != null) {
+      final List<Object> parameters = new ArrayList<>();
+      parameters.add(null); // Process Instance parameter
+      parameters.add(invoice.getId());
+      CallStoredProcedure.getInstance().call("C_INVOICE_POST", parameters, null, false, false);
+    }
+  }
+
+  protected void executeRollBack() {
+    try {
+      log.error("Error executing creating Invoice");
+      OBDal.getInstance().rollbackAndClose();
+    } catch (Exception e2) {
+      log.error("An error happened when rollback was executed.", e2);
+    }
+  }
+}