Merge release-7.1 into master

This commit is contained in:
Carlos Ruiz 2020-03-07 12:08:07 +01:00
commit 3a0f1d36b0
16 changed files with 1326 additions and 240 deletions

View File

@ -0,0 +1,220 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-4191
-- Feb 28, 2020, 2:24:36 PM CET
INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,IsServerProcess,ShowHelp,CopyFromProcess,AD_Process_UU,AllowMultipleExecution) VALUES (200117,0,0,'Y',TO_DATE('2020-02-28 14:24:35','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:24:35','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Storage Provider','Migrate the storage provider for attachments, archives and/or images','N','MigrateStorageProvider','N','org.idempiere.process.MigrateStorageProvider','6','D',0,0,'N','N','Y','N','e88ade56-8e2f-4dcf-a29c-687b83ee31ed','P')
;
-- Feb 28, 2020, 2:24:49 PM CET
INSERT INTO AD_Menu (AD_Menu_ID,Name,Description,Action,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsSummary,AD_Process_ID,IsSOTrx,IsReadOnly,EntityType,IsCentrallyMaintained,AD_Menu_UU) VALUES (200173,'Migrate Storage Provider','Migrate the storage provider for attachments, archives and/or images','P',0,0,'Y',TO_DATE('2020-02-28 14:24:48','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:24:48','YYYY-MM-DD HH24:MI:SS'),100,'N',200117,'Y','N','D','Y','66ef5225-0a24-4471-abcb-9d127aa6e6f3')
;
-- Feb 28, 2020, 2:24:49 PM CET
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNodeMM_UU) SELECT t.AD_Client_ID, 0, 'Y', SysDate, 100, SysDate, 100,t.AD_Tree_ID, 200173, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200173)
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=0, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=218
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=1, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=153
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=2, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=263
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=3, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=166
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=4, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=203
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=5, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53242
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=6, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=236
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=7, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=183
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=8, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=160
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=9, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=278
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=10, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=345
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=11, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53296
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=12, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53014
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=13, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53108
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=0, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=261
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=1, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53202
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=2, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=225
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=3, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200026
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=4, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200009
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=5, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=148
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=6, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=529
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=7, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=397
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=8, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=532
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=9, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53084
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=10, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=514
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=11, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200069
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=12, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200070
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=13, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200067
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=14, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200068
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=15, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200027
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=16, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=200173
;
-- Feb 28, 2020, 2:36:57 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200287,0,0,'Y',TO_DATE('2020-02-28 14:36:56','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:36:56','YYYY-MM-DD HH24:MI:SS'),100,'Client (All)',200117,10,19,'N',10,'N','AD_AllClients_V_ID','Y','D',203119,'0e5fb109-e45c-40c6-86bd-ddb870b3c54f','N')
;
-- Feb 28, 2020, 2:41:33 PM CET
UPDATE AD_Process_Para SET DefaultValue='@SQL=SELECT CASE WHEN @#AD_Client_ID@>0 THEN @#AD_Client_ID@ ELSE -1 END', ReadOnlyLogic='@#AD_Client_ID@>0',Updated=TO_DATE('2020-02-28 14:41:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200287
;
-- Feb 28, 2020, 2:42:41 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203404,0,0,'Y',TO_DATE('2020-02-28 14:41:52','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:41:52','YYYY-MM-DD HH24:MI:SS'),100,'Actual_StorageProvider_ID','Actual Storage Provider',NULL,NULL,'Actual Storage Provider','D','0cfa1388-b17c-4c16-8506-8209d566cbd9')
;
-- Feb 28, 2020, 2:43:45 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,AD_Reference_Value_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200288,0,0,'Y',TO_DATE('2020-02-28 14:43:45','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:43:45','YYYY-MM-DD HH24:MI:SS'),100,'Actual Storage Provider',200117,20,18,200023,'N',10,'N','Actual_StorageProvider_ID','Y','D',203404,'e8760265-8b93-4535-bc62-3267597b8148','N')
;
-- Feb 28, 2020, 2:44:40 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200289,0,0,'Y',TO_DATE('2020-02-28 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,'Storage Provider',200117,30,19,'N',10,'Y','AD_StorageProvider_ID','Y','D',200238,'fcded692-5976-4c18-be93-1de330b2c0f7','N')
;
-- Feb 28, 2020, 2:45:25 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203405,0,0,'Y',TO_DATE('2020-02-28 14:45:09','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:45:09','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateAttachment','Migrate Attachment',NULL,NULL,'Migrate Attachment','D','d8cebb40-2e30-4561-9c0c-34ce599f602f')
;
-- Feb 28, 2020, 2:45:55 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200290,0,0,'Y',TO_DATE('2020-02-28 14:45:55','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:45:55','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Attachment',200117,40,20,'N',1,'Y','N','IsMigrateAttachment','Y','D',203405,'90601452-26c5-40f4-89fe-9a3875973afa','N')
;
-- Feb 28, 2020, 2:46:10 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203406,0,0,'Y',TO_DATE('2020-02-28 14:46:00','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:46:00','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateArchive','Migrate Archive',NULL,NULL,'Migrate Archive','D','b7080f1a-398e-4a19-9ccf-03d22aa8e605')
;
-- Feb 28, 2020, 2:46:17 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200291,0,0,'Y',TO_DATE('2020-02-28 14:46:16','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:46:16','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Archive',200117,50,20,'N',1,'Y','N','IsMigrateArchive','Y','D',203406,'a35d4b7a-2647-4ad1-a994-68b376ef696e','N')
;
-- Feb 28, 2020, 2:46:30 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203407,0,0,'Y',TO_DATE('2020-02-28 14:46:21','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:46:21','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateImage','Migrate Image',NULL,NULL,'Migrate Image','D','da9b6551-af77-4e28-b788-bf94462cd342')
;
-- Feb 28, 2020, 2:46:33 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200292,0,0,'Y',TO_DATE('2020-02-28 14:46:33','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:46:33','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Image',200117,60,20,'N',1,'Y','N','IsMigrateImage','Y','D',203407,'1c6fb7fb-fd93-48a6-8f30-3f8912880947','N')
;
-- Feb 28, 2020, 2:47:29 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200293,0,0,'Y',TO_DATE('2020-02-28 14:47:28','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2020-02-28 14:47:28','YYYY-MM-DD HH24:MI:SS'),100,'Delete old/existing records','Otherwise records will be added',200117,70,20,'N',1,'Y','N','DeleteOld','Y','D',1669,'2de2ab75-8533-4ff6-b01b-62f660c5d7a2','N')
;
-- Feb 28, 2020, 2:49:30 PM CET
UPDATE AD_Process_Para SET Name='Delete old/existing files', Description='Delete the records from the old storage provider after moved', Help='WARNING! This option cannot be rolled back! Be cautious, take backups. If not enabled, the system administrator can/must remove manually the old files from the previous storage provider later.', IsCentrallyMaintained='N',Updated=TO_DATE('2020-02-28 14:49:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200293
;
-- Feb 28, 2020, 5:54:24 PM CET
UPDATE AD_Process_Para SET DisplayLogic='@AD_AllClients_V_ID:-1@=-1',Updated=TO_DATE('2020-02-28 17:54:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200288
;
-- Mar 4, 2020, 5:01:54 PM CET
UPDATE AD_Process SET Help='<p><span style="color:#ff0000"><b>WARNING: This process can be destructive, so please be sure that you have a backup of the database, as well as a backup of your old storage provider.</b></span></p>
<p>The process migrates files between storage providers.</p>
<ul><li><b>Client:</b> Optional, you can select a client to migrate, if empty it will try to migrate storage providers from all clients with the Actual Storage Provider selected below.</li><li><b>Actual Storage Provider:</b> If the client is empty, you define here the storage provider to migrate, if empty it migrates clients with the storage provider not set (this is by default DB).</li><li><b>Storage Provider:</b> The new storage provider to migrate the files.</li><li><b>Migrate Attachment:</b> If enabled, it migrates the attachment files to the new storage provider.</li><li><b>Migrate Archive:</b> If enabled, it migrates the archive files to the new storage provider.</li><li><b>Migrate Image:</b> If enabled, it migrates the image files to the new storage provider.</li><li><b>Delete old/existing files:</b> If enabled, after the files are migrated the program tries to free space deleting the files from the previous storage provider.  <span style="color:#ff0000">Note that migrating from/to a DB storage provider is a destructive action that cannot be recovered, it implies deleting the old/existing files</span>.</li></ul>
<p>Please note that during the migration the whole set of records in the table being migrated (attachment, archive, image) is locked, so operations on these records are not permitted.  Because of this, it is recommended to run this process in a <b>maintenance window</b> without users logged in the system.</p>
<p>In case of failure the attachments / archives / images that succeeded as a whole from a client are still migrated, but not partial records (which would result in data corruption if allowed).</p>
',Updated=TO_DATE('2020-03-04 17:01:54','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200117
;
-- Mar 4, 2020, 4:21:15 PM CET
UPDATE AD_Process_Para SET Name='Client', Description='Client/Tenant for this installation.', Help='A Client is a company or a legal entity. You cannot share data between Clients. Tenant is a synonym for Client.', AD_Reference_ID=18, AD_Reference_Value_ID=129, IsCentrallyMaintained='N',Updated=TO_DATE('2020-03-04 16:21:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200287
;
-- Mar 4, 2020, 4:23:12 PM CET
UPDATE AD_Process_Para SET AD_Reference_ID=19, AD_Reference_Value_ID=NULL,Updated=TO_DATE('2020-03-04 16:23:12','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200287
;
SELECT register_migration_script('202002281451_IDEMPIERE-4191.sql') FROM dual
;

View File

@ -0,0 +1,217 @@
-- IDEMPIERE-4191
-- Feb 28, 2020, 2:24:36 PM CET
INSERT INTO AD_Process (AD_Process_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,IsReport,Value,IsDirectPrint,Classname,AccessLevel,EntityType,Statistic_Count,Statistic_Seconds,IsBetaFunctionality,IsServerProcess,ShowHelp,CopyFromProcess,AD_Process_UU,AllowMultipleExecution) VALUES (200117,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:24:35','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:24:35','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Storage Provider','Migrate the storage provider for attachments, archives and/or images','N','MigrateStorageProvider','N','org.idempiere.process.MigrateStorageProvider','6','D',0,0,'N','N','Y','N','e88ade56-8e2f-4dcf-a29c-687b83ee31ed','P')
;
-- Feb 28, 2020, 2:24:49 PM CET
INSERT INTO AD_Menu (AD_Menu_ID,Name,Description,"action",AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsSummary,AD_Process_ID,IsSOTrx,IsReadOnly,EntityType,IsCentrallyMaintained,AD_Menu_UU) VALUES (200173,'Migrate Storage Provider','Migrate the storage provider for attachments, archives and/or images','P',0,0,'Y',TO_TIMESTAMP('2020-02-28 14:24:48','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:24:48','YYYY-MM-DD HH24:MI:SS'),100,'N',200117,'Y','N','D','Y','66ef5225-0a24-4471-abcb-9d127aa6e6f3')
;
-- Feb 28, 2020, 2:24:49 PM CET
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo, AD_TreeNodeMM_UU) SELECT t.AD_Client_ID, 0, 'Y', statement_timestamp(), 100, statement_timestamp(), 100,t.AD_Tree_ID, 200173, 0, 999, Generate_UUID() FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=200173)
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=0, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=218
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=1, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=153
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=2, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=263
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=3, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=166
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=4, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=203
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=5, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=53242
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=6, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=236
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=7, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=183
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=8, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=160
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=9, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=278
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=10, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=345
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=11, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=53296
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=12, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=53014
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=0, SeqNo=13, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=53108
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=0, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=261
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=1, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=53202
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=2, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=225
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=3, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200026
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=4, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200009
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=5, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=148
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=6, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=529
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=7, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=397
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=8, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=532
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=9, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=53084
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=10, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=514
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=11, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200069
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=12, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200070
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=13, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200067
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=14, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200068
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=15, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200027
;
-- Feb 28, 2020, 2:25:18 PM CET
UPDATE AD_TreeNodeMM SET Parent_ID=156, SeqNo=16, Updated=statement_timestamp() WHERE AD_Tree_ID=10 AND Node_ID=200173
;
-- Feb 28, 2020, 2:36:57 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200287,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:36:56','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:36:56','YYYY-MM-DD HH24:MI:SS'),100,'Client (All)',200117,10,19,'N',10,'N','AD_AllClients_V_ID','Y','D',203119,'0e5fb109-e45c-40c6-86bd-ddb870b3c54f','N')
;
-- Feb 28, 2020, 2:41:33 PM CET
UPDATE AD_Process_Para SET DefaultValue='@SQL=SELECT CASE WHEN @#AD_Client_ID@>0 THEN @#AD_Client_ID@ ELSE -1 END', ReadOnlyLogic='@#AD_Client_ID@>0',Updated=TO_TIMESTAMP('2020-02-28 14:41:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200287
;
-- Feb 28, 2020, 2:42:41 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203404,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:41:52','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:41:52','YYYY-MM-DD HH24:MI:SS'),100,'Actual_StorageProvider_ID','Actual Storage Provider',NULL,NULL,'Actual Storage Provider','D','0cfa1388-b17c-4c16-8506-8209d566cbd9')
;
-- Feb 28, 2020, 2:43:45 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,AD_Reference_Value_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200288,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:43:45','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:43:45','YYYY-MM-DD HH24:MI:SS'),100,'Actual Storage Provider',200117,20,18,200023,'N',10,'N','Actual_StorageProvider_ID','Y','D',203404,'e8760265-8b93-4535-bc62-3267597b8148','N')
;
-- Feb 28, 2020, 2:44:40 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200289,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,'Storage Provider',200117,30,19,'N',10,'Y','AD_StorageProvider_ID','Y','D',200238,'fcded692-5976-4c18-be93-1de330b2c0f7','N')
;
-- Feb 28, 2020, 2:45:25 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203405,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:45:09','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:45:09','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateAttachment','Migrate Attachment',NULL,NULL,'Migrate Attachment','D','d8cebb40-2e30-4561-9c0c-34ce599f602f')
;
-- Feb 28, 2020, 2:45:55 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200290,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:45:55','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:45:55','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Attachment',200117,40,20,'N',1,'Y','N','IsMigrateAttachment','Y','D',203405,'90601452-26c5-40f4-89fe-9a3875973afa','N')
;
-- Feb 28, 2020, 2:46:10 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203406,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:46:00','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:46:00','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateArchive','Migrate Archive',NULL,NULL,'Migrate Archive','D','b7080f1a-398e-4a19-9ccf-03d22aa8e605')
;
-- Feb 28, 2020, 2:46:17 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200291,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:46:16','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:46:16','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Archive',200117,50,20,'N',1,'Y','N','IsMigrateArchive','Y','D',203406,'a35d4b7a-2647-4ad1-a994-68b376ef696e','N')
;
-- Feb 28, 2020, 2:46:30 PM CET
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,Help,PrintName,EntityType,AD_Element_UU) VALUES (203407,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:46:21','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:46:21','YYYY-MM-DD HH24:MI:SS'),100,'IsMigrateImage','Migrate Image',NULL,NULL,'Migrate Image','D','da9b6551-af77-4e28-b788-bf94462cd342')
;
-- Feb 28, 2020, 2:46:33 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200292,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:46:33','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:46:33','YYYY-MM-DD HH24:MI:SS'),100,'Migrate Image',200117,60,20,'N',1,'Y','N','IsMigrateImage','Y','D',203407,'1c6fb7fb-fd93-48a6-8f30-3f8912880947','N')
;
-- Feb 28, 2020, 2:47:29 PM CET
INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200293,0,0,'Y',TO_TIMESTAMP('2020-02-28 14:47:28','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2020-02-28 14:47:28','YYYY-MM-DD HH24:MI:SS'),100,'Delete old/existing records','Otherwise records will be added',200117,70,20,'N',1,'Y','N','DeleteOld','Y','D',1669,'2de2ab75-8533-4ff6-b01b-62f660c5d7a2','N')
;
-- Feb 28, 2020, 2:49:30 PM CET
UPDATE AD_Process_Para SET Name='Delete old/existing files', Description='Delete the records from the old storage provider after moved', Help='WARNING! This option cannot be rolled back! Be cautious, take backups. If not enabled, the system administrator can/must remove manually the old files from the previous storage provider later.', IsCentrallyMaintained='N',Updated=TO_TIMESTAMP('2020-02-28 14:49:30','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200293
;
-- Feb 28, 2020, 5:54:24 PM CET
UPDATE AD_Process_Para SET DisplayLogic='@AD_AllClients_V_ID:-1@=-1',Updated=TO_TIMESTAMP('2020-02-28 17:54:24','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200288
;
-- Mar 4, 2020, 5:01:54 PM CET
UPDATE AD_Process SET Help='<p><span style="color:#ff0000"><b>WARNING: This process can be destructive, so please be sure that you have a backup of the database, as well as a backup of your old storage provider.</b></span></p>
<p>The process migrates files between storage providers.</p>
<ul><li><b>Client:</b> Optional, you can select a client to migrate, if empty it will try to migrate storage providers from all clients with the Actual Storage Provider selected below.</li><li><b>Actual Storage Provider:</b> If the client is empty, you define here the storage provider to migrate, if empty it migrates clients with the storage provider not set (this is by default DB).</li><li><b>Storage Provider:</b> The new storage provider to migrate the files.</li><li><b>Migrate Attachment:</b> If enabled, it migrates the attachment files to the new storage provider.</li><li><b>Migrate Archive:</b> If enabled, it migrates the archive files to the new storage provider.</li><li><b>Migrate Image:</b> If enabled, it migrates the image files to the new storage provider.</li><li><b>Delete old/existing files:</b> If enabled, after the files are migrated the program tries to free space deleting the files from the previous storage provider.  <span style="color:#ff0000">Note that migrating from/to a DB storage provider is a destructive action that cannot be recovered, it implies deleting the old/existing files</span>.</li></ul>
<p>Please note that during the migration the whole set of records in the table being migrated (attachment, archive, image) is locked, so operations on these records are not permitted.  Because of this, it is recommended to run this process in a <b>maintenance window</b> without users logged in the system.</p>
<p>In case of failure the attachments / archives / images that succeeded as a whole from a client are still migrated, but not partial records (which would result in data corruption if allowed).</p>
',Updated=TO_TIMESTAMP('2020-03-04 17:01:54','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_ID=200117
;
-- Mar 4, 2020, 4:21:15 PM CET
UPDATE AD_Process_Para SET Name='Client', Description='Client/Tenant for this installation.', Help='A Client is a company or a legal entity. You cannot share data between Clients. Tenant is a synonym for Client.', AD_Reference_ID=18, AD_Reference_Value_ID=129, IsCentrallyMaintained='N',Updated=TO_TIMESTAMP('2020-03-04 16:21:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200287
;
-- Mar 4, 2020, 4:23:12 PM CET
UPDATE AD_Process_Para SET AD_Reference_ID=19, AD_Reference_Value_ID=NULL,Updated=TO_TIMESTAMP('2020-03-04 16:23:12','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Process_Para_ID=200287
;
SELECT register_migration_script('202002281451_IDEMPIERE-4191.sql') FROM dual
;

View File

@ -0,0 +1,388 @@
/**********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Sponsor: *
* - FH *
* Contributors: *
* - Carlos Ruiz *
**********************************************************************/
package org.idempiere.process;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.compiere.model.IArchiveStore;
import org.compiere.model.IAttachmentStore;
import org.compiere.model.IImageStore;
import org.compiere.model.MArchive;
import org.compiere.model.MAttachment;
import org.compiere.model.MClient;
import org.compiere.model.MClientInfo;
import org.compiere.model.MImage;
import org.compiere.model.MStorageProvider;
import org.compiere.model.Query;
import org.compiere.process.ProcessInfoParameter;
import org.compiere.process.SvrProcess;
import org.compiere.util.CacheMgt;
/**
* IDEMPIERE-4191
* @author Carlos Ruiz - globalqss
*/
public class MigrateStorageProvider extends SvrProcess {
private int p_AD_Client_ID = -1;
private int p_Actual_StorageProvider_ID = 0;
private int p_AD_StorageProvider_ID = -1;
private boolean p_IsMigrateAttachment = false;
private boolean p_IsMigrateArchive = false;
private boolean p_IsMigrateImage = false;
private boolean p_DeleteOld = false;
int cntAttachment = 0;
int cntArchive = 0;
int cntImage = 0;
/**
* Prepare - e.g., get Parameters.
*/
protected void prepare() {
for (ProcessInfoParameter para : getParameter()) {
String name = para.getParameterName();
if ("AD_AllClients_V_ID".equals(name)) {
if (para.getParameter() != null) {
p_AD_Client_ID = para.getParameterAsInt();
}
} else if ("Actual_StorageProvider_ID".equals(name)) {
p_Actual_StorageProvider_ID = para.getParameterAsInt();
} else if ("AD_StorageProvider_ID".equals(name)) {
p_AD_StorageProvider_ID = para.getParameterAsInt();
} else if ("IsMigrateAttachment".equals(name)) {
p_IsMigrateAttachment = para.getParameterAsBoolean();
} else if ("IsMigrateArchive".equals(name)) {
p_IsMigrateArchive = para.getParameterAsBoolean();
} else if ("IsMigrateImage".equals(name)) {
p_IsMigrateImage = para.getParameterAsBoolean();
} else if ("DeleteOld".equals(name)) {
p_DeleteOld = para.getParameterAsBoolean();
} else {
log.log(Level.SEVERE, "Unknown Parameter: " + name);
}
}
} // prepare
/**
* Perform process.
* @return Message
* @throws Exception
*/
protected String doIt() throws Exception {
if (log.isLoggable(Level.INFO))
log.info("AD_AllClients_V_ID" + p_AD_Client_ID
+ ", Actual_StorageProvider_ID=" + p_Actual_StorageProvider_ID
+ ", AD_StorageProvider_ID=" + p_AD_StorageProvider_ID
+ ", IsMigrateAttachment=" + p_IsMigrateAttachment
+ ", IsMigrateArchive=" + p_IsMigrateArchive
+ ", IsMigrateImage=" + p_IsMigrateImage
+ ", DeleteOld=" + p_DeleteOld);
if ( ! (p_IsMigrateAttachment || p_IsMigrateArchive || p_IsMigrateImage ) ) {
return "Nothing to migrate, please select an option";
}
// Create list of clients to process:
// - single AD_Client
// - clients using the actual storage provider (depending on the isMigrate flags)
List<Integer> clients = new ArrayList<Integer>();
if (p_AD_Client_ID >= 0) {
clients.add(p_AD_Client_ID);
p_Actual_StorageProvider_ID = 0;
} else {
StringBuilder whereClause = new StringBuilder();
StringBuilder storageClause = new StringBuilder();
if (p_Actual_StorageProvider_ID > 0) {
storageClause.append("=").append(p_Actual_StorageProvider_ID);
} else {
storageClause.append(" IS NULL");
}
if (p_IsMigrateAttachment) {
whereClause.append("AD_StorageProvider_ID").append(storageClause);
}
if (p_IsMigrateArchive) {
if (whereClause.length() > 0) {
whereClause.append(" OR ");
}
whereClause.append("StorageArchive_ID").append(storageClause);
}
if (p_IsMigrateImage) {
if (whereClause.length() > 0) {
whereClause.append(" OR ");
}
whereClause.append("StorageImage_ID").append(storageClause);
}
int[] ids = new Query(getCtx(), MClientInfo.Table_Name, whereClause.toString(), get_TrxName())
.setOrderBy("AD_Client_ID")
.getIDs();
for (int id : ids) {
clients.add(id);
}
}
if ( clients.size() == 0) {
return "Nothing to migrate, no clients with that storage provider";
}
MStorageProvider newProvider = new MStorageProvider(getCtx(), p_AD_StorageProvider_ID, get_TrxName());
boolean isNewStorageDB = MStorageProvider.METHOD_Database.equals(newProvider.getMethod());
int idxClient = 0;
int totalClients = clients.size();
// for each client
for (int clientid : clients) {
idxClient++;
MClientInfo clientInfo = MClientInfo.get(getCtx(), clientid);
MClient client = MClient.get(getCtx(), clientid);
int odometer = 10;
if (p_IsMigrateAttachment) {
if ( clientInfo.getAD_StorageProvider_ID() == p_AD_StorageProvider_ID
|| (clientInfo.getAD_StorageProvider_ID() == 0 && isNewStorageDB)) {
String msg = client.getName() + " has already attachment storage " + newProvider.getName();
addLog(msg);
} else {
migrateAttachments(newProvider, idxClient, totalClients, clientid, clientInfo, client, odometer);
}
}
if (p_IsMigrateArchive) {
if ( clientInfo.getStorageArchive_ID() == p_AD_StorageProvider_ID
|| (clientInfo.getStorageArchive_ID() == 0 && isNewStorageDB)) {
String msg = client.getName() + " has already archive storage " + newProvider.getName();
addLog(msg);
} else {
migrateArchives(newProvider, idxClient, totalClients, clientid, clientInfo, client, odometer);
}
}
if (p_IsMigrateImage) {
if ( clientInfo.getStorageImage_ID() == p_AD_StorageProvider_ID
|| (clientInfo.getStorageImage_ID() == 0 && isNewStorageDB)) {
String msg = client.getName() + " has already image storage " + newProvider.getName();
addLog(msg);
} else {
migrateImages(newProvider, idxClient, totalClients, clientid, clientInfo, client, odometer);
}
}
} // end for each client
return "@Updated@ " + cntAttachment + " @AD_Attachment_ID@, " + cntArchive + " @AD_Archive_ID@, " + cntImage + " @AD_Image_ID@";
} // doIt
private void migrateAttachments(MStorageProvider newProvider, int idxClient, int totalClients, int clientid,
MClientInfo clientInfo, MClient client, int odometer) throws SQLException {
// migrate attachment
status(idxClient, totalClients, "Migrating attachments for " + client.getName());
int[] attachIds = new Query(getCtx(), MAttachment.Table_Name, "AD_Client_ID=?", get_TrxName())
.setParameters(clientid)
.setOrderBy("AD_Attachment_ID")
.setForUpdate(true) // lock these records in the table
.getIDs();
int cntRecords = attachIds.length;
// iterate on each record of the associated table
int idxAttach = 0;
for (int attachId : attachIds) {
idxAttach++;
if (idxAttach % odometer == 0) {
progress(idxClient, totalClients, idxAttach, cntRecords, "Migrating attachment ");
}
MAttachment attachment = new MAttachment(getCtx(), attachId, get_TrxName());
attachment.getEntries();
attachment.setStorageProvider(newProvider);
attachment.set_ValueNoCheck("Updated", new Timestamp(System.currentTimeMillis())); // to force save
// create file on the new storage provider
attachment.saveEx();
cntAttachment++;
}
// set the corresponding storage provider
int oldProviderId = clientInfo.getAD_StorageProvider_ID();
clientInfo.setAD_StorageProvider_ID(p_AD_StorageProvider_ID);
clientInfo.saveEx();
// cache reset
CacheMgt.get().reset(MClientInfo.Table_Name, clientInfo.getAD_Client_ID());
commitEx();
String msg = "Migrated " + cntRecords + " attachments on " + client.getName();
addLog(msg);
// if delete old
if (p_DeleteOld) {
MStorageProvider oldProvider = new MStorageProvider(getCtx(), oldProviderId, get_TrxName());
if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) {
// DB method doesn't require delete
IAttachmentStore oldStore = oldProvider.getAttachmentStore();
// iterate on each record of the associated table
idxAttach = 0;
for (int attachId : attachIds) {
idxAttach++;
if (idxAttach % odometer == 0) {
progress(idxClient, totalClients, idxAttach, cntRecords, "Deleting old attachment ");
}
// delete file on old storage
MAttachment attachment = new MAttachment(getCtx(), attachId, get_TrxName());
attachment.setStorageProvider(newProvider);
attachment.getEntries();
oldStore.delete(attachment, oldProvider);
}
msg = "Deleted " + cntRecords + " old attachment files on " + client.getName();
addLog(msg);
}
}
}
private void migrateArchives(MStorageProvider newProvider, int idxClient, int totalClients, int clientid,
MClientInfo clientInfo, MClient client, int odometer) throws SQLException {
// migrate archive
status(idxClient, totalClients, "Migrating archives for " + client.getName());
int[] archiveIds = new Query(getCtx(), MArchive.Table_Name, "AD_Client_ID=?", get_TrxName())
.setParameters(clientid)
.setOrderBy("AD_Archive_ID")
.setForUpdate(true) // lock these records in the table
.getIDs();
int cntRecords = archiveIds.length;
// iterate on each record of the associated table
int idxArchive = 0;
for (int archiveId : archiveIds) {
idxArchive++;
if (idxArchive % odometer == 0) {
progress(idxClient, totalClients, idxArchive, cntRecords, "Migrating archive ");
}
MArchive archive = new MArchive(getCtx(), archiveId, get_TrxName());
byte[] data = archive.getBinaryData();
archive.setStorageProvider(newProvider);
archive.setBinaryData(data);
archive.set_ValueNoCheck("Updated", new Timestamp(System.currentTimeMillis())); // to force save
// create file on the new storage provider
archive.saveEx();
cntArchive++;
}
// set the corresponding storage provider
int oldProviderId = clientInfo.getStorageArchive_ID();
clientInfo.setStorageArchive_ID(p_AD_StorageProvider_ID);
clientInfo.saveEx();
// cache reset
CacheMgt.get().reset(MClientInfo.Table_Name, clientInfo.getAD_Client_ID());
commitEx();
String msg = "Migrated " + cntRecords + " archives on " + client.getName();
addLog(msg);
// if delete old
if (p_DeleteOld) {
MStorageProvider oldProvider = new MStorageProvider(getCtx(), oldProviderId, get_TrxName());
if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) {
// DB method doesn't require delete
IArchiveStore oldStore = oldProvider.getArchiveStore();
// iterate on each record of the associated table
idxArchive = 0;
for (int archiveId : archiveIds) {
idxArchive++;
if (idxArchive % odometer == 0) {
progress(idxClient, totalClients, idxArchive, cntRecords, "Deleting old archive ");
}
// delete file on old storage
MArchive archive = new MArchive(getCtx(), archiveId, get_TrxName());
archive.setStorageProvider(newProvider);
oldStore.deleteArchive(archive, oldProvider);
}
msg = "Deleted " + cntRecords + " old archive files on " + client.getName();
addLog(msg);
}
}
}
private void migrateImages(MStorageProvider newProvider, int idxClient, int totalClients, int clientid,
MClientInfo clientInfo, MClient client, int odometer) throws SQLException {
// migrate image
status(idxClient, totalClients, "Migrating images for " + client.getName());
int[] imageIds = new Query(getCtx(), MImage.Table_Name, "AD_Client_ID=?", get_TrxName())
.setParameters(clientid)
.setOrderBy("AD_Image_ID")
.setForUpdate(true) // lock these records in the table
.getIDs();
int cntRecords = imageIds.length;
// iterate on each record of the associated table
int idxImage = 0;
for (int imageId : imageIds) {
idxImage++;
if (idxImage % odometer == 0) {
progress(idxClient, totalClients, idxImage, cntRecords, "Migrating image ");
}
MImage image = new MImage(getCtx(), imageId, get_TrxName());
byte[] data = image.getBinaryData();
image.setStorageProvider(newProvider);
image.setBinaryData(data);
image.set_ValueNoCheck("Updated", new Timestamp(System.currentTimeMillis())); // to force save
// create file on the new storage provider
image.saveEx();
cntImage++;
}
// set the corresponding storage provider
int oldProviderId = clientInfo.getStorageImage_ID();
clientInfo.setStorageImage_ID(p_AD_StorageProvider_ID);
clientInfo.saveEx();
// cache reset
CacheMgt.get().reset(MClientInfo.Table_Name, clientInfo.getAD_Client_ID());
commitEx();
String msg = "Migrated " + cntRecords + " images on " + client.getName();
addLog(msg);
// if delete old
if (p_DeleteOld) {
MStorageProvider oldProvider = new MStorageProvider(getCtx(), oldProviderId, get_TrxName());
if (! (oldProviderId == 0 || MStorageProvider.METHOD_Database.equals(oldProvider.getMethod()))) {
// DB method doesn't require delete
IImageStore oldStore = oldProvider.getImageStore();
// iterate on each record of the associated table
idxImage = 0;
for (int imageId : imageIds) {
idxImage++;
if (idxImage % odometer == 0) {
progress(idxClient, totalClients, idxImage, cntRecords, "Deleting old image ");
}
// delete file on old storage
MImage image = new MImage(getCtx(), imageId, get_TrxName());
image.setStorageProvider(newProvider);
oldStore.delete(image, oldProvider);
}
msg = "Deleted " + cntRecords + " old image files on " + client.getName();
addLog(msg);
}
}
}
private void progress(int idxClient, int totalClients, int idxRecord, int cntRecords, String msg) {
if (processUI != null) {
processUI.statusUpdate("Client " + idxClient + "/" + totalClients + " - " + msg + " " + idxRecord + "/" + cntRecords + " = " + idxRecord*100/cntRecords + "%");
}
}
private void status(int idxClient, int totalClients, String msg) {
if (processUI != null) {
processUI.statusUpdate("Client " + idxClient + "/" + totalClients + " - " + msg);
}
}
} // MigrateStorageProvider

View File

@ -21,6 +21,7 @@ import java.math.RoundingMode;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -75,8 +76,8 @@ public class Doc_AllocationHdr extends Doc
private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02); private static final BigDecimal TOLERANCE = BigDecimal.valueOf(0.02);
/** Facts */ /** Facts */
private ArrayList<Fact> m_facts = null; private ArrayList<Fact> m_facts = null;
BigDecimal gainLossAmt =Env.ZERO; private Hashtable<Integer, BigDecimal> htGainLossAmtByInv = new Hashtable<Integer, BigDecimal>();
private BigDecimal cmGainLossAmt=Env.ZERO; private Hashtable<Integer, BigDecimal> htGainLossAmtByCM = new Hashtable<Integer, BigDecimal>();
private ArrayList<FactLine> gainLossFactList; private ArrayList<FactLine> gainLossFactList;
@ -741,18 +742,32 @@ public class Doc_AllocationHdr extends Doc
.append(" FROM Fact_Acct ") .append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") .append("WHERE AD_Table_ID=? AND Record_ID=?")
.append(" AND C_AcctSchema_ID=?") .append(" AND C_AcctSchema_ID=?")
.append(" AND Account_ID=?")
.append(" AND PostingType='A'"); .append(" AND PostingType='A'");
// For Invoice // For Invoice
List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(), List<Object> valuesInv = DB.getSQLValueObjectsEx(getTrxName(), sql.toString(),
MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID()); MInvoice.Table_ID, invoice.getC_Invoice_ID(), as.getC_AcctSchema_ID(), acct.getAccount_ID());
if (valuesInv != null) { if (valuesInv != null) {
if (invoice.isSOTrx()) { if (invoice.getReversal_ID() == 0 || invoice.get_ID() < invoice.getReversal_ID())
invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr {
invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) {
} else { invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr } else {
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
}
}
else
{
if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo())) {
invoiceSource = (BigDecimal) valuesInv.get(2); // AmtSourceCr
invoiceAccounted = (BigDecimal) valuesInv.get(3); // AmtAcctCr
} else {
invoiceSource = (BigDecimal) valuesInv.get(0); // AmtSourceDr
invoiceAccounted = (BigDecimal) valuesInv.get(1); // AmtAcctDr
}
} }
} }
@ -786,7 +801,7 @@ public class Doc_AllocationHdr extends Doc
acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); acctDifference = invoiceAccounted.subtract(allocationAccounted.abs());
} }
// Full Payment in currency // Full Payment in currency
if (allocationSource.compareTo(invoiceSource) == 0) if (allocationSource.abs().compareTo(invoiceSource.abs()) == 0)
{ {
acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); // gain is negative acctDifference = invoiceAccounted.subtract(allocationAccounted.abs()); // gain is negative
@ -822,13 +837,21 @@ public class Doc_AllocationHdr extends Doc
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct()); MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct()); MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
BigDecimal cmGainLossAmt = htGainLossAmtByCM.get(invoice.getC_Invoice_ID());
if (cmGainLossAmt == null)
cmGainLossAmt = Env.ZERO;
BigDecimal gainLossAmt = htGainLossAmtByInv.get(invoice.getC_Invoice_ID());
if (gainLossAmt == null)
gainLossAmt = Env.ZERO;
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0) if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0)
cmGainLossAmt = cmGainLossAmt.add(acctDifference); cmGainLossAmt = cmGainLossAmt.add(acctDifference);
else else
gainLossAmt = gainLossAmt.add(acctDifference); gainLossAmt = gainLossAmt.add(acctDifference);
htGainLossAmtByCM.put(invoice.getC_Invoice_ID(), cmGainLossAmt);
htGainLossAmtByInv.put(invoice.getC_Invoice_ID(), gainLossAmt);
// //
if (invoice.isSOTrx()) if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo()))
{ {
FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference); FactLine fl = fact.createLine (line, loss, gain, as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString()); fl.setDescription(description.toString());
@ -1049,112 +1072,164 @@ public class Doc_AllocationHdr extends Doc
* @param payment payment * @param payment payment
* @return Error Message or null if OK * @return Error Message or null if OK
*/ */
private String createInvoiceRounding(MAcctSchema as, Fact fact, MAccount bpAcct) { private String createInvoiceRounding(MAcctSchema as, Fact fact, MAccount bpAcct)
{
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
ResultSet rs = null; ResultSet rs = null;
// Invoice AR/AP // Invoice AR/AP
BigDecimal totalInvoiceSource = BigDecimal.ZERO;
BigDecimal totalInvoiceAccounted = BigDecimal.ZERO;
boolean isCMReversal =false ;
MInvoice invoice = null;
MPayment payment = null;
ArrayList<MInvoice> invList = new ArrayList<MInvoice>(); ArrayList<MInvoice> invList = new ArrayList<MInvoice>();
ArrayList<MPayment> payList = new ArrayList<MPayment>();
Hashtable<Integer, Integer> htInvAllocLine = new Hashtable<Integer, Integer>();
for (int i = 0; i < p_lines.length; i++) for (int i = 0; i < p_lines.length; i++)
{ {
MInvoice invoice = null;
MPayment payment = null;
DocLine_Allocation line = (DocLine_Allocation)p_lines[i]; DocLine_Allocation line = (DocLine_Allocation)p_lines[i];
if (line.getC_Invoice_ID() != 0) if (line.getC_Invoice_ID() != 0)
invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName());
if (line.getC_Payment_ID() != 0)
payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
if (invoice != null )
{ {
boolean isDebit = false; invoice = new MInvoice (getCtx(), line.getC_Invoice_ID(), getTrxName());
// to cater for invoice reverse-accrual. if (!invList.contains(invoice))
if (invoice.isSOTrx() && !invoice.isCreditMemo()) invList.add(invoice);
isDebit = true; htInvAllocLine.put(invoice.getC_Invoice_ID(), line.get_ID());
else if (!invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) }
isDebit = true; if (line.getC_Payment_ID() != 0)
else if (invoice.isSOTrx() && invoice.isCreditMemo() && invoice.getReversal_ID() == 0) {
isDebit = true; payment = new MPayment (getCtx(), line.getC_Payment_ID(), getTrxName());
// if (!payList.contains(payment))
StringBuilder sql = new StringBuilder("SELECT ") payList.add(payment);
.append((isDebit )
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") // Invoice
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'")
.append(" AND Account_ID= ? ");
pstmt = null;
rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, MInvoice.Table_ID);
pstmt.setInt(2, invoice.getC_Invoice_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID());
rs = pstmt.executeQuery();
if (rs.next())
{
BigDecimal invoiceSource = rs.getBigDecimal(1);
BigDecimal invoiceAccounted = rs.getBigDecimal(2);
if ( !invList.contains(invoice))
{
totalInvoiceSource =totalInvoiceSource.add(invoiceSource);
totalInvoiceAccounted =totalInvoiceAccounted.add(invoiceAccounted);
}
invList.add(invoice);
}
}
catch (Exception e)
{
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally {
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
} }
} }
BigDecimal allocInvoiceSource = BigDecimal.ZERO;
BigDecimal allocInvoiceAccounted = BigDecimal.ZERO; Hashtable<Integer, BigDecimal> htInvSource = new Hashtable<Integer, BigDecimal>();
MAllocationLine allocationLine = null; Hashtable<Integer, BigDecimal> htInvAccounted = new Hashtable<Integer, BigDecimal>();
FactLine[] factlines = fact.getLines(); for (MInvoice invoice : invList)
boolean isExcludeCMGainLoss = false; {
for (FactLine factLine : factlines) { boolean isDebit = false;
if (bpAcct != null) { // to cater for invoice reverse-accrual.
if (factLine.getAccount_ID() == bpAcct.getAccount_ID() ) if (invoice.getReversal_ID() == 0 || invoice.get_ID() < invoice.getReversal_ID())
{
if (invoice.isSOTrx() && !invoice.isCreditMemo())
isDebit = true;
else if (!invoice.isSOTrx() && invoice.isCreditMemo())
isDebit = true;
}
else
{
if (!invoice.isSOTrx() && !invoice.isCreditMemo())
isDebit = true;
else if (invoice.isSOTrx() && invoice.isCreditMemo())
isDebit = true;
}
//
StringBuilder sql = new StringBuilder("SELECT ")
.append((isDebit )
? "SUM(AmtSourceDr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceCr), SUM(AmtAcctCr)") // po
.append(" FROM Fact_Acct ")
.append("WHERE AD_Table_ID=? AND Record_ID=?") // Invoice
.append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'")
.append(" AND Account_ID= ? ");
pstmt = null;
rs = null;
try
{
pstmt = DB.prepareStatement(sql.toString(), getTrxName());
pstmt.setInt(1, MInvoice.Table_ID);
pstmt.setInt(2, invoice.getC_Invoice_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID());
rs = pstmt.executeQuery();
if (rs.next())
{ {
if (factLine.getLine_ID() != 0 ) BigDecimal invoiceSource = rs.getBigDecimal(1);
BigDecimal invoiceAccounted = rs.getBigDecimal(2);
htInvSource.put(invoice.getC_Invoice_ID(), invoiceSource);
htInvAccounted.put(invoice.getC_Invoice_ID(), invoiceAccounted);
}
}
catch (Exception e)
{
throw new RuntimeException(e.getLocalizedMessage(), e);
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
}
Hashtable<Integer, BigDecimal> htAllocInvSource = new Hashtable<Integer, BigDecimal>();
Hashtable<Integer, BigDecimal> htAllocInvAccounted = new Hashtable<Integer, BigDecimal>();
Hashtable<Integer, Boolean> htIsExcludeCMGainLoss = new Hashtable<Integer, Boolean>();
Hashtable<Integer, Boolean> htIsCMReversal = new Hashtable<Integer, Boolean>();
FactLine[] factlines = fact.getLines();
for (FactLine factLine : factlines)
{
if (bpAcct != null)
{
if (factLine.getAccount_ID() == bpAcct.getAccount_ID())
{
MAllocationLine allocationLine = null;
if (factLine.getLine_ID() != 0)
allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName()); allocationLine = new MAllocationLine(getCtx(), factLine.getLine_ID(), getTrxName());
MInvoice invoice = null;
MPayment payment = null;
if (allocationLine != null) if (allocationLine != null)
{
invoice = allocationLine.getInvoice(); invoice = allocationLine.getInvoice();
if (allocationLine.getC_Payment_ID() > 0)
payment = new MPayment (getCtx(), allocationLine.getC_Payment_ID(), getTrxName());
}
BigDecimal allocInvoiceSource = htAllocInvSource.get(allocationLine.getC_Invoice_ID());
if (allocInvoiceSource == null)
allocInvoiceSource = Env.ZERO;
BigDecimal allocInvoiceAccounted = htAllocInvAccounted.get(allocationLine.getC_Invoice_ID());
if (allocInvoiceAccounted == null)
allocInvoiceAccounted = Env.ZERO;
BigDecimal cmGainLossAmt = htGainLossAmtByCM.get(invoice.getC_Invoice_ID());
if (cmGainLossAmt == null)
cmGainLossAmt = Env.ZERO;
BigDecimal gainLossAmt = htGainLossAmtByInv.get(invoice.getC_Invoice_ID());
if (gainLossAmt == null)
gainLossAmt = Env.ZERO;
Boolean isExcludeCMGainLoss = htIsExcludeCMGainLoss.get(invoice.getC_Invoice_ID());
if (isExcludeCMGainLoss == null)
isExcludeCMGainLoss = Boolean.FALSE;
Boolean isCMReversal = htIsCMReversal.get(invoice.getC_Invoice_ID());
if (isCMReversal == null)
isCMReversal = Boolean.FALSE;
if (invoice.isSOTrx()) if (invoice.isSOTrx())
{ {
if (factLine.getC_Currency_ID() != as.getC_Currency_ID()) if (factLine.getC_Currency_ID() != as.getC_Currency_ID())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr()); {
if (!invoice.isCreditMemo())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceCr());
else
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
}
if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo()) if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr());
else if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) { if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0)
{
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!invoice.getDateAcct().equals(getDateAcct())) if (!invoice.getDateAcct().equals(getDateAcct()))
isCMReversal =true; isCMReversal = true;
} }
if (invoice!=null) if (invoice!=null)
{ {
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) { if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 )
{
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs());
cmGainLossAmt = Env.ZERO; cmGainLossAmt = Env.ZERO;
} }
if (gainLossFactList.contains(factLine)) { if (gainLossFactList.contains(factLine))
{
isExcludeCMGainLoss = true; isExcludeCMGainLoss = true;
} }
} }
@ -1164,8 +1239,8 @@ public class Doc_AllocationHdr extends Doc
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
} }
}
} else else
{ {
if (as.getC_Currency_ID() != factLine.getC_Currency_ID()) if (as.getC_Currency_ID() != factLine.getC_Currency_ID())
allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr()); allocInvoiceSource = allocInvoiceSource.add(factLine.getAmtSourceDr());
@ -1173,58 +1248,100 @@ public class Doc_AllocationHdr extends Doc
if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo()) if (!gainLossFactList.contains(factLine) && !invoice.isCreditMemo())
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctDr());
if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0 ) { if (!gainLossFactList.contains(factLine) && invoice.isCreditMemo() && invoice.getReversal_ID() > 0)
{
allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr()); allocInvoiceAccounted = allocInvoiceAccounted.add(factLine.getAmtAcctCr());
// this is to cater for reverse-accrual. // this is to cater for reverse-accrual.
if (!invoice.getDateAcct().equals(getDateAcct())) if (!invoice.getDateAcct().equals(getDateAcct()))
isCMReversal =true; isCMReversal = true;
} }
if (invoice!=null ) if (invoice != null)
{ {
if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0 ) { if (invoice.isCreditMemo() || invoice.getReversal_ID() > 0)
{
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs()); allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt.abs());
cmGainLossAmt = Env.ZERO; cmGainLossAmt = Env.ZERO;
} }
if (gainLossFactList.contains(factLine)) { if (gainLossFactList.contains(factLine))
{
isExcludeCMGainLoss = true; isExcludeCMGainLoss = true;
} }
} }
}
} htAllocInvSource.put(invoice.getC_Invoice_ID(), allocInvoiceSource);
htAllocInvAccounted.put(invoice.getC_Invoice_ID(), allocInvoiceAccounted);
htGainLossAmtByCM.put(invoice.getC_Invoice_ID(), cmGainLossAmt);
htGainLossAmtByInv.put(invoice.getC_Invoice_ID(), gainLossAmt);
htIsExcludeCMGainLoss.put(invoice.getC_Invoice_ID(), isExcludeCMGainLoss);
htIsCMReversal.put(invoice.getC_Invoice_ID(), isCMReversal);
} }
} }
} }
for (MInvoice invoice : invList)
BigDecimal acctDifference = null; // gain is negative
//
StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(allocInvoiceSource).append("/").append(allocInvoiceAccounted);
if (log.isLoggable(Level.FINE)) log.fine(description.toString());
boolean isBPartnerAdjust = true;
if (allocInvoiceSource.abs().compareTo(totalInvoiceSource.abs()) == 0)
{ {
if (isExcludeCMGainLoss) BigDecimal invoiceSource = htInvSource.get(invoice.getC_Invoice_ID());
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt); if (invoiceSource == null)
if (payment != null && payment.getReversal_ID() > 0 ) invoiceSource = Env.ZERO;
allocInvoiceAccounted = allocInvoiceAccounted.subtract(gainLossAmt); BigDecimal invoiceAccounted = htInvAccounted.get(invoice.getC_Invoice_ID());
else if (invoiceAccounted == null)
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt); invoiceAccounted = Env.ZERO;
if (isCMReversal) BigDecimal allocInvoiceSource = htAllocInvSource.get(invoice.getC_Invoice_ID());
acctDifference = totalInvoiceAccounted.subtract(allocInvoiceAccounted.abs()); if (allocInvoiceSource == null)
else allocInvoiceSource = Env.ZERO;
acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted.abs()); // gain is positive for receipt BigDecimal allocInvoiceAccounted = htAllocInvAccounted.get(invoice.getC_Invoice_ID());
if (allocInvoiceAccounted == null)
allocInvoiceAccounted = Env.ZERO;
BigDecimal cmGainLossAmt = htGainLossAmtByCM.get(invoice.getC_Invoice_ID());
if (cmGainLossAmt == null)
cmGainLossAmt = Env.ZERO;
BigDecimal gainLossAmt = htGainLossAmtByInv.get(invoice.getC_Invoice_ID());
if (gainLossAmt == null)
gainLossAmt = Env.ZERO;
Boolean isExcludeCMGainLoss = htIsExcludeCMGainLoss.get(invoice.getC_Invoice_ID());
if (isExcludeCMGainLoss == null)
isExcludeCMGainLoss = Boolean.FALSE;
Boolean isCMReversal = htIsCMReversal.get(invoice.getC_Invoice_ID());
if (isCMReversal == null)
isCMReversal = Boolean.FALSE;
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference); BigDecimal acctDifference = null; // gain is negative
if (log.isLoggable(Level.FINE)) log.fine(d2.toString()); //
description.append(" - ").append(d2); StringBuilder description = new StringBuilder("Invoice=(").append(getC_Currency_ID()).append(")").append(allocInvoiceSource).append("/").append(allocInvoiceAccounted);
} else{ if (log.isLoggable(Level.FINE)) log.fine(description.toString());
MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), invoice.get_ID(), getTrxName()); boolean isBPartnerAdjust = true;
for (MAllocationHdr alloc : allocations) if (allocInvoiceSource.abs().compareTo(invoiceSource.abs()) == 0)
{ {
StringBuilder sql = new StringBuilder("SELECT ") if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
for (MPayment payment : payList)
{
if (payment != null && payment.getReversal_ID() > 0 )
allocInvoiceAccounted = allocInvoiceAccounted.subtract(gainLossAmt);
else
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
}
if (isCMReversal)
acctDifference = invoiceAccounted.subtract(allocInvoiceAccounted.abs());
else
acctDifference = allocInvoiceAccounted.subtract(invoiceAccounted.abs()); // gain is positive for receipt
StringBuilder d2 = new StringBuilder("(full) = ").append(acctDifference);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
else
{
MAllocationHdr[] allocations = MAllocationHdr.getOfInvoice(getCtx(), invoice.get_ID(), getTrxName());
for (MAllocationHdr alloc : allocations)
{
if (alloc.get_ID() == get_ID())
continue;
StringBuilder sql = new StringBuilder("SELECT ")
.append(invoice.isSOTrx() .append(invoice.isSOTrx()
? "SUM(AmtSourceCr), SUM(AmtAcctCr), SUM(AmtAcctDr)" // so ? "SUM(AmtSourceCr), SUM(AmtAcctCr), SUM(AmtAcctDr)" // so
: "SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtAcctCr)") // po : "SUM(AmtSourceDr), SUM(AmtAcctDr), SUM(AmtAcctCr)") // po
@ -1232,7 +1349,8 @@ public class Doc_AllocationHdr extends Doc
.append("WHERE AD_Table_ID=? AND Record_ID=?") // allocation .append("WHERE AD_Table_ID=? AND Record_ID=?") // allocation
.append(" AND C_AcctSchema_ID=?") .append(" AND C_AcctSchema_ID=?")
.append(" AND PostingType='A'") .append(" AND PostingType='A'")
.append(" AND Account_ID= ? "); .append(" AND Account_ID=?")
.append(" AND Line_ID IN (SELECT C_AllocationLine_ID FROM C_AllocationLine WHERE C_AllocationHdr_ID=? AND C_Invoice_ID=?)");
pstmt = null; pstmt = null;
rs = null; rs = null;
try try
@ -1242,15 +1360,17 @@ public class Doc_AllocationHdr extends Doc
pstmt.setInt(2, alloc.get_ID()); pstmt.setInt(2, alloc.get_ID());
pstmt.setInt(3, as.getC_AcctSchema_ID()); pstmt.setInt(3, as.getC_AcctSchema_ID());
pstmt.setInt(4, bpAcct.getAccount_ID()); pstmt.setInt(4, bpAcct.getAccount_ID());
pstmt.setInt(5, alloc.get_ID());
pstmt.setInt(6, invoice.getC_Invoice_ID());
rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
if (rs.next()) if (rs.next())
{ {
BigDecimal allocateSource = rs.getBigDecimal(1); BigDecimal allocateSource = rs.getBigDecimal(1);
BigDecimal allocateAccounted = rs.getBigDecimal(2); BigDecimal allocateAccounted = rs.getBigDecimal(2);
BigDecimal allocateCredit = rs.getBigDecimal(3); BigDecimal allocateCredit = rs.getBigDecimal(3);
allocInvoiceSource =allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO); allocInvoiceSource = allocInvoiceSource.add(allocateSource != null ? allocateSource: BigDecimal.ZERO);
allocInvoiceAccounted =allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : BigDecimal.ZERO); allocInvoiceAccounted = allocInvoiceAccounted.add(allocateAccounted != null ? allocateAccounted : BigDecimal.ZERO);
allocInvoiceAccounted= allocInvoiceAccounted.subtract(allocateCredit != null ? allocateCredit : BigDecimal.ZERO); allocInvoiceAccounted = allocInvoiceAccounted.subtract(allocateCredit != null ? allocateCredit : BigDecimal.ZERO);
} }
} }
@ -1258,88 +1378,100 @@ public class Doc_AllocationHdr extends Doc
{ {
throw new RuntimeException(e.getLocalizedMessage(), e); throw new RuntimeException(e.getLocalizedMessage(), e);
} }
finally { finally
{
DB.close(rs, pstmt); DB.close(rs, pstmt);
rs = null; pstmt = null; rs = null; pstmt = null;
}
} }
double multiplier = allocInvoiceSource.doubleValue() / invoiceSource.doubleValue();
// Reduce Orig Invoice Accounted
BigDecimal reduceOrigAccounted = invoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
if (reduceOrigAccounted.compareTo(invoiceAccounted) < 0 )
invoiceAccounted = reduceOrigAccounted;
if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
// Difference based on percentage of Orig Invoice
acctDifference = allocInvoiceAccounted.subtract(invoiceAccounted);
// ignore Tolerance
if (acctDifference.abs().compareTo(BigDecimal.valueOf(0.01)) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
} }
double multiplier = allocInvoiceSource.doubleValue() / totalInvoiceSource.doubleValue();
if (acctDifference.signum() == 0)
// Reduce Orig Invoice Accounted
BigDecimal reduceOrigAccounted = totalInvoiceAccounted.multiply(BigDecimal.valueOf(multiplier));
if (reduceOrigAccounted.compareTo(totalInvoiceAccounted) < 0 )
totalInvoiceAccounted = reduceOrigAccounted;
if (isExcludeCMGainLoss)
allocInvoiceAccounted = allocInvoiceAccounted.add(cmGainLossAmt);
allocInvoiceAccounted = allocInvoiceAccounted.add(gainLossAmt);
// Difference based on percentage of Orig Invoice
acctDifference = allocInvoiceAccounted.subtract(totalInvoiceAccounted);
// ignore Tolerance
if (acctDifference.abs().compareTo(BigDecimal.valueOf(0.01)) < 0)
acctDifference = Env.ZERO;
// Round
int precision = as.getStdPrecision();
if (acctDifference.scale() > precision)
acctDifference = acctDifference.setScale(precision, RoundingMode.HALF_UP);
StringBuilder d2 = new StringBuilder("(partial) = ").append(acctDifference).append(" - Multiplier=").append(multiplier);
if (log.isLoggable(Level.FINE)) log.fine(d2.toString());
description.append(" - ").append(d2);
}
if (acctDifference.signum() == 0)
{
log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (acctDifference.abs().compareTo(TOLERANCE) <= 0)
{
if (invoice.isSOTrx())
{ {
FactLine fl = null; log.fine("No Difference");
return null;
}
MAccount gain = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedGain_Acct());
MAccount loss = MAccount.get (as.getCtx(), as.getAcctSchemaDefault().getRealizedLoss_Acct());
//
if (acctDifference.abs().compareTo(TOLERANCE) <= 0)
{
Integer C_AllocationLine_ID = htInvAllocLine.get(invoice.getC_Invoice_ID());
if ((invoice.isSOTrx() && !invoice.isCreditMemo()) || (!invoice.isSOTrx() && invoice.isCreditMemo()))
{
FactLine fl = null;
if (!isBPartnerAdjust) if (!isBPartnerAdjust)
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
else else
fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference); fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference);
fl.setDescription(description.toString()); fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
if (!fact.isAcctBalanced()) if (!fact.isAcctBalanced())
{ {
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID() ) if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID())
{ {
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
} else }
else
{ {
fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, loss, gain,as.getC_Currency_ID(), acctDifference.negate());
} }
} }
}else fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
}
else
{ {
FactLine fl = null; FactLine fl = null;
if (!isBPartnerAdjust) if (!isBPartnerAdjust)
fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference.negate());
else else
fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference.negate()); fl = fact.createLine (null, bpAcct,as.getC_Currency_ID(), acctDifference.negate());
fl.setDescription(description.toString()); fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
if (!fact.isAcctBalanced()) if (!fact.isAcctBalanced())
{ {
if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID() ) if (as.isCurrencyBalancing() && as.getC_Currency_ID() != invoice.getC_Currency_ID())
{ {
fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference); fl = fact.createLine (null, as.getCurrencyBalancing_Acct(),as.getC_Currency_ID(), acctDifference);
} else { }
fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference); else
{
fl = fact.createLine (null, loss, gain, as.getC_Currency_ID(), acctDifference);
} }
} }
fl.setDescription(description.toString());
fl.setLine_ID(C_AllocationLine_ID == null ? 0 : C_AllocationLine_ID);
} }
} }
}
return null; return null;
} // createInvoiceRounding } // createInvoiceRounding

View File

@ -763,6 +763,21 @@ public class Doc_MatchInv extends Doc
cr.setQty(getQty().multiply(multiplier).negate()); cr.setQty(getQty().multiply(multiplier).negate());
} }
} }
// Rounding correction
if (refInvLine != null && refInvLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
{
p_Error = createInvoiceGainLoss(as, fact, expense, refInvLine.getParent(), dr.getAmtSourceCr(), dr.getAmtAcctCr());
if (p_Error != null)
return null;
}
if (m_invoiceLine != null && m_invoiceLine.getParent().getC_Currency_ID() != as.getC_Currency_ID()) // in foreign currency
{
p_Error = createInvoiceGainLoss(as, fact, expense, m_invoiceLine.getParent(), cr.getAmtSourceDr(), cr.getAmtAcctDr());
if (p_Error != null)
return null;
}
if (m_matchInv.getReversal_ID() == 0) if (m_matchInv.getReversal_ID() == 0)
{ {
cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID()); cr.setC_Activity_ID(m_invoiceLine.getC_Activity_ID());
@ -880,7 +895,7 @@ public class Doc_MatchInv extends Doc
return null; return null;
// //
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID()) if (m_matchInv.getReversal_ID() == 0)
{ {
String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv " String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv "
+ "WHERE C_InvoiceLine_ID IN (SELECT C_InvoiceLine_ID FROM C_InvoiceLine WHERE C_Invoice_ID=?) " + "WHERE C_InvoiceLine_ID IN (SELECT C_InvoiceLine_ID FROM C_InvoiceLine WHERE C_Invoice_ID=?) "
@ -939,15 +954,28 @@ public class Doc_MatchInv extends Doc
if (totalAmtAcctCr == null) if (totalAmtAcctCr == null)
totalAmtAcctCr = Env.ZERO; totalAmtAcctCr = Env.ZERO;
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) if (m_matchInv.getReversal_ID() == 0)
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); {
} matchInvSource = matchInvSource.add(totalAmtSourceCr);
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0) matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
{ }
matchInvSource = matchInvSource.add(totalAmtSourceDr); else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); {
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
}
else if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr);
}
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr);
}
} }
else else
{ {
@ -955,13 +983,13 @@ public class Doc_MatchInv extends Doc
{ {
matchInvSource = matchInvSource.add(totalAmtSourceDr); matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
acctDifference = totalAmtAcctCr.negate(); acctDifference = totalAmtAcctCr;
} }
else else
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
acctDifference = totalAmtSourceDr.negate(); acctDifference = totalAmtAcctDr.negate();
} }
} }
} }
@ -1050,7 +1078,7 @@ public class Doc_MatchInv extends Doc
if (receiptSource == null || receiptAccounted == null) if (receiptSource == null || receiptAccounted == null)
return null; return null;
// //
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID()) if (m_matchInv.getReversal_ID() == 0)
{ {
String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv " String matchInvLineSql = "SELECT M_MatchInv_ID FROM M_MatchInv "
+ "WHERE M_InOutLine_ID IN (SELECT M_InOutLine_ID FROM M_InOutLine WHERE M_InOut_ID=?) " + "WHERE M_InOutLine_ID IN (SELECT M_InOutLine_ID FROM M_InOutLine WHERE M_InOut_ID=?) "
@ -1110,45 +1138,42 @@ public class Doc_MatchInv extends Doc
if (totalAmtAcctCr == null) if (totalAmtAcctCr == null)
totalAmtAcctCr = Env.ZERO; totalAmtAcctCr = Env.ZERO;
if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0) if (m_matchInv.getReversal_ID() == 0)
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); if (totalAmtSourceDr.signum() == 0 && totalAmtAcctDr.signum() == 0)
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
}
else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
{
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
}
else
{
if (m_matchInv.getReversal_ID() == 0 || m_matchInv.get_ID() < m_matchInv.getReversal_ID())
{ {
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) matchInvSource = matchInvSource.add(totalAmtSourceCr);
{ matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
matchInvSource = matchInvSource.add(totalAmtSourceDr); }
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr); else if (totalAmtSourceCr.signum() == 0 && totalAmtAcctCr.signum() == 0)
} {
else matchInvSource = matchInvSource.add(totalAmtSourceDr);
{ matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
matchInvSource = matchInvSource.add(totalAmtSourceCr); }
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr); else if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
} {
matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr).subtract(totalAmtAcctCr);
} }
else else
{ {
if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0) matchInvSource = matchInvSource.add(totalAmtSourceCr);
{ matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr).subtract(totalAmtAcctDr);
matchInvSource = matchInvSource.add(totalAmtSourceDr); }
matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr); }
acctDifference = totalAmtAcctCr.negate(); else
} {
else if (totalAmtAcctDr.compareTo(totalAmtAcctCr) > 0)
{ {
matchInvSource = matchInvSource.add(totalAmtSourceCr); matchInvSource = matchInvSource.add(totalAmtSourceDr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr); matchInvAccounted = matchInvAccounted.add(totalAmtAcctDr);
acctDifference = totalAmtAcctDr.negate(); acctDifference = totalAmtAcctCr.negate();;
} }
else
{
matchInvSource = matchInvSource.add(totalAmtSourceCr);
matchInvAccounted = matchInvAccounted.add(totalAmtAcctCr);
acctDifference = totalAmtAcctDr;
} }
} }
} }

View File

@ -39,7 +39,7 @@ public class MArchive extends X_AD_Archive {
/** /**
* *
*/ */
private static final long serialVersionUID = -9116541441191978777L; private static final long serialVersionUID = -2384941426301490384L;
/** /**
* Get Archives * Get Archives
@ -145,7 +145,7 @@ public class MArchive extends X_AD_Archive {
* @param trxName * @param trxName
*/ */
private void initArchiveStoreDetails(Properties ctx, String trxName) { private void initArchiveStoreDetails(Properties ctx, String trxName) {
MClientInfo clientInfo = MClientInfo.get(ctx); MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
provider=new MStorageProvider(ctx, clientInfo.getStorageArchive_ID(), trxName); provider=new MStorageProvider(ctx, clientInfo.getStorageArchive_ID(), trxName);
} }
@ -286,4 +286,14 @@ public class MArchive extends X_AD_Archive {
if (prov != null && prov.isPendingFlush()) if (prov != null && prov.isPendingFlush())
prov.flush(this,provider); prov.flush(this,provider);
} }
/**
* Set Storage Provider
* Used temporarily for the process to migrate storage provider
* @param Storage provider
*/
public void setStorageProvider(MStorageProvider p) {
provider = p;
}
} // MArchive } // MArchive

View File

@ -57,7 +57,7 @@ public class MAttachment extends X_AD_Attachment
/** /**
* *
*/ */
private static final long serialVersionUID = 6596285414376249694L; private static final long serialVersionUID = -1685512419870004665L;
/** /**
* *
@ -685,4 +685,14 @@ public class MAttachment extends X_AD_Attachment
return destZipFile; return destZipFile;
} }
/**
* Set Storage Provider
* Used temporarily for the process to migrate storage provider
* @param Storage provider
*/
public void setStorageProvider(MStorageProvider p) {
provider = p;
}
} // MAttachment } // MAttachment

View File

@ -339,10 +339,15 @@ public class MImage extends X_AD_Image
* @param trxName * @param trxName
*/ */
private void initImageStoreDetails(Properties ctx, String trxName) { private void initImageStoreDetails(Properties ctx, String trxName) {
MClientInfo clientInfo = MClientInfo.get(ctx); MClientInfo clientInfo = MClientInfo.get(ctx, getAD_Client_ID());
provider=new MStorageProvider(ctx, clientInfo.getStorageImage_ID(), trxName); provider=new MStorageProvider(ctx, clientInfo.getStorageImage_ID(), trxName);
} }
/**
* Set Storage Provider
* Used temporarily for the process to migrate storage provider
* @param Storage provider
*/
public void setStorageProvider(MStorageProvider p) { public void setStorageProvider(MStorageProvider p) {
provider = p; provider = p;
} }

View File

@ -1616,10 +1616,10 @@ public class MInOut extends X_M_InOut implements DocAction
} }
if (!po.isPosted()) if (!po.isPosted())
addDocsPostProcess(po); addDocsPostProcess(po);
MMatchInv matchInvCreated = po.getMatchInvCreated();
if (matchInvCreated != null) { MMatchInv[] matchInvList = MMatchInv.getInOut(getCtx(), getM_InOut_ID(), get_TrxName());
for (MMatchInv matchInvCreated : matchInvList)
addDocsPostProcess(matchInvCreated); addDocsPostProcess(matchInvCreated);
}
} }
// Update PO with ASI // Update PO with ASI
if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0 if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc}/RUN_SyncDBDev.sh"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc}"/>
</launchConfiguration>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramLaunchConfigurationType">
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${workspace}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LAUNCH_CONFIGURATION_BUILD_SCOPE" value="${none}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/mvn"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--batch-mode verify"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc}"/>
</launchConfiguration>

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.adempiere.webui.AdempiereWebUI;
import org.atmosphere.cpr.AtmosphereResource; import org.atmosphere.cpr.AtmosphereResource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -192,11 +193,9 @@ public class AtmosphereServerPush implements ServerPush {
} }
if (!ok) { if (!ok) {
for(int i = 0; i < 3 && !ok; i++) { for(int i = 0; i < 3 && !ok; i++) {
for (int ii = 0; ii < 10 && schedules.size() > 0; ii++) { try {
try { Thread.sleep(100);
Thread.sleep(50); } catch (InterruptedException e1) {}
} catch (InterruptedException e1) {}
}
if (schedules.size() > 0) { if (schedules.size() > 0) {
try { try {
ok = commitResponse(); ok = commitResponse();
@ -209,6 +208,15 @@ public class AtmosphereServerPush implements ServerPush {
} }
if (!ok) { if (!ok) {
log.warn("Failed to resume long polling resource"); log.warn("Failed to resume long polling resource");
Desktop d = desktop.get();
if (d != null) {
Integer count = (Integer) d.getAttribute(AdempiereWebUI.SERVERPUSH_SCHEDULE_FAILURES);
if (count != null)
count = Integer.valueOf(count.intValue()+1);
else
count = Integer.valueOf(1);
d.setAttribute(AdempiereWebUI.SERVERPUSH_SCHEDULE_FAILURES, count);
}
} }
} }
} else { } else {

View File

@ -118,6 +118,8 @@ public class AdempiereWebUI extends Window implements EventListener<Event>, IWeb
private ConcurrentMap<String, String[]> m_URLParameters; private ConcurrentMap<String, String[]> m_URLParameters;
public static final String SERVERPUSH_SCHEDULE_FAILURES = "serverpush.schedule.failures";
public AdempiereWebUI() public AdempiereWebUI()
{ {
this.setVisible(false); this.setVisible(false);

View File

@ -25,6 +25,7 @@ import java.util.Properties;
import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener; import javax.swing.event.ListDataListener;
import org.adempiere.webui.AdempiereWebUI;
import org.adempiere.webui.ValuePreference; import org.adempiere.webui.ValuePreference;
import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.apps.AEnv;
import org.adempiere.webui.component.AutoComplete; import org.adempiere.webui.component.AutoComplete;
@ -768,6 +769,7 @@ ContextMenuListener, IZoomableEditor
private interface ITableDirEditor { private interface ITableDirEditor {
public void setEditor(WTableDirEditor editor); public void setEditor(WTableDirEditor editor);
public void cleanup();
} }
private static class EditorCombobox extends Combobox implements ITableDirEditor { private static class EditorCombobox extends Combobox implements ITableDirEditor {
@ -815,7 +817,7 @@ ContextMenuListener, IZoomableEditor
/** /**
* *
*/ */
protected void cleanup() { public void cleanup() {
if (editor.tableCacheListener != null) { if (editor.tableCacheListener != null) {
CacheMgt.get().unregister(editor.tableCacheListener); CacheMgt.get().unregister(editor.tableCacheListener);
editor.tableCacheListener = null; editor.tableCacheListener = null;
@ -873,7 +875,7 @@ ContextMenuListener, IZoomableEditor
/** /**
* *
*/ */
protected void cleanup() { public void cleanup() {
if (editor.tableCacheListener != null) { if (editor.tableCacheListener != null) {
CacheMgt.get().unregister(editor.tableCacheListener); CacheMgt.get().unregister(editor.tableCacheListener);
editor.tableCacheListener = null; editor.tableCacheListener = null;
@ -916,7 +918,12 @@ ContextMenuListener, IZoomableEditor
} }
private void refreshLookupList() { private void refreshLookupList() {
Executions.schedule(editor.getComponent().getDesktop(), new EventListener<Event>() { int failures = 0;
Desktop desktop = editor.getComponent().getDesktop();
Object attr = desktop.getAttribute(AdempiereWebUI.SERVERPUSH_SCHEDULE_FAILURES);
if (attr != null && attr instanceof Integer)
failures = ((Integer)attr).intValue();
Executions.schedule(desktop, new EventListener<Event>() {
@Override @Override
public void onEvent(Event event) { public void onEvent(Event event) {
try { try {
@ -925,6 +932,13 @@ ContextMenuListener, IZoomableEditor
} catch (Exception e) {} } catch (Exception e) {}
} }
}, new Event("onResetLookupList")); }, new Event("onResetLookupList"));
attr = desktop.getAttribute(AdempiereWebUI.SERVERPUSH_SCHEDULE_FAILURES);
if (attr != null && attr instanceof Integer) {
int f = ((Integer)attr).intValue();
if (f > failures) {
((ITableDirEditor)editor.getComponent()).cleanup();
}
}
} }
@Override @Override

View File

@ -30,6 +30,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.adempiere.webui.AdempiereWebUI;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.zkoss.zk.au.out.AuScript; import org.zkoss.zk.au.out.AuScript;
@ -121,7 +122,7 @@ public class WebSocketServerPush implements ServerPush {
if (endPoint == null) { if (endPoint == null) {
if (dt.isServerPushEnabled()) { if (dt.isServerPushEnabled()) {
try { try {
Thread.sleep(2000); Thread.sleep(300);
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }
endPoint = getEndPoint(dt.getId()); endPoint = getEndPoint(dt.getId());
@ -202,7 +203,18 @@ public class WebSocketServerPush implements ServerPush {
synchronized (schedules) { synchronized (schedules) {
schedules.add(new Schedule(task, event, scheduler)); schedules.add(new Schedule(task, event, scheduler));
} }
echo(); boolean ok = echo();
if (!ok) {
Desktop d = desktop.get();
if (d != null) {
Integer count = (Integer) d.getAttribute(AdempiereWebUI.SERVERPUSH_SCHEDULE_FAILURES);
if (count != null)
count = Integer.valueOf(count.intValue()+1);
else
count = Integer.valueOf(1);
d.setAttribute(AdempiereWebUI.SERVERPUSH_SCHEDULE_FAILURES, count);
}
}
} else { } else {
//in event listener thread, can schedule immediately //in event listener thread, can schedule immediately
scheduler.schedule(task, event); scheduler.schedule(task, event);

View File

@ -290,6 +290,35 @@ Copyright (C) 2007 Ashley G Ramdass.
wgt.$syncScroll () wgt.$syncScroll ()
} }
//Incorporate fix from https://tracker.zkoss.org/browse/ZK-4204
//Probably can be removed after the upgrade to zk9
zk.afterLoad('zk', function () {
if (navigator.sendBeacon && window.URLSearchParams) {
zAu._rmDesktop = function(dt, dummy) {
var url = zk.ajaxURI(null, {desktop: dt, au: true}),
data = jq.param({dtid: dt.id, cmd_0: dummy ? 'dummy' : 'rmDesktop', opt_0: 'i'}),
headers = {};
if (zk.pfmeter) {
var fakeReq = {
setRequestHeader: function (name, value) {
headers[name] = value;
}
};
zAu._pfsend(dt, fakeReq, true, false);
}
var params = new URLSearchParams(data);
for (var key in headers) {
if (headers.hasOwnProperty(key))
params.append(key, headers[key]);
}
navigator.sendBeacon(url, zk.chrome // https://crbug.com/747787
? new Blob([params.toString()], {type: 'application/x-www-form-urlencoded'})
: params
);
}
}
});
]]> ]]>
</script> </script>
<include src="${themePreference}"/> <include src="${themePreference}"/>