Project:
View Issue Details[ Jump to Notes ] | [ Issue History ] [ Print ] | |||||||
ID | ||||||||
0031655 | ||||||||
Type | Category | Severity | Reproducibility | Date Submitted | Last Update | |||
feature request | [Retail Modules] Web POS | minor | have not tried | 2015-12-07 14:59 | 2016-06-16 08:40 | |||
Reporter | mtaal | View Status | public | |||||
Assigned To | mtaal | |||||||
Priority | normal | Resolution | fixed | Fixed in Version | ||||
Status | closed | Fix in branch | Fixed in SCM revision | e7408dbbf027 | ||||
Projection | none | ETA | none | Target Version | ||||
OS | Any | Database | Any | Java version | ||||
OS Version | Database version | Ant version | ||||||
Product Version | SCM revision | |||||||
Review Assigned To | migueldejuana | |||||||
Regression level | ||||||||
Regression date | ||||||||
Regression introduced in release | ||||||||
Regression introduced by commit | ||||||||
Triggers an Emergency Pack | No | |||||||
Summary | 0031655: WebPOS Synchronous transactions | |||||||
Description | See wiki page: http://wiki.openbravo.com/wiki/Projects:WebPOS_Synchronized_Transactions [^] | |||||||
Steps To Reproduce | See description | |||||||
Proposed Solution | See wiki page. | |||||||
Tags | No tags attached. | |||||||
Attached Files | 1505-mobile.diff [^] (107,464 bytes) 2016-05-15 16:48 [Show Content] [Hide Content]diff --git a/src-test/org/openbravo/test/mobile/common/junit/toolbox/OBWildcardPatternSuite.java b/src-test/org/openbravo/test/mobile/common/junit/toolbox/OBWildcardPatternSuite.java --- a/src-test/org/openbravo/test/mobile/common/junit/toolbox/OBWildcardPatternSuite.java +++ b/src-test/org/openbravo/test/mobile/common/junit/toolbox/OBWildcardPatternSuite.java @@ -24,6 +24,7 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -97,6 +98,12 @@ final Class<?> loadedClass = classLoader.loadClass(className); boolean isTestToBeExecuted = true; + // ignore abstract classes, these are sometimes included here if located in + // a test package + if (Modifier.isAbstract(loadedClass.getModifiers())) { + continue; + } + // if we are in high volume mode, add only compatible tests if (SequentialTestInfo.getHighVolumenMode()) { final TestClassAnnotations testClassAnnotations = loadedClass diff --git a/src-test/org/openbravo/test/mobile/common/selenium/terminals/WebPOSTerminalHelper.java b/src-test/org/openbravo/test/mobile/common/selenium/terminals/WebPOSTerminalHelper.java --- a/src-test/org/openbravo/test/mobile/common/selenium/terminals/WebPOSTerminalHelper.java +++ b/src-test/org/openbravo/test/mobile/common/selenium/terminals/WebPOSTerminalHelper.java @@ -173,7 +173,7 @@ } } - private void verifyOrderIsReset() { + protected void verifyOrderIsReset() { final Boolean isOrderList = (Boolean) SeleniumHelper .executeScriptWithReturn("OB.MobileApp.model.orderList !== undefined"); if (isOrderList) { @@ -200,7 +200,7 @@ } private void verifyIsScanTab() { - final String currentTab= PosterminalAPI.getLastTabShown(); + final String currentTab = PosterminalAPI.getLastTabShown(); assertThat("The test is finished but the selected tab is not the 'scan' tab", currentTab, equalTo("scan")); } diff --git a/src-test/org/openbravo/test/mobile/common/selenium/utils/AllowedErrorsHelper.java b/src-test/org/openbravo/test/mobile/common/selenium/utils/AllowedErrorsHelper.java --- a/src-test/org/openbravo/test/mobile/common/selenium/utils/AllowedErrorsHelper.java +++ b/src-test/org/openbravo/test/mobile/common/selenium/utils/AllowedErrorsHelper.java @@ -27,6 +27,7 @@ import org.openbravo.test.mobile.common.selenium.testhelpers.SequentialTestInfo; import org.openbravo.test.mobile.common.selenium.testhelpers.TestLogger; +import org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions.TestSynchronizedSaleWithError; public class AllowedErrorsHelper { private static ArrayList<String> testsAllowedToHaveTomcatErrors; @@ -60,6 +61,7 @@ testsAllowedToHaveTomcatErrors.add("TerminalChangeNotAllowedAfterLogout"); testsAllowedToHaveTomcatErrors.add("SecureTerminalConfChange"); testsAllowedToHaveTomcatErrors.add("I31062_CheckValidationForNonLayawayAllowedUsers"); + testsAllowedToHaveTomcatErrors.add(TestSynchronizedSaleWithError.class.getSimpleName()); // To handle this case: // WARN org.openbravo.dal.core.OBContext - The user 3073EDF96A3C42CC86C7069E379522D2 does not @@ -67,6 +69,12 @@ testsAllowedToHaveTomcatErrors.add("I30997_NewCustomerForReceipt"); testsAllowedToHaveTomcatErrors.add("I31195_MultipleAddressesSearch"); testsAllowedToHaveTomcatErrors.add("I31196_ReassignNewCustomer"); + testsAllowedToHaveTomcatErrors.add("TestSynchronizedTransaction.testSale"); + testsAllowedToHaveTomcatErrors.add("TestSynchronizedTransaction.testCashup"); + testsAllowedToHaveTomcatErrors.add("TestSynchronizedTransaction.testCashManagement"); + testsAllowedToHaveTomcatErrors.add("TestSynchronizedTransaction.testCustomerCreationComplex"); + testsAllowedToHaveTomcatErrors.add("TestSynchronizedTransaction.testCustomerCreationSimple"); + return testsAllowedToHaveTomcatErrors; } @@ -117,6 +125,7 @@ testsAllowedToHaveJavascriptErrors.add("I32306_VerifyOrderLineNegateQtyWithPreference"); testsAllowedToHaveJavascriptErrors.add("I32360_VerifyFamilyProductInAssortment"); testsAllowedToHaveJavascriptErrors.add("I31158_VerifyLayawayWithReturn"); + testsAllowedToHaveJavascriptErrors.add(TestSynchronizedSaleWithError.class.getSimpleName()); // illegal allowed errors. these errors have to be fixed: testsAllowedToHaveJavascriptErrors.add("TerminalChangeAllowed"); @@ -124,6 +133,7 @@ testsAllowedToHaveJavascriptErrors.add("TerminalChangeAllowedAfterCashup"); testsAllowedToHaveJavascriptErrors.add("I31715_CheckPopupError"); testsAllowedToHaveJavascriptErrors.add("I32016_FailToSaveManifest"); + return testsAllowedToHaveJavascriptErrors; } @@ -180,11 +190,13 @@ testsAllowedToHaveLogclientErrors.add("I32360_VerifyFamilyProductInAssortment"); testsAllowedToHaveLogclientErrors.add("I31158_VerifyLayawayWithReturn"); testsAllowedToHaveLogclientErrors.add("I32558_VerifiedReturnsChangeQuantityLine"); + testsAllowedToHaveLogclientErrors.add(TestSynchronizedSaleWithError.class.getSimpleName()); // illegal allowed tests: testsAllowedToHaveLogclientErrors.add("I27554_SwitchToERPAndBackToWebPOSDifferentAccount"); testsAllowedToHaveLogclientErrors.add("SVBSChangePricelistInLayaway"); testsAllowedToHaveLogclientErrors.add("I31715_CheckPopupError"); + return testsAllowedToHaveLogclientErrors; } diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java deleted file mode 100644 --- a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - ************************************************************************* - * The contents of this file are subject to the Openbravo Public License - * Version 1.0 (the "License"), being the Mozilla Public License - * Version 1.1 with a permitted attribution clause; you may not use this - * file except in compliance with the License. You may obtain a copy of - * the License at http://www.openbravo.com/legal/license.html - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * The Original Code is Openbravo ERP. - * The Initial Developer of the Original Code is Openbravo S.L.U. - * All portions are Copyright (C) 2014 Openbravo S.L.U. - * All Rights Reserved. - * Contributor(s): ______________________________________. - ************************************************************************ - */ - -package org.openbravo.test.mobile.retail.pack.selenium.tests.sales; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; - -import org.junit.Test; -import org.openbravo.test.mobile.common.TestAnnotations; -import org.openbravo.test.mobile.common.selenium.SeleniumHelper; -import org.openbravo.test.mobile.common.selenium.javascript.SynchronizationHelper; -import org.openbravo.test.mobile.common.selenium.javascript.TestId; -import org.openbravo.test.mobile.common.selenium.terminals.WebPOSTerminalHelper; - -public class I31655_CreateSynchronizedSale extends WebPOSTerminalHelper { - - @Test - @TestAnnotations(waitFixOf = 31655) - public void test() { - final Boolean preference = (Boolean) SeleniumHelper - .executeScriptWithReturn("OB.MobileApp.model.get('permissions').OBPOS_SynchronizedRequestOrder;"); - - SeleniumHelper - .executeScript("OB.MobileApp.model.get('permissions').OBPOS_SynchronizedRequestOrder=true;"); - final Long beforeTime = (Long) SeleniumHelper - .executeScriptWithReturn("OB.UTIL.showLoadingChangeTime"); - tap(TestId.BUTTON_SEARCH); - write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER.getRowName()); - tap(TestId.BUTTON_SEARCH_EXECUTE); - verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); - tap(TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER); - verify(TestId.LABEL_TOTALTOPAY, "150.50"); - tap(TestId.BUTTON_SEARCH); - write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT.getRowName()); - tap(TestId.BUTTON_SEARCH_EXECUTE); - verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); - tap(TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT); - verify(TestId.LABEL_TOTALTOPAY, "165.00"); - tap(TestId.BUTTON_PAY); - tap(TestId.BUTTON_PAY_EXACT); - tap(TestId.BUTTON_PAY_DONE); - verify(TestId.LABEL_TOTALTOPAY, "0.00"); - SynchronizationHelper.waitUntiTheApplicationHasSynchronized(); - final Long afterTime = (Long) SeleniumHelper.executeScriptWithReturn("OB.UTIL.showLoadingChangeTime"); - assertThat("showLoading wasn't appeared", afterTime, greaterThan(beforeTime)); - - SeleniumHelper - .executeScript("OB.MobileApp.model.get('permissions').OBPOS_SynchronizedRequestOrder=false;"); - final Long beforeTime2 = (Long) SeleniumHelper - .executeScriptWithReturn("OB.UTIL.showLoadingChangeTime"); - tap(TestId.BUTTON_SEARCH); - write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER.getRowName()); - tap(TestId.BUTTON_SEARCH_EXECUTE); - verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); - tap(TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER); - verify(TestId.LABEL_TOTALTOPAY, "150.50"); - tap(TestId.BUTTON_SEARCH); - write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT.getRowName()); - tap(TestId.BUTTON_SEARCH_EXECUTE); - verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); - tap(TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT); - verify(TestId.LABEL_TOTALTOPAY, "165.00"); - tap(TestId.BUTTON_PAY); - tap(TestId.BUTTON_PAY_EXACT); - tap(TestId.BUTTON_PAY_DONE); - verify(TestId.LABEL_TOTALTOPAY, "0.00"); - SynchronizationHelper.waitUntiTheApplicationHasSynchronized(); - final Long afterTime2 = (Long) SeleniumHelper - .executeScriptWithReturn("OB.UTIL.showLoadingChangeTime"); - assertThat("showLoading wasn't appeared", afterTime2, equalTo(beforeTime2)); - - SeleniumHelper - .executeScript("OB.MobileApp.model.get('permissions').OBPOS_SynchronizedRequestOrder=" - + preference + ";"); - } -} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/BaseSynchronizedTransactionTest.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/BaseSynchronizedTransactionTest.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/BaseSynchronizedTransactionTest.java @@ -0,0 +1,137 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): ______________________________________. + ************************************************************************ + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; + +import org.jboss.netty.handler.timeout.TimeoutException; +import org.openbravo.test.mobile.common.selenium.SeleniumHelper; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperInsertUpdateOrDelete; +import org.openbravo.test.mobile.common.selenium.terminals.WebPOSTerminalHelper; +import org.openbravo.test.mobile.common.selenium.utils.OBUtils; +import org.openbravo.test.mobile.common.selenium.utils.Wait; + +public abstract class BaseSynchronizedTransactionTest extends WebPOSTerminalHelper { + + private static void setPreference() { + // delete as the preference can be there from previous run + new DatabaseHelperInsertUpdateOrDelete("Insert Preference OBMOBC_SynchronizedMode") + .execute( + "INSERT INTO ad_preference(ad_preference_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, value, property, ispropertylist, selected) " + + "VALUES ('D19D716CA32F486587FB5100F08D493D', '39363B0921BB4293B48383844325E84C', '0', 'Y', now(), '100', now(), '100', 'Y', 'OBMOBC_SynchronizedMode', 'Y', 'N')", + 1); + } + + private static void deletePreference() { + new DatabaseHelperInsertUpdateOrDelete("Remove existing OBMOBC_SynchronizedMode").execute( + "DELETE from AD_Preference WHERE ad_preference_id = 'D19D716CA32F486587FB5100F08D493D'", + DatabaseHelperInsertUpdateOrDelete.UNEXPECTED_AFFECTED_ROWS); + } + + private Long beforeTime = 0l; + private boolean testFinishedCorrectly = false; + private boolean shouldSynchronizedDialogAppear = true; + + @Override + public void before() { + // default + setShouldSynchronizedDialogAppear(true); + + super.before(); + + // clear it, if it was there from before + deletePreference(); + setPreference(); + OBUtils.reload(); + + testFinishedCorrectly = false; + + beforeTime = (Long) SeleniumHelper + .executeScriptWithReturn("OB.Data.showSynchronizedDialogChangeTime"); + + final boolean inSynchronizedMode = (Boolean) SeleniumHelper + .executeScriptWithReturn("OB.MobileApp.model.get('permissions').OBMOBC_SynchronizedMode"); + + assertThat("Running in synchronize mode", inSynchronizedMode, equalTo(true)); + } + + @Override + public void after() { + deletePreference(); + if (testFinishedCorrectly) { + // read before reload + final Long afterTime = (Long) SeleniumHelper + .executeScriptWithReturn("OB.Data.showSynchronizedDialogChangeTime"); + + if (isShouldSynchronizedDialogAppear()) { + assertThat("Transaction Dialog hasn't appeared, it should", afterTime, + greaterThan(beforeTime)); + } else { + // should not have appeared + assertThat("Transaction Dialog has appeared, it shouldn't", afterTime, equalTo(beforeTime)); + } + + OBUtils.reload(); + } + boolean afterSuccessfull = false; + try { + super.after(); + afterSuccessfull = true; + } finally { + if (testFinishedCorrectly && afterSuccessfull) { + OBUtils.reload(); + } + } + } + + public boolean isShouldSynchronizedDialogAppear() { + return shouldSynchronizedDialogAppear; + } + + public void setShouldSynchronizedDialogAppear(boolean shouldSynchronizedDialogAppear) { + this.shouldSynchronizedDialogAppear = shouldSynchronizedDialogAppear; + } + + protected void setFinishedCorrectly() { + testFinishedCorrectly = true; + } + + protected void resetFinishedCorrectly() { + testFinishedCorrectly = false; + } + + protected void waitForSynchronizationToReturn() { + new Wait() { + @Override + protected boolean until(final int currentIteration) { + return (Boolean) SeleniumHelper + .executeScriptWithReturn("OB.MobileApp.model.showSynchronizedDialog === null"); + } + + @Override + protected void timeout() { + throw new TimeoutException( + String.format("Synchronized Confirmation Dialog remains visible")); + } + }; + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/SynchronizedCashupWithDeposit.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/SynchronizedCashupWithDeposit.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/SynchronizedCashupWithDeposit.java @@ -0,0 +1,140 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author RAL + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import java.text.NumberFormat; +import java.util.Locale; + +import org.junit.Test; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.testhelpers.WebPOSSnippet; + +public class SynchronizedCashupWithDeposit extends BaseSynchronizedTransactionTest { + + @Test + public void test1() { + WebPOSSnippet.cleanCashup(this); + + depositAmount(); + + verifyCashup(); + setFinishedCorrectly(); + } + + @Test + public void test2() { + setShouldSynchronizedDialogAppear(false); + verifyCashup(); + setFinishedCorrectly(); + } + + private void verifyCashup() { + // first cashup + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHUP); + + // step 1 of 4 + verify(TestId.LABEL_CASHUP_STEP2_TITLE, "Step 1 of 4: Count Cash"); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 2 of 4 + verify(TestId.LABEL_CASHUP_STEP3_TITLE, "Step 2 of 4: Count Cash"); + verify(TestId.LABEL_CASHUP_CARDEXPECTED, "0.00"); + verify(TestId.LABEL_CASHUP_CASHEXPECTED, "111.00"); + verify(TestId.LABEL_CASHUP_CASHCOUNTED, "0.00"); + verify(TestId.LABEL_CASHUP_CASHUSAFOREIGNEXPECTED, "(0.00 USD)"); + verify(TestId.LABEL_CASHUP_CASHUSAEXPECTED, "0.00"); + verify(TestId.LABEL_CASHUP_VOUCHEREXPECTED, "0.00"); + verify(TestId.LABEL_CASHUP_TOTALEXPECTED, "111.00"); + verify(TestId.LABEL_CASHUP_TOTALCOUNTED, "-111.00"); + tap(TestId.BUTTON_CASHUP_CARD_OK); + tap(TestId.BUTTON_CASHUP_CASHUSA_OK); + tap(TestId.BUTTON_CASHUP_VOUCHER_OK); + verify(TestId.LABEL_CASHUP_CASHUSACOUNTED, "(0.00 USD)"); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 3 of 4 + // cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // usa cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select USA Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // voucher + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Voucher to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 4 of 4 + verify(TestId.LABEL_CASHUP_STEP5_TITLE, "Step 4 of 4: Post, print and close"); + verify(TestId.LABEL_CASHUP_POSTPRINTANDCLOSE, "Post, Print & Close"); + verify(TestId.LABEL_CASHUP_NETSALES_TITLE, "Net Sales"); + verify(TestId.LABEL_CASHUP_NETSALES_AMOUNT, "0.00"); + verify(TestId.LABEL_CASHUP_GROSSSALES_TITLE, "Gross Sales"); + verify(TestId.LABEL_CASHUP_GROSSSALES_AMOUNT, "0.00"); + // verify(TestId.LABEL_CASHUP_NETSALES_TAX21TITTLE, "Entregas IVA 21%"); + // verify(TestId.LABEL_CASHUP_NETSALES_TAX21, "0.00"); + verify(TestId.LABEL_CASHUP_NETRETURNS_TITLE, "Net Returns"); + verify(TestId.LABEL_CASHUP_NETRETURNS_AMOUNT, "0.00"); + verify(TestId.LABEL_CASHUP_GROSSRETURNS_TITLE, "Gross Returns"); + verify(TestId.LABEL_CASHUP_GROSSRETURNS_AMOUNT, "0.00"); + verify(TestId.LABEL_CASHUP_GROSSRETURNS_TITLE, "Gross Returns"); + verify(TestId.LABEL_CASHUP_DEPOSIT_TOTAL, "111.00"); + verify(TestId.LABEL_CASHUP_EXPECTED_TOTAL, "111.00"); + verify(TestId.LABEL_CASHUP_TOTALTRASACTIONS, "0.00"); + tap(TestId.BUTTON_CASHUP_CANCEL); + // tap(TestId.BUTTON_CASHUP_POSTPRINTANDCLOSE); + // + // // done + // verify(TestId.LABEL_POPUP_TITLE, "Good job!"); + // tap(TestId.BUTTON_POPUP_OK); + // verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } + + private void depositAmount() { + final int amount = 111; + + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHMANAGEMENT); + verify(TestId.LABEL_CASHMANAGEMENT_TITLE, "Cash Management"); + WebPOSSnippet.tapKeypad(this, amount); + tap(TestId.BUTTON_CASHMANAGEMENT_CASHDEPOSIT); + verify(TestId.LABEL_SELECTDEPOSIT_BACOFFICEVBS, "Backoffice transfer to VBS"); + tap(TestId.BUTTON_SELECTDEPOSIT_BACOFFICEVBS); + verify(TestId.LABEL_CASHMANAGEMENT_ROW1_AMOUNT, + String.format("%s.00", NumberFormat.getNumberInstance(Locale.US).format(amount))); + verify(TestId.LABEL_CASHMANAGEMENT_ROW1_DESCRIPTION, + "Deposit: Cash - Backoffice transfer to VBS"); + tap(TestId.BUTTON_CASHMANAGEMENT_DONE); + verify(TestId.LABEL_POPUP_TITLE, "Done"); + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + } + +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/SynchronizedCashupWithSaleAndReturn.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/SynchronizedCashupWithSaleAndReturn.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/SynchronizedCashupWithSaleAndReturn.java @@ -0,0 +1,197 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import org.junit.Test; +import org.openbravo.test.mobile.common.TestClassAnnotations; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; + +@TestClassAnnotations(isHighVolumeCompatible = true) +public class SynchronizedCashupWithSaleAndReturn extends BaseSynchronizedTransactionTest { + + @Test + public void test() { + firstCashup(); + sale(); + secondCashup(); + setFinishedCorrectly(); + } + + private void sale() { + // sale + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_ADHESIVEBODYWARNMERS.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_ADHESIVEBODYWARNMERS); + verify(TestId.LABEL_TOTALTOPAY, "3.60"); + + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_TEKTOWEL.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_TEKTOWEL); + verify(TestId.LABEL_TOTALTOPAY, "23.50"); + + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_ALPINESKIING.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_ALPINESKIING); + verify(TestId.LABEL_TOTALTOPAY, "133.40"); + + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_BABYCARRIER.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_BABYCARRIER); + verify(TestId.LABEL_TOTALTOPAY, "243.90"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // with return + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_RETURNTHISRECEIPT); + verify(TestId.LABEL_RECEIPT_TYPE, "To be Returned"); + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_BABYCARRIER.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + tap(TestId.BUTTON_SEARCHPRODUCT_BABYCARRIER); + verify(TestId.LABEL_TOTALTOPAY, "-110.50"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + } + + private void firstCashup() { + // first cashup + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHUP); + + // step 1 of 4 + verify(TestId.LABEL_CASHUP_STEP2_TITLE, "Step 1 of 4: Count Cash"); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 2 of 4 + verify(TestId.LABEL_CASHUP_STEP3_TITLE, "Step 2 of 4: Count Cash"); + tap(TestId.BUTTON_CASHUP_CARD_OK); + tap(TestId.BUTTON_CASHUP_CASHUSA_OK); + tap(TestId.BUTTON_CASHUP_VOUCHER_OK); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 3 of 4 + // cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // usa cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select USA Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // voucher + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Voucher to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 4 of 4 + verify(TestId.LABEL_CASHUP_STEP5_TITLE, "Step 4 of 4: Post, print and close"); + verify(TestId.LABEL_CASHUP_POSTPRINTANDCLOSE, "Post, Print & Close"); + tap(TestId.BUTTON_CASHUP_POSTPRINTANDCLOSE); + + // done + verify(TestId.LABEL_POPUP_TITLE, "Good job!"); + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } + + private void secondCashup() { + // first cashup + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHUP); + + // step 1 of 4 + verify(TestId.LABEL_CASHUP_STEP2_TITLE, "Step 1 of 4: Count Cash"); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 2 of 4 + verify(TestId.LABEL_CASHUP_STEP3_TITLE, "Step 2 of 4: Count Cash"); + verify(TestId.LABEL_CASHUP_CARDEXPECTED, "0.00"); + verify(TestId.LABEL_CASHUP_CASHEXPECTED, "133.40"); + verify(TestId.LABEL_CASHUP_CASHCOUNTED, "0.00"); + verify(TestId.LABEL_CASHUP_CASHUSAFOREIGNEXPECTED, "(0.00 USD)"); + verify(TestId.LABEL_CASHUP_CASHUSAEXPECTED, "0.00"); + verify(TestId.LABEL_CASHUP_VOUCHEREXPECTED, "0.00"); + verify(TestId.LABEL_CASHUP_TOTALEXPECTED, "133.40"); + verify(TestId.LABEL_CASHUP_TOTALCOUNTED, "-133.40"); + tap(TestId.BUTTON_CASHUP_CARD_OK); + tap(TestId.BUTTON_CASHUP_CASHUSA_OK); + tap(TestId.BUTTON_CASHUP_VOUCHER_OK); + verify(TestId.LABEL_CASHUP_CASHUSACOUNTED, "(0.00 USD)"); + verify(TestId.LABEL_CASHUP_TOTALCOUNTED, "-133.40"); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 3 of 4 + // cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // usa cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select USA Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // voucher + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Voucher to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 4 of 4 + verify(TestId.LABEL_CASHUP_STEP5_TITLE, "Step 4 of 4: Post, print and close"); + verify(TestId.LABEL_CASHUP_POSTPRINTANDCLOSE, "Post, Print & Close"); + + verify(TestId.LABEL_CASHUP_NETSALES_TITLE, "Net Sales"); + verify(TestId.LABEL_CASHUP_NETSALES_AMOUNT, "201.58"); + verify(TestId.LABEL_CASHUP_NETSALES_2_TAX21, "42.32"); + verify(TestId.LABEL_CASHUP_GROSSSALES_TITLE, "Gross Sales"); + verify(TestId.LABEL_CASHUP_GROSSSALES_AMOUNT, "243.90"); + + verify(TestId.LABEL_CASHUP_NETRETURNS_TITLE, "Net Returns"); + verify(TestId.LABEL_CASHUP_NETRETURNS_AMOUNT, "91.32"); + verify(TestId.LABEL_CASHUP_NETRETURMS_TAX21, "19.18"); + verify(TestId.LABEL_CASHUP_GROSSRETURNS_TITLE, "Gross Returns"); + verify(TestId.LABEL_CASHUP_GROSSRETURNS_AMOUNT, "110.50"); + + verify(TestId.LABEL_CASHUP_TOTALTRASACTIONS, "133.40"); + + tap(TestId.BUTTON_CASHUP_POSTPRINTANDCLOSE); + + // done + verify(TestId.LABEL_POPUP_TITLE, "Good job!"); + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } + +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I25623_VerifiedReturnsAvoidMoreThanOrdered.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I25623_VerifiedReturnsAvoidMoreThanOrdered.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I25623_VerifiedReturnsAvoidMoreThanOrdered.java @@ -0,0 +1,133 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author RAL + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.junit.Test; +import org.openbravo.test.mobile.common.TestAnnotations; +import org.openbravo.test.mobile.common.TestClassAnnotations; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperSelect; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.javascript.TestRegistryHelper; + +/** + * Verifies that we do not return more than ordered + * + * @author MDJ + * + */ +@TestClassAnnotations(isHighVolumeCompatible = true) +public class Synchronized_I25623_VerifiedReturnsAvoidMoreThanOrdered extends + BaseSynchronizedTransactionTest { + + @Test + @TestAnnotations(from = "RR15Q2", waitFixOf = 30773) + public void test() { + final String receiptNo1 = BackboneHelper.getDocumentNo(); + final String customer = get(TestId.BUTTON_RECEIPT_CUSTOMER); + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 5000); + tap(TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER); + tap(TestId.BUTTON_EDIT); + tap(TestId.BUTTON_KEYPAD_5); + tap(TestId.BUTTON_KEYPAD_QUANTITY); + verify(TestId.LABEL_TOTALTOPAY, "752.50"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + checkOrder(receiptNo1); + + final String receiptNo2 = BackboneHelper.getDocumentNo(); + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_VERIFIEDRETURN); + write(TestId.FIELD_SEARCH_RECEIPT, receiptNo1); + tap(TestId.BUTTON_VERIFIEDRETURNS_SEARCH); + verify(TestId.LABEL_VERIFIEDRETURNS_ROW1_TITLE, String.format("%s - %s", receiptNo1, customer)); + tap(TestId.BUTTON_VERIFIEDRETURNS_ROW1); + verify(TestId.LABEL_POPUP_DOCUMENTNO, receiptNo1); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_CHECKALL); + verify(TestId.LABEL_VERIFIEDRETURNS_LINES_PRODUCT, "Avalanche transceiver"); + verify(TestId.LABEL_VERIFIEDRETURNS_LINES_TOTALQTY, "5"); + verify(TestId.LABEL_VERIFIEDRETURNS_LINES_REMAININGQTY, "5"); + write(TestId.INPUT_VERIFIEDRETURNS_LINES_QTY, "1"); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYMINUS); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYPLUS); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYPLUS); + tap(TestId.BUTTON_POPUP_APPLY); + verify(TestId.LABEL_TOTALTOPAY, "-451.50"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + checkOrder(receiptNo2); + + final String receiptNo3 = BackboneHelper.getDocumentNo(); + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_VERIFIEDRETURN); + write(TestId.FIELD_SEARCH_RECEIPT, receiptNo1); + tap(TestId.BUTTON_VERIFIEDRETURNS_SEARCH); + verify(TestId.LABEL_VERIFIEDRETURNS_ROW1_TITLE, String.format("%s - %s", receiptNo1, customer)); + tap(TestId.BUTTON_VERIFIEDRETURNS_ROW1); + verify(TestId.LABEL_POPUP_DOCUMENTNO, receiptNo1); + + TestRegistryHelper.waitForPopupToUpdate(); + + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_CHECKALL); + verify(TestId.LABEL_VERIFIEDRETURNS_LINES_PRODUCT, "Avalanche transceiver"); + verify(TestId.LABEL_VERIFIEDRETURNS_LINES_TOTALQTY, "5"); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYMINUS); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYMINUS); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYPLUS); + tap(TestId.BUTTON_VERIFIEDRETURNS_LINES_QTYPLUS); + tap(TestId.BUTTON_POPUP_APPLY); + verify(TestId.LABEL_TOTALTOPAY, "-301.00"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + checkOrder(receiptNo3); + setFinishedCorrectly(); + } + + private void checkOrder(final String receiptNo) { + // verify that the order has been saved in the backend + final String sql = "select documentno from C_ORDER " + "WHERE documentno='" + receiptNo + "'"; + + new DatabaseHelperSelect() { + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + final String documentno = rs.getString("documentno"); + + assertThat("'Expected' didn't return the expected data", documentno, equalTo(receiptNo)); + } + }.execute(sql, 1); + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I27476_SameDocumentNoAfterPayAndReload.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I27476_SameDocumentNoAfterPayAndReload.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I27476_SameDocumentNoAfterPayAndReload.java @@ -0,0 +1,75 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author RAL + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; + +import org.junit.Test; +import org.openbravo.test.mobile.common.selenium.SeleniumHelper; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.utils.OBUtils; + +public class Synchronized_I27476_SameDocumentNoAfterPayAndReload extends + BaseSynchronizedTransactionTest { + + @Test + public void test() { + // at the end the page is reloaded so then the + // synchronized dialog check can not be done in the after + // check specifically below + setShouldSynchronizedDialogAppear(false); + long beforeTime = (Long) SeleniumHelper + .executeScriptWithReturn("OB.Data.showSynchronizedDialogChangeTime"); + + final String documentNo = BackboneHelper.getDocumentNo(); + + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_SKI); + tap(TestId.BUTTON_PRODUCT_SKI_GLIDEWAX); + verify(TestId.LABEL_TOTALTOPAY, "12.50"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + final String[] documentnoHeader = documentNo.split("/"); + final int documentNumber = Integer.parseInt(documentnoHeader[1]) + 1; + final String newDocumentno = String.format("%s/%07d", documentnoHeader[0], documentNumber); + assertThat(BackboneHelper.getDocumentNo(), equalTo(newDocumentno)); + + final Long afterTime = (Long) SeleniumHelper + .executeScriptWithReturn("OB.Data.showSynchronizedDialogChangeTime"); + + assertThat("Transaction Dialog hasn't appeared, it should", afterTime, greaterThan(beforeTime)); + + // Reload the webpage + OBUtils.reload(); + + assertThat(BackboneHelper.getDocumentNo(), equalTo(newDocumentno)); + setFinishedCorrectly(); + } + +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I27615_PartiallyPaidLayaway.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I27615_PartiallyPaidLayaway.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I27615_PartiallyPaidLayaway.java @@ -0,0 +1,164 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author RAL + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.util.ArrayList; + +import org.junit.Test; +import org.openbravo.test.mobile.common.TestAnnotations; +import org.openbravo.test.mobile.common.selenium.database.WebPOSDatabaseConstants; +import org.openbravo.test.mobile.common.selenium.database.WebPOSDatabaseHelper; +import org.openbravo.test.mobile.common.selenium.database.WebPOSDatabaseHelper.PaymentPlanDetailsOfDocumentno; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.testhelpers.TestLogger; +import org.openbravo.test.mobile.common.selenium.testhelpers.WebPOSSnippet; +import org.openbravo.test.mobile.common.selenium.utils.OBNumber; + +public class Synchronized_I27615_PartiallyPaidLayaway extends BaseSynchronizedTransactionTest { + + private static final int I_28831 = 28831; + private static String receiptNo; + private static String customer; + private static final OBNumber _549_5F = new OBNumber(549.5f); + private static final OBNumber _454_13F = new OBNumber(454.13f); + private static final OBNumber _275 = new OBNumber(275f); + private static final OBNumber _274_5 = new OBNumber(274.5f); + + final WebPOSDatabaseHelper dbh = new WebPOSDatabaseHelper(); + + @Override + public void afterSuccessfulTest_VerifyTerminalIsLeftAsTestStarted() { + if (getTestMethodName().equals("test9")) { + super.afterSuccessfulTest_VerifyTerminalIsLeftAsTestStarted(); + } + } + + @Test + @TestAnnotations(waitFixOf = I_28831) + public void test1() { + // create the layaway + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYTHISRECEIPT); + verify(TestId.LABEL_RECEIPT_TYPE, "To be laid away"); + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_BACKPACKSANDTRAVEL); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_ALPINESKIING); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_ALPINESKIING); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_ALPINESKIING); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_ALPINESKIING); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_ALPINESKIING); + receiptNo = BackboneHelper.getDocumentNo(); + customer = get(TestId.BUTTON_RECEIPT_CUSTOMER); + verify(TestId.LABEL_TOTALTOPAY, "549.50"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // partial pay + tap(TestId.BUTTON_MENU_LAYAWAYS); + write(TestId.FIELD_SEARCH_RECEIPT, receiptNo); + tap(TestId.BUTTON_LAYAWAYS_SEARCH); + tap(TestId.TABLE_RECEIPTSEARCH, String.format("%s - %s", receiptNo, customer)); + tap(TestId.BUTTON_PAY); + WebPOSSnippet.tapKeypad(this, 275); + tap(TestId.BUTTON_CASH); + verify(TestId.LABEL_RECEIPT_PAY_REMAINING, "274.50€"); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // verify the transaction in the server + TestLogger.getLogger().info("Verifying the Sale Payment Plan in the backend"); + final PaymentPlanDetailsOfDocumentno pm = dbh.getPaymentPlanDetailsOf(receiptNo, 1).get(0); + assertThat(pm.accountName, equalTo(WebPOSDatabaseConstants.VBS1001_CASHBOOK_STORE)); + assertThat(pm.paymentMethodName, equalTo("Cash")); + assertThat(pm.currency, equalTo("EUR")); + assertThat(pm.numberOfPayments, equalTo(new OBNumber(1f))); + assertThat(pm.expected, equalTo(_549_5F)); + assertThat(pm.netAmt, equalTo(_454_13F)); + assertThat(pm.received, equalTo(_275)); + assertThat(pm.outstanding, equalTo(_274_5)); + assertThat(pm.paidAmt, equalTo(_275)); + assertThat(pm.paidConverted, equalTo(_275)); + setFinishedCorrectly(); + } + + @Test + @TestAnnotations(to = "RR15Q2", waitFixOf = I_28831) + public void test2() { + tap(TestId.BUTTON_DELETERECEIPT); + tap(TestId.BUTTON_DELETERECEIPT_CONFIRM); + setFinishedCorrectly(); + } + + @Test + @TestAnnotations(waitFixOf = I_28831) + public void test3() { + // pay the outstanding + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYS); + write(TestId.FIELD_SEARCH_RECEIPT, receiptNo); + tap(TestId.BUTTON_LAYAWAYS_SEARCH); + tap(TestId.TABLE_RECEIPTSEARCH, String.format("%s - %s", receiptNo, customer)); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_RECEIPT_PAY_REMAINING, "0.00€"); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // verify the transaction in the server + TestLogger.getLogger().info("Verifying the Sale Payment Plan in the backend"); + final ArrayList<PaymentPlanDetailsOfDocumentno> pms = dbh.getPaymentPlanDetailsOf(receiptNo, 2); + final PaymentPlanDetailsOfDocumentno pm = pms.get(0); + assertThat(pm.accountName, equalTo(WebPOSDatabaseConstants.VBS1001_CASHBOOK_STORE)); + assertThat(pm.paymentMethodName, equalTo("Cash")); + assertThat(pm.currency, equalTo("EUR")); + assertThat(pm.numberOfPayments, equalTo(new OBNumber(2f))); + assertThat(pm.expected, equalTo(_549_5F)); + assertThat(pm.netAmt, equalTo(_454_13F)); + assertThat(pm.received, equalTo(_549_5F)); + assertThat(pm.outstanding, equalTo(OBNumber.ZERO)); + assertThat(pm.paidAmt, equalTo(_275)); + assertThat(pm.paidConverted, equalTo(_275)); + final PaymentPlanDetailsOfDocumentno pm2 = pms.get(1); + assertThat(pm2.accountName, equalTo(WebPOSDatabaseConstants.VBS1001_CASHBOOK_STORE)); + assertThat(pm2.paymentMethodName, equalTo("Cash")); + assertThat(pm2.currency, equalTo("EUR")); + assertThat(pm2.paidAmt, equalTo(_274_5)); + assertThat(pm2.paidConverted, equalTo(_274_5)); + setFinishedCorrectly(); + } + + @Test + @TestAnnotations(to = "RR15Q2", waitFixOf = I_28831) + public void test9() { + tap(TestId.BUTTON_DELETERECEIPT); + tap(TestId.BUTTON_DELETERECEIPT_CONFIRM); + setFinishedCorrectly(); + } + +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I30412_QuotationsAndPromotions.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I30412_QuotationsAndPromotions.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I30412_QuotationsAndPromotions.java @@ -0,0 +1,140 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author JGA + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import org.junit.After; +import org.junit.Test; +import org.openbravo.test.mobile.common.TestClassAnnotations; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperInsertUpdateOrDelete; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.utils.OBUtils; + +@TestClassAnnotations(isHighVolumeCompatible = true) +public class Synchronized_I30412_QuotationsAndPromotions extends BaseSynchronizedTransactionTest { + String documentNo; + + @Test + public void test() { + boolean isTestSuccessful = false; + try { + generatePromotion(); + OBUtils.reload(); // Refresh the terminal to load the changes + + createquotation(); + paysalesorder(); + + // restore + removePromotion(); + isTestSuccessful = true; + OBUtils.reload(); + setFinishedCorrectly(); + } finally { + if (!isTestSuccessful) { + removePromotion(); + } + } + } + + @Override + @After + public void after() { + } + + private void paysalesorder() { + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + } + + private void createquotation() { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CREATEQUOTATION); + verify(TestId.LABEL_RECEIPT_TYPE, "Quotation - Draft"); + + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_TEKTOWEL.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_TEKTOWEL); + tap(TestId.BUTTON_SEARCHPRODUCT_TEKTOWEL); + + verify(TestId.LABEL_TOTALTOPAY, "39.80"); + + tap(TestId.BUTTON_EDIT); + tap(TestId.BUTTON_KEYPAD_PRICE); + tap(TestId.BUTTON_KEYPAD_1); + tap(TestId.BUTTON_KEYPAD_ENTER); + verify(TestId.LABEL_TOTALTOPAY, "2.00"); + + tap(TestId.BUTTON_PAY); + verify(TestId.LABEL_RECEIPT_TYPE, "Quotation - Under Evaluation"); + + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CREATEORDERFROMQUOTATION); + tap(TestId.BUTTON_POPUP_UPDATEPRICES); + tap(TestId.BUTTON_POPUP_CREATEORDER); + verify(TestId.LABEL_TOTALTOPAY, "39.80"); + } + + public void generatePromotion() { + final String insertoffer = "insert into m_offer " + + "(m_offer_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, name," + + "addamt, discount, datefrom, bpartner_selection, bp_group_selection, product_selection," + + "prod_cat_selection, pricelist_selection, m_offer_type_id, apply_next, print_name, org_selection," + + "ismultiple, characteristics_selection, em_obdisc_x, em_obdisc_y, em_obdisc_distribute, em_obdisc_role_selection," + + "em_obdisc_approval_required) " + + "VALUES " + + "('B305DD9172CD4C799088549E9463CFAC', '39363B0921BB4293B48383844325E84C','67839EEFA49E44AC969BD60093FCC899','Y',now(),'100',now(),'100','Issue30412Discount'," + + "0,0,now(),'Y','Y','N'," + + "'Y','Y','E08EE3C23EBA49358A881EF06C139D63','Y','Issue30412Discount','N'," + + "'N','Y',3,2,'N','Y','N')"; + new DatabaseHelperInsertUpdateOrDelete().execute(insertoffer, 1); + final String insertofferproduct = "insert into m_offer_product " + + "(m_offer_product_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, m_offer_id," + + "m_product_id, em_obdisc_is_gift) " + + "VALUES " + + "('A3AA02FC448841C59D93557AA6777204','39363B0921BB4293B48383844325E84C','67839EEFA49E44AC969BD60093FCC899','Y',now(),'100',now(),'100','B305DD9172CD4C799088549E9463CFAC'," + + "'DBC715536AEF47B18E3558FA01D6F770','N')"; + new DatabaseHelperInsertUpdateOrDelete().execute(insertofferproduct, 1); + final String insertofferorg = "insert into m_offer_organization " + + "(m_offer_organization_id, ad_client_id, ad_org_id, isactive, created, createdby, updated, updatedby, m_offer_id) " + + "VALUES " + + "('5A3D5970463D4E5F894EEBBA7AA6EA50','39363B0921BB4293B48383844325E84C','D270A5AC50874F8BA67A88EE977F8E3B','Y',now(),'100',now(),'100','B305DD9172CD4C799088549E9463CFAC')"; + new DatabaseHelperInsertUpdateOrDelete().execute(insertofferorg, 1); + } + + private void removePromotion() { + final String deleteofferorg = "delete from m_offer_organization " + + "WHERE m_offer_organization_id = '5A3D5970463D4E5F894EEBBA7AA6EA50' " + + "AND m_offer_id = 'B305DD9172CD4C799088549E9463CFAC'"; + new DatabaseHelperInsertUpdateOrDelete().execute(deleteofferorg, 1); + final String deleteofferproduct = "delete from m_offer_product " + + "WHERE m_offer_product_id = 'A3AA02FC448841C59D93557AA6777204' " + + "AND m_offer_id = 'B305DD9172CD4C799088549E9463CFAC'"; + new DatabaseHelperInsertUpdateOrDelete().execute(deleteofferproduct, 1); + final String deleteoffer = "delete from m_offer " + + "WHERE m_offer_id = 'B305DD9172CD4C799088549E9463CFAC'"; + new DatabaseHelperInsertUpdateOrDelete().execute(deleteoffer, 1); + } + +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31323_LayawayPayOpenTicket.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31323_LayawayPayOpenTicket.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31323_LayawayPayOpenTicket.java @@ -0,0 +1,99 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author MCA + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import org.junit.Test; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.utils.OBUtils; + +public class Synchronized_I31323_LayawayPayOpenTicket extends BaseSynchronizedTransactionTest { + private String customer; + private String documentNo1; + private String documentNo2; + + @Test + public void test() { + + // sometimes a previous test keeps a ticket there + tap(TestId.BUTTON_DELETERECEIPT); + tap(TestId.BUTTON_DELETERECEIPT_CONFIRM); + + // Create the layaway 1 + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYTHISRECEIPT); + verify(TestId.LABEL_RECEIPT_TYPE, "To be laid away"); + documentNo1 = BackboneHelper.getDocumentNo(); + customer = get(TestId.BUTTON_RECEIPT_CUSTOMER); + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_BACKPACKSANDTRAVEL); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_ALPINESKIING); + verify(TestId.LABEL_TOTALTOPAY, "109.90"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // Create the layaway 2 + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYTHISRECEIPT); + verify(TestId.LABEL_RECEIPT_TYPE, "To be laid away"); + documentNo2 = BackboneHelper.getDocumentNo(); + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_MOUNTAINEERING); + tap(TestId.BUTTON_PRODUCT_MOUNTAINEERING_CRAMPONS10POINT); + verify(TestId.LABEL_TOTALTOPAY, "39.90"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_PAYOPENTICKETS); + write(TestId.FIELD_SEARCH_MULTIORDERS_TEXT, getTerminal()); + tap(TestId.BUTTON_POPUP_OPENTICKETS_SEARCH); + verify(TestId.LABEL_MULTIORDERS_SEARCHRESULTS_ROW1_TOPLINE, + String.format("%s - %s", documentNo2, customer)); + verify(TestId.LABEL_MULTIORDERS_SEARCHRESULTS_ROW2_TOPLINE, + String.format("%s - %s", documentNo1, customer)); + tap(TestId.BUTTON_POPUP_OPENTICKETS_ROW1); + tap(TestId.BUTTON_POPUP_OPENTICKETS_ROW2); + tap(TestId.BUTTON_POPUP_OPENTICKETS_DONE); + + verify(TestId.LABEL_RECEIPT_MULTIORDER_TOTALQTY, "2"); + verify(TestId.LABEL_RECEIPT_MULTIORDER_TOTALGROSS, "149.80"); + + // refresh the page and verify multiorder + OBUtils.reload(); + verify(TestId.LABEL_RECEIPT_MULTIORDER_TOTALQTY, "2"); + verify(TestId.LABEL_RECEIPT_MULTIORDER_TOTALGROSS, "149.80"); + + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + tap(TestId.BUTTON_DELETERECEIPT); + tap(TestId.BUTTON_DELETERECEIPT_CONFIRM); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + setFinishedCorrectly(); + } + +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31462_VoidLayaway.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31462_VoidLayaway.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31462_VoidLayaway.java @@ -0,0 +1,100 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author = RAL + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.junit.Test; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperSelect; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.utils.OBNumber; + +public class Synchronized_I31462_VoidLayaway extends BaseSynchronizedTransactionTest { + + @Test + public void test() { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYTHISRECEIPT); + verify(TestId.LABEL_RECEIPT_TYPE, "To be laid away"); + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_BACKPACKSANDTRAVEL); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_WHISTLE); + verify(TestId.LABEL_TOTALTOPAY, "2.90"); + final String organizationId = BackboneHelper.getTerminalValue("organization"); + final String clientId = BackboneHelper.getTerminalValue("client"); + final String receiptNo = BackboneHelper.getDocumentNo(); + final String customer = get(TestId.BUTTON_RECEIPT_CUSTOMER); + final String cashupId = BackboneHelper.getTerminalValue("cashUpId"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // retrieve the layaway + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYS); + write(TestId.FIELD_SEARCH_RECEIPT, receiptNo); + tap(TestId.BUTTON_LAYAWAYS_SEARCH); + tap(TestId.TABLE_RECEIPTSEARCH, String.format("%s - %s", receiptNo, customer)); + verify(TestId.LABEL_RECEIPT_TYPE, "Layaway"); + verify(TestId.LABEL_RECEIPT_COUNTER, "1"); + verify(TestId.LABEL_TOTALTOPAY, "2.90"); + // void + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_VOIDLAYAWAY); + verify(TestId.LABEL_RECEIPT_TYPE, "Void this Layaway"); + verify(TestId.LABEL_RECEIPT_COUNTER, "1"); + verify(TestId.LABEL_TOTALTOPAY, "2.90"); + isVisible(TestId.BUTTON_PAY_DONE, true); + isVisible(TestId.BUTTON_LAYAWAY, false); + tap(TestId.BUTTON_PAY_DONE); + + verifyOrderStatus(receiptNo, organizationId, clientId, OBNumber.ZERO, OBNumber.ZERO, cashupId, + "CL"); + setFinishedCorrectly(); + } + + public static void verifyOrderStatus(final String documentNo, final String organizationId, + final String clientId, final OBNumber net, final OBNumber gross, final String cashupId, + final String status) { + final String c_order = String + .format( + "SELECT c_order_id, ad_client_id, ad_org_id, totallines, grandtotal, em_obpos_app_cashup_id, docstatus FROM c_order WHERE documentno='%s'", + documentNo); + new DatabaseHelperSelect() { + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + assertThat(rs.getString("ad_org_id"), equalTo(organizationId)); + assertThat(rs.getString("ad_client_id"), equalTo(clientId)); + assertThat(new OBNumber(rs.getBigDecimal("totallines")), equalTo(net)); + assertThat(new OBNumber(rs.getBigDecimal("grandtotal")), equalTo(gross)); + assertThat(rs.getString("em_obpos_app_cashup_id"), equalTo(cashupId)); + assertThat(rs.getString("docstatus"), equalTo(status)); + } + }.execute(c_order, 1); + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31892_VoidLayawayAndCashUp.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31892_VoidLayawayAndCashUp.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_I31892_VoidLayawayAndCashUp.java @@ -0,0 +1,344 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author JGA + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.junit.Test; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperSelect; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.testhelpers.WebPOSSnippet; + +public class Synchronized_I31892_VoidLayawayAndCashUp extends BaseSynchronizedTransactionTest { + private String layawayDocumentNo; + private String salesDocumentNo; + + @Test + public void test() { + WebPOSSnippet.cleanCashup(this); + + createSalesWithCard(); + + createLayaway(); + + partialyPaidLayaway(); + + voidLayawayWithOverpayment(); + + checkPaymentsBeforeCashup(); + + doCashup(); + + checkReconciliations(); + + setFinishedCorrectly(); + } + + private void checkReconciliations() { + String sql = String + .format( + "SELECT fft.status AS status, fft.paymentamt AS paymentamt, fft.depositamt AS depositamt, fft.fin_reconciliation_id AS reconciliation, co.documentNo AS documentNo " + + "FROM c_order co " + + "LEFT JOIN fin_finacc_transaction fft ON co.em_obpos_app_cashup_id = fft.em_obpos_app_cashup_id " + + "WHERE co.documentno in ('%s', '%s') " + + "AND co.em_obpos_applications_id = '%s' " + + "ORDER BY co.documentno, fft.paymentamt, fft.depositamt, fft.fin_reconciliation_id ", + layawayDocumentNo, salesDocumentNo, "12FA7864FBDE4FCC8D6E3891A936D61F"); + new DatabaseHelperSelect() { + int recordNo = 1; + + @Override + protected void yieldResultSet(ResultSet rs) throws SQLException { + final String status = rs.getString("status"); + final Long paymentamt = rs.getLong("paymentamt"); + final Long depositamt = rs.getLong("depositamt"); + final String reconciliation = rs.getString("reconciliation"); + final String documentNo = rs.getString("documentNo"); + System.err.println(">>>>>>>>>>>"); + System.err.println(status); + System.err.println(paymentamt); + System.err.println(depositamt); + System.err.println(reconciliation); + System.err.println(documentNo); + System.err.println(recordNo++); + if (true) { + return; + } + switch (recordNo) { + case 1: + assertEquals(salesDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(50.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 2: + assertEquals(salesDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(50.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 3: + assertEquals(salesDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(161.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 4: + assertEquals(salesDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(221.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 5: + assertEquals(salesDocumentNo, documentNo); + assertEquals(50.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 6: + assertEquals(salesDocumentNo, documentNo); + assertEquals(60.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 7: + assertEquals(salesDocumentNo, documentNo); + assertEquals(161.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 8: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(50.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 9: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(50.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 10: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(161.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 11: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(221.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 12: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(50.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 13: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(60.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + case 14: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(161.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertNotNull(reconciliation); + assertEquals("RPPC", status); + break; + } + recordNo++; + } + }.execute(sql, 14); + + } + + private void doCashup() { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHUP); + // Step 1 of 4 + tap(TestId.BUTTON_CASHUP_COUNTCASH_50); + tap(TestId.BUTTON_CASHUP_NEXT); + // Step 2 of 4 + tap(TestId.BUTTON_CASHUP_CARD_OK); + tap(TestId.BUTTON_CASHUP_CASHUSA_OK); + tap(TestId.BUTTON_CASHUP_VOUCHER_OK); + tap(TestId.BUTTON_CASHUP_NEXT); + // Step 3 of 4 + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // Step 4 of 4 + tap(TestId.BUTTON_CASHUP_POSTPRINTANDCLOSE); + verify(TestId.LABEL_POPUP_CONFIRMATION_TITLE, "The Cash Up process was completed successfully."); + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } + + private void checkPaymentsBeforeCashup() { + String sql = String + .format( + "SELECT fft.status AS status, fft.paymentamt AS paymentamt, fft.depositamt AS depositamt, fft.fin_reconciliation_id AS reconciliation, co.documentNo AS documentNo " + + "FROM c_order co " + + "LEFT JOIN fin_finacc_transaction fft ON co.em_obpos_app_cashup_id = fft.em_obpos_app_cashup_id " + + "WHERE co.documentno in ('%s', '%s') " + + "AND co.em_obpos_applications_id = '%s' " + + "ORDER BY co.documentno, fft.paymentamt, fft.depositamt, fft.fin_reconciliation_id", + layawayDocumentNo, salesDocumentNo, "12FA7864FBDE4FCC8D6E3891A936D61F"); + new DatabaseHelperSelect() { + int recordNo = 1; + + @Override + protected void yieldResultSet(ResultSet rs) throws SQLException { + final String status = rs.getString("status"); + final Long paymentamt = rs.getLong("paymentamt"); + final Long depositamt = rs.getLong("depositamt"); + final String reconciliation = rs.getString("reconciliation"); + final String documentNo = rs.getString("documentNo"); + switch (recordNo) { + case 1: + assertEquals(salesDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(50.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 2: + assertEquals(salesDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(221.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 3: + assertEquals(salesDocumentNo, documentNo); + assertEquals(60.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 4: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(50.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 5: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(0.00, paymentamt, 0.1); + assertEquals(221.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + case 6: + assertEquals(layawayDocumentNo, documentNo); + assertEquals(60.00, paymentamt, 0.1); + assertEquals(0.00, depositamt, 0.1); + assertEquals(null, reconciliation); + assertEquals("RDNC", status); + break; + } + recordNo++; + } + }.execute(sql, 6); + } + + private void voidLayawayWithOverpayment() { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYS); + write(TestId.FIELD_SEARCH_RECEIPT, layawayDocumentNo); + tap(TestId.BUTTON_LAYAWAYS_SEARCH); + tap(TestId.BUTTON_LAYAWAYS_ROW1); + verify(TestId.LABEL_TOTALTOPAY, "150.50"); + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_VOIDLAYAWAY); + verify(TestId.LABEL_RECEIPT_TYPE, "Void this Layaway"); + tap(TestId.BUTTON_CARD); + write(TestId.INPUT_POINTOFSALE, "60"); + tap(TestId.BUTTON_KEYPAD_ENTER); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_POPUP_TITLE, "Overpayment"); + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } + + private void partialyPaidLayaway() { + layawayDocumentNo = BackboneHelper.getDocumentNo(); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_CASH_50); + verify(TestId.LABEL_RECEIPT_PAYMENT_ROW1_AMOUNT, "50.00"); + isDisabled(TestId.BUTTON_LAYAWAY, false); + tap(TestId.BUTTON_LAYAWAY); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } + + private void createLayaway() { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_LAYAWAYTHISRECEIPT); + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_BESTSELLERS); + tap(TestId.BUTTON_PRODUCT_BESTSELLERS_AVALANCHETRANSCEIVER); + verify(TestId.LABEL_TOTALTOPAY, "150.50"); + } + + private void createSalesWithCard() { + tap(TestId.BUTTON_BROWSE); + tap(TestId.BUTTON_CATEGORY_BACKPACKSANDTRAVEL); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_BABYCARRIER); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_BABYCARRIER); + verify(TestId.LABEL_TOTALTOPAY, "221.00"); + salesDocumentNo = BackboneHelper.getDocumentNo(); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAYMENT_CARD); + tap(TestId.BUTTON_PAY_EXACT); + verify(TestId.LABEL_RECEIPT_PAYMENT_ROW1_AMOUNT, "221.00"); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_RejectQuotations.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_RejectQuotations.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/Synchronized_RejectQuotations.java @@ -0,0 +1,116 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): + ************************************************************************ + * + * @author EBE + * + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.junit.Test; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperSelect; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; + +public class Synchronized_RejectQuotations extends BaseSynchronizedTransactionTest { + + @Test + public void test() { + // create 2 quotations + createQuotation(); + final String documentNo1 = BackboneHelper.getDocumentNo(); + assertThat(documentNo1, containsString("QT")); + tap(TestId.BUTTON_DELETERECEIPT); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // reject quotation 1 + loadQuotation(documentNo1); + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_REJECTQUOTATIONS); + TestId.SELECT_QUOTATIONS_REJECT_REASON.enyoNode().executeExtension(".setSelected(0)"); + verify(TestId.SELECT_QUOTATIONS_REJECT_REASON_OPTION1, "BE8B7D78615D48BFBC27FF1F0C9789C7"); + tap(TestId.BUTTON_QUOTATIONS_REJECT_OK); + verifyRejected(documentNo1, "REJECT_1"); + + createQuotation(); + final String documentNo2 = BackboneHelper.getDocumentNo(); + assertThat(documentNo2, containsString("QT")); + tap(TestId.BUTTON_DELETERECEIPT); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // reject quotation 2 + loadQuotation(documentNo2); + logger.info("Reject quotation 2"); + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_REJECTQUOTATIONS); + TestId.SELECT_QUOTATIONS_REJECT_REASON.enyoNode().executeExtension(".setSelected(1)"); + verify(TestId.SELECT_QUOTATIONS_REJECT_REASON_OPTION2, "7B53AE732A31416E8879F5849F45F7DC"); + tap(TestId.BUTTON_QUOTATIONS_REJECT_OK); + verifyRejected(documentNo2, "REJECT_2"); + setFinishedCorrectly(); + } + + private void createQuotation() { + // create quotation + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CREATEQUOTATION); + + // add a product + tap(TestId.BUTTON_CATEGORY_BACKPACKSANDTRAVEL); + tap(TestId.BUTTON_PRODUCT_BACKPACKSANDTRAVEL_WHISTLE); + isDisabled(TestId.BUTTON_PAY, false); + + // Tap pay + tap(TestId.BUTTON_PAY); + + // Verify Label Under Evaluation + verify(TestId.LABEL_RECEIPT_TYPE, "Quotation - Under Evaluation"); + } + + private void loadQuotation(final String documentNo) { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_QUOTATIONS); + write(TestId.FIELD_SEARCH_RECEIPT, documentNo); + tap(TestId.BUTTON_QUOTATIONS_SEARCH); + tap(TestId.BUTTON_QUOTATIONS_ROW1); + } + + private void verifyRejected(final String documentNo, final String rejectReason) { + final String sql = "SELECT R.value" // + + " FROM C_Order C" // + + " LEFT JOIN C_Reject_Reason R ON C.c_reject_reason_id = R.c_reject_reason_id" // + + " WHERE C.documentno = '" + documentNo + "' AND C.docstatus = 'CJ'"; + new DatabaseHelperSelect() { + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + logger.info("Verifying rejected quotation in the backend"); + final String value = rs.getString("value"); + + assertThat(rejectReason, equalTo(value)); + } + }.execute(sql, 1); + + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestNonSynchronizedSale.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestNonSynchronizedSale.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestNonSynchronizedSale.java @@ -0,0 +1,75 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): ______________________________________. + ************************************************************************ + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import org.openbravo.test.mobile.common.TestClassAnnotations; +import org.openbravo.test.mobile.common.selenium.SeleniumHelper; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperInsertUpdateOrDelete; +import org.openbravo.test.mobile.common.selenium.javascript.SynchronizationHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.terminals.WebPOSTerminalHelper; + +@TestClassAnnotations(isHighVolumeCompatible = true) +public class TestNonSynchronizedSale extends WebPOSTerminalHelper { + + public void before() { + // delete any preference which maybe has been left over from before. + new DatabaseHelperInsertUpdateOrDelete("Remove existing OBMOBC_SynchronizedMode").execute( + "DELETE from AD_Preference WHERE ad_preference_id = 'D19D716CA32F486587FB5100F08D493D'", + DatabaseHelperInsertUpdateOrDelete.UNEXPECTED_AFFECTED_ROWS); + super.before(); + } + + @Test + // @TestAnnotations(waitFixOf = 31655) + public void test() { + final boolean inSynchronizedMode = (Boolean) SeleniumHelper + .executeScriptWithReturn("OB.MobileApp.model.get('permissions').OBMOBC_SynchronizedMode"); + + assertThat("Running in synchronize mode", inSynchronizedMode, equalTo(false)); + + final Long beforeTime2 = (Long) SeleniumHelper + .executeScriptWithReturn("OB.Data.showSynchronizedDialogChangeTime"); + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER); + verify(TestId.LABEL_TOTALTOPAY, "150.50"); + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT); + verify(TestId.LABEL_TOTALTOPAY, "165.00"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + SynchronizationHelper.waitUntiTheApplicationHasSynchronized(); + final Long afterTime2 = (Long) SeleniumHelper + .executeScriptWithReturn("OB.Data.showSynchronizedDialogChangeTime"); + assertThat("Transaction Dialog has appeared, it shouldn't", afterTime2, equalTo(beforeTime2)); + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestSynchronizedSaleWithError.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestSynchronizedSaleWithError.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestSynchronizedSaleWithError.java @@ -0,0 +1,91 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): ______________________________________. + ************************************************************************ + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import org.openbravo.test.mobile.common.TestClassAnnotations; +import org.openbravo.test.mobile.common.selenium.SeleniumHelper; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.SynchronizationHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.testhelpers.WebPOSSnippet; + +@TestClassAnnotations(isHighVolumeCompatible = true) +public class TestSynchronizedSaleWithError extends BaseSynchronizedTransactionTest { + + private String documentNo1; + private String documentNo2; + + @Test + // @TestAnnotations(waitFixOf = 31655) + public void test() { + try { + WebPOSSnippet.cleanCashup(this); + + documentNo1 = BackboneHelper.getDocumentNo(); + + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER); + verify(TestId.LABEL_TOTALTOPAY, "150.50"); + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT); + verify(TestId.LABEL_TOTALTOPAY, "165.00"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + + // force an error in the order loader + SeleniumHelper.executeScript("OB.MobileApp.model.get('terminal').id=undefined"); + + tap(TestId.BUTTON_PAY_DONE); + + verify(TestId.LABEL_TOTALTOPAY, "165.00"); + + documentNo2 = BackboneHelper.getDocumentNo(); + assertThat("Document has been incremented", documentNo1, equalTo(documentNo2)); + + final Long currentCash = (Long) SeleniumHelper + .executeScriptWithReturn("OB.MobileApp.model.paymentnames['OBPOS_payment.cash'].currentCash"); + assertThat("Current cash has been incremented, it shouldn't after an error", currentCash, + equalTo(new Long("0"))); + + final String linesInReceipt = BackboneHelper.getOrderAtributeValue("lines.length"); + assertThat("There should be 2 lines in the receipt", linesInReceipt, equalTo("2")); + + // delete the ticket, to clean it up + tap(TestId.BUTTON_DELETERECEIPT); + tap(TestId.BUTTON_DELETERECEIPT_CONFIRM); + + SynchronizationHelper.waitUntiTheApplicationHasSynchronized(); + setFinishedCorrectly(); + } catch (Throwable e) { + e.printStackTrace(System.err); + throw new RuntimeException(e); + } + } +} diff --git a/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestSynchronizedTransaction.java b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestSynchronizedTransaction.java new file mode 100644 --- /dev/null +++ b/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/system/synchronizedtransactions/TestSynchronizedTransaction.java @@ -0,0 +1,338 @@ +/* + ************************************************************************* + * The contents of this file are subject to the Openbravo Public License + * Version 1.0 (the "License"), being the Mozilla Public License + * Version 1.1 with a permitted attribution clause; you may not use this + * file except in compliance with the License. You may obtain a copy of + * the License at http://www.openbravo.com/legal/license.html + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + * License for the specific language governing rights and limitations + * under the License. + * The Original Code is Openbravo ERP. + * The Initial Developer of the Original Code is Openbravo S.L.U. + * All portions are Copyright (C) 2016 Openbravo S.L.U. + * All Rights Reserved. + * Contributor(s): ______________________________________. + ************************************************************************ + */ + +package org.openbravo.test.mobile.retail.pack.selenium.tests.system.synchronizedtransactions; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.closeTo; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.text.NumberFormat; +import java.util.Locale; +import java.util.Random; + +import org.junit.Test; +import org.openbravo.test.mobile.common.TestClassAnnotations; +import org.openbravo.test.mobile.common.selenium.database.ConnectionHelper; +import org.openbravo.test.mobile.common.selenium.database.DatabaseHelperSelect; +import org.openbravo.test.mobile.common.selenium.database.WebPOSDatabaseConstants; +import org.openbravo.test.mobile.common.selenium.database.WebPOSDatabaseHelper; +import org.openbravo.test.mobile.common.selenium.javascript.BackboneHelper; +import org.openbravo.test.mobile.common.selenium.javascript.SynchronizationHelper; +import org.openbravo.test.mobile.common.selenium.javascript.TestId; +import org.openbravo.test.mobile.common.selenium.testhelpers.WebPOSSnippet; + +@TestClassAnnotations(isHighVolumeCompatible = true) +public class TestSynchronizedTransaction extends BaseSynchronizedTransactionTest { + + @Test + // @TestAnnotations(waitFixOf = 31655) + public void testSale() { + WebPOSSnippet.cleanCashup(this); + + tap(TestId.BUTTON_DELETERECEIPT); + tap(TestId.BUTTON_DELETERECEIPT_CONFIRM); + + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_AVALANCHETRANSCEIVER); + verify(TestId.LABEL_TOTALTOPAY, "150.50"); + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_INSECTREPELLENT); + verify(TestId.LABEL_TOTALTOPAY, "165.00"); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + + waitForSynchronizationToReturn(); + + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + SynchronizationHelper.waitUntiTheApplicationHasSynchronized(); + setFinishedCorrectly(); + } + + @Test + public void testCashup() { + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHUP); + + // step 1 of 4 + verify(TestId.LABEL_CASHUP_STEP2_TITLE, "Step 1 of 4: Count Cash"); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 2 of 4 + verify(TestId.LABEL_CASHUP_STEP3_TITLE, "Step 2 of 4: Count Cash"); + tap(TestId.BUTTON_CASHUP_CARD_OK); + tap(TestId.BUTTON_CASHUP_CASHUSA_OK); + tap(TestId.BUTTON_CASHUP_VOUCHER_OK); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 3 of 4 + // cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // usa cash + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select USA Cash to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + // voucher + verify(TestId.LABEL_CASHUP_STEP4_TITLE, "Step 3 of 4: Select Voucher to keep"); + verify(TestId.LABEL_CASHUP_KEEPNOTHING, "Nothing"); + tap(TestId.BUTTON_CASHUP_KEEPNOTHING); + tap(TestId.BUTTON_CASHUP_NEXT); + + // step 4 of 4 + verify(TestId.LABEL_CASHUP_STEP5_TITLE, "Step 4 of 4: Post, print and close"); + verify(TestId.LABEL_CASHUP_POSTPRINTANDCLOSE, "Post, Print & Close"); + tap(TestId.BUTTON_CASHUP_POSTPRINTANDCLOSE); + + waitForSynchronizationToReturn(); + + // done + verify(TestId.LABEL_POPUP_TITLE, "Good job!"); + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + setFinishedCorrectly(); + } + + @Test + public void testCashManagement() { + final int importCount = WebPOSDatabaseHelper.countProcessedImportEntries(); + + WebPOSSnippet.cleanCashup(this); + + final Random random = new Random(); + final int max = 200; + final int min = 50; + // one way to know if the transaction in the backend will be this one, its being sure that is + // the only one in the fin_finacc_transaction table + final int randomNumber = random.nextInt(max - min) + min; + + tap(TestId.BUTTON_MENU); + tap(TestId.BUTTON_MENU_CASHMANAGEMENT); + verify(TestId.LABEL_CASHMANAGEMENT_TITLE, "Cash Management"); + WebPOSSnippet.tapKeypad(this, randomNumber); + tap(TestId.BUTTON_CASHMANAGEMENT_CASHDEPOSIT); + verify(TestId.LABEL_SELECTDEPOSIT_BACOFFICEVBS, "Backoffice transfer to VBS"); + tap(TestId.BUTTON_SELECTDEPOSIT_BACOFFICEVBS); + verify(TestId.LABEL_CASHMANAGEMENT_ROW1_AMOUNT, + String.format("%s.00", NumberFormat.getNumberInstance(Locale.US).format(randomNumber))); + verify(TestId.LABEL_CASHMANAGEMENT_ROW1_DESCRIPTION, + "Deposit: Cash - Backoffice transfer to VBS"); + tap(TestId.BUTTON_CASHMANAGEMENT_DONE); + verify(TestId.LABEL_POPUP_TITLE, "Done"); + + waitForSynchronizationToReturn(); + + tap(TestId.BUTTON_POPUP_OK); + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // verify that the two transcactions has been made to the backend + logger.info("Verifying that the backend has received the transaction (1/2). Amount = '" + + randomNumber + "'"); + new DatabaseHelperSelect() { + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + final double paymentamt = rs.getDouble("paymentamt"); + final double depositamt = rs.getDouble("depositamt"); + assertThat("Cash deposit transaction was not found in the backend", paymentamt, + closeTo(randomNumber, 10)); + assertThat("Cash deposit transaction was not found in the backend", depositamt, + closeTo(0, 10)); + } + }.execute( + ConnectionHelper.getTOP( + String + .format( + "SELECT paymentamt, depositamt FROM fin_finacc_transaction where fin_financial_account_id='%s' AND description='Cash - Backoffice transfer to VBS' AND paymentamt=%s ORDER BY created DESC", + WebPOSDatabaseConstants.VBS_CASHBOOK_BACKOFFICE_FIN_ACCOUNT_ID, randomNumber), + 1), 1); + + logger.info("Verifying that the backend has received the transaction (2/2). Amount = '" + + randomNumber + "'"); + new DatabaseHelperSelect() { + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + final double paymentamt = rs.getDouble("paymentamt"); + final double depositamt = rs.getDouble("depositamt"); + assertThat("Cash deposit transaction was not found in the backend", paymentamt, + closeTo(0, 10)); + assertThat("Cash deposit transaction was not found in the backend", depositamt, + closeTo(randomNumber, 10)); + } + }.execute( + ConnectionHelper.getTOP( + String + .format( + "SELECT paymentamt, depositamt FROM fin_finacc_transaction where fin_financial_account_id='%s' AND description='Cash - Backoffice transfer to VBS' AND depositamt=%s ORDER BY created DESC", + WebPOSDatabaseConstants.VBS1001_CASHBOOK_STORE_CASH_FIN_ACCOUNT_ID, + randomNumber), 1), 1); + + WebPOSDatabaseHelper.verifyProcessedImportEntries(importCount + 6); + setFinishedCorrectly(); + } + + @Test + public void testCustomerCreationSimple() { + tap(TestId.BUTTON_RECEIPT_CUSTOMER); + tap(TestId.BUTTON_CUSTOMER_NEW); + write(TestId.FIELD_CUSTOMER_NAME, "John"); + write(TestId.FIELD_CUSTOMER_LASTNAME, "Doe"); + write(TestId.FIELD_CUSTOMER_ADDRES, "St Johns Wood road, 32"); + tap(TestId.BUTTON_CUSTOMER_SAVE); + + waitForSynchronizationToReturn(); + + tap(TestId.BUTTON_CUSTOMER_ASSIGNTOCUSTOMER); + setFinishedCorrectly(); + } + + @Test + public void testCustomerCreationComplex() { + // https://issues.openbravo.com/view.php?id=31206 + for (int i = 0; i < 5; i++) { + final String customerName = "John" + System.currentTimeMillis(); + final String lastName = "Doe"; + final String addressName = "My Address " + System.currentTimeMillis(); + tap(TestId.BUTTON_RECEIPT_CUSTOMER); + tap(TestId.BUTTON_CUSTOMER_NEW); + write(TestId.FIELD_CUSTOMER_NAME, customerName); + write(TestId.FIELD_CUSTOMER_LASTNAME, lastName); + write(TestId.FIELD_CUSTOMER_ADDRES, addressName); + tap(TestId.BUTTON_CUSTOMER_SAVE); + + waitForSynchronizationToReturn(); + + tap(TestId.BUTTON_CUSTOMER_ASSIGNTOCUSTOMER); + } + + final String customerName = "John" + System.currentTimeMillis(); + final String lastName = "Doe"; + final String expectedBPName = customerName + " " + lastName; + final String addressName = "My Address " + System.currentTimeMillis(); + tap(TestId.BUTTON_RECEIPT_CUSTOMER); + tap(TestId.BUTTON_CUSTOMER_NEW); + write(TestId.FIELD_CUSTOMER_NAME, customerName); + write(TestId.FIELD_CUSTOMER_LASTNAME, lastName); + write(TestId.FIELD_CUSTOMER_ADDRES, addressName); + tap(TestId.BUTTON_CUSTOMER_SAVE); + + waitForSynchronizationToReturn(); + + tap(TestId.BUTTON_CUSTOMER_ASSIGNTOCUSTOMER); + + tap(TestId.BUTTON_SEARCH); + write(TestId.FIELD_SEARCH_TEXT, TestId.BUTTON_SEARCHPRODUCT_ADHESIVEBODYWARNMERS.getRowName()); + tap(TestId.BUTTON_SEARCH_EXECUTE); + verifyHgvolTime(TestId.BUTTON_SEARCH_EXECUTE, 10000); + tap(TestId.BUTTON_SEARCHPRODUCT_ADHESIVEBODYWARNMERS); + + verify(TestId.LABEL_TOTALTOPAY, "3.60"); + tap(TestId.BUTTON_SCAN); + // 'Basecamp lantern' 772EE3421FE84D768A674840C2EB855B + write(TestId.INPUT_POINTOFSALE, "0000001688191"); + tap(TestId.BUTTON_KEYPAD_ENTER); + verify(TestId.LABEL_TOTALTOPAY, "59.10"); + + final String receiptNo = BackboneHelper.getDocumentNo(); + tap(TestId.BUTTON_PAY); + tap(TestId.BUTTON_PAY_EXACT); + tap(TestId.BUTTON_PAY_DONE); + + waitForSynchronizationToReturn(); + + verify(TestId.LABEL_TOTALTOPAY, "0.00"); + + // check bp + final String bpSql = "SELECT name FROM c_bpartner WHERE c_bpartner_id IN (SELECT c_bpartner_id FROM c_order WHERE documentno = '" + + receiptNo + "')"; + new DatabaseHelperSelect() { + + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + final String foundName = rs.getString("name"); + + logger.info(String.format("Verifying that the database record %s is the expected %s", + foundName, customerName)); + assertThat("The bp name is not the expected", foundName, equalTo(expectedBPName)); + } + }.execute(bpSql, 1); + + // check address + final String bpLocationSql = "SELECT name FROM c_bpartner_location WHERE c_bpartner_location_id IN (SELECT c_bpartner_location_id FROM c_order WHERE documentno = '" + + receiptNo + "')"; + new DatabaseHelperSelect() { + + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + final String foundName = rs.getString("name"); + + logger.info(String.format("Verifying that the database record %s is the expected %s", + foundName, customerName)); + assertThat("The address name is not the expected", foundName, equalTo(addressName)); + } + }.execute(bpLocationSql, 1); + + // check products + final String sql = "SELECT m_product_id, name FROM m_product WHERE m_product_id IN (SELECT m_product_id FROM c_orderline WHERE c_order_id IN (SELECT c_order_id FROM c_order WHERE documentno = '" + + receiptNo + "')) ORDER BY name"; + new DatabaseHelperSelect() { + int count = 0; + + @Override + protected void yieldResultSet(final ResultSet rs) throws SQLException { + count++; + final String productId = rs.getString("m_product_id"); + final String productName = rs.getString("name"); + + logger.info(String.format( + "Verifying that the database record (%s) '%s' is one of the expected", productId, + productName)); + switch (count) { + case 1: + assertThat("The product name is not one of the expected", productName, + equalTo("Adhesive body warmers")); + assertThat("The 'productId' is not one of the expected", productId, + equalTo("AC79520FEB4743B3AAA379BF70B9B7DA")); + break; + case 2: + assertThat("The product name is not one of the expected", productName, + equalTo("Basecamp lantern")); + assertThat("The 'productId' is not one of the expected", productId, + equalTo("772EE3421FE84D768A674840C2EB855B")); + break; + default: + throw new IllegalArgumentException("The returned resulset is missing the assertions"); + } + } + }.execute(sql, 2); + setFinishedCorrectly(); + } + +} 1505-core.diff [^] (64,585 bytes) 2016-05-15 16:48 [Show Content] [Hide Content] diff --git a/src-db/database/sourcedata/AD_MESSAGE.xml b/src-db/database/sourcedata/AD_MESSAGE.xml --- a/src-db/database/sourcedata/AD_MESSAGE.xml +++ b/src-db/database/sourcedata/AD_MESSAGE.xml @@ -447,6 +447,18 @@ <!--4125E049FC3942C39597DA7AAE82FC8C--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> <!--4125E049FC3942C39597DA7AAE82FC8C--></AD_MESSAGE> +<!--441A964522074E10BA95E9417DF83455--><AD_MESSAGE> +<!--441A964522074E10BA95E9417DF83455--> <AD_MESSAGE_ID><![CDATA[441A964522074E10BA95E9417DF83455]]></AD_MESSAGE_ID> +<!--441A964522074E10BA95E9417DF83455--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--441A964522074E10BA95E9417DF83455--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--441A964522074E10BA95E9417DF83455--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--441A964522074E10BA95E9417DF83455--> <VALUE><![CDATA[OBMOBC_TransactionFailedTitle]]></VALUE> +<!--441A964522074E10BA95E9417DF83455--> <MSGTEXT><![CDATA[Transaction Failed]]></MSGTEXT> +<!--441A964522074E10BA95E9417DF83455--> <MSGTYPE><![CDATA[I]]></MSGTYPE> +<!--441A964522074E10BA95E9417DF83455--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--441A964522074E10BA95E9417DF83455--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> +<!--441A964522074E10BA95E9417DF83455--></AD_MESSAGE> + <!--44E2FBBC2D3C4B43B4A28D993C743297--><AD_MESSAGE> <!--44E2FBBC2D3C4B43B4A28D993C743297--> <AD_MESSAGE_ID><![CDATA[44E2FBBC2D3C4B43B4A28D993C743297]]></AD_MESSAGE_ID> <!--44E2FBBC2D3C4B43B4A28D993C743297--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> @@ -663,6 +675,18 @@ <!--5DB7BD0ABD15432FB907215C3A16D2BF--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> <!--5DB7BD0ABD15432FB907215C3A16D2BF--></AD_MESSAGE> +<!--60099D85E7F743C9888C79501C2B2689--><AD_MESSAGE> +<!--60099D85E7F743C9888C79501C2B2689--> <AD_MESSAGE_ID><![CDATA[60099D85E7F743C9888C79501C2B2689]]></AD_MESSAGE_ID> +<!--60099D85E7F743C9888C79501C2B2689--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--60099D85E7F743C9888C79501C2B2689--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--60099D85E7F743C9888C79501C2B2689--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--60099D85E7F743C9888C79501C2B2689--> <VALUE><![CDATA[OBMOBC_TransactionFailed]]></VALUE> +<!--60099D85E7F743C9888C79501C2B2689--> <MSGTEXT><![CDATA[The transaction failed on the server, change your input or try again. Detailed error message: %0]]></MSGTEXT> +<!--60099D85E7F743C9888C79501C2B2689--> <MSGTYPE><![CDATA[I]]></MSGTYPE> +<!--60099D85E7F743C9888C79501C2B2689--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--60099D85E7F743C9888C79501C2B2689--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> +<!--60099D85E7F743C9888C79501C2B2689--></AD_MESSAGE> + <!--609E83AFE22040819F66D76230246225--><AD_MESSAGE> <!--609E83AFE22040819F66D76230246225--> <AD_MESSAGE_ID><![CDATA[609E83AFE22040819F66D76230246225]]></AD_MESSAGE_ID> <!--609E83AFE22040819F66D76230246225--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> @@ -1047,6 +1071,18 @@ <!--9925F9856B92417CA4119158FDA68B12--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> <!--9925F9856B92417CA4119158FDA68B12--></AD_MESSAGE> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--><AD_MESSAGE> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <AD_MESSAGE_ID><![CDATA[9C0ACBDEB67E4C9582BDA8BEC7C8BC50]]></AD_MESSAGE_ID> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <VALUE><![CDATA[OBMOBC_ProcessingTransaction]]></VALUE> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <MSGTEXT><![CDATA[Your transaction is being processed on the server.]]></MSGTEXT> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <MSGTYPE><![CDATA[I]]></MSGTYPE> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> +<!--9C0ACBDEB67E4C9582BDA8BEC7C8BC50--></AD_MESSAGE> + <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--><AD_MESSAGE> <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--> <AD_MESSAGE_ID><![CDATA[9C1E55F357A14DCCAECA6A0A2CCB62FA]]></AD_MESSAGE_ID> <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> @@ -1059,6 +1095,18 @@ <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> <!--9C1E55F357A14DCCAECA6A0A2CCB62FA--></AD_MESSAGE> +<!--9C3E5839CE344A16A8B1F9D119BDC116--><AD_MESSAGE> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <AD_MESSAGE_ID><![CDATA[9C3E5839CE344A16A8B1F9D119BDC116]]></AD_MESSAGE_ID> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <VALUE><![CDATA[OBMOBC_ProcessingTransactionTitle]]></VALUE> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <MSGTEXT><![CDATA[Processing Transaction]]></MSGTEXT> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <MSGTYPE><![CDATA[I]]></MSGTYPE> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--9C3E5839CE344A16A8B1F9D119BDC116--> <ISINCLUDEINI18N><![CDATA[N]]></ISINCLUDEINI18N> +<!--9C3E5839CE344A16A8B1F9D119BDC116--></AD_MESSAGE> + <!--9D1EB89366C2466F9E06097F98BB9DDD--><AD_MESSAGE> <!--9D1EB89366C2466F9E06097F98BB9DDD--> <AD_MESSAGE_ID><![CDATA[9D1EB89366C2466F9E06097F98BB9DDD]]></AD_MESSAGE_ID> <!--9D1EB89366C2466F9E06097F98BB9DDD--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> diff --git a/src-db/database/sourcedata/AD_REF_LIST.xml b/src-db/database/sourcedata/AD_REF_LIST.xml --- a/src-db/database/sourcedata/AD_REF_LIST.xml +++ b/src-db/database/sourcedata/AD_REF_LIST.xml @@ -187,6 +187,18 @@ <!--80AB4F4D0FBE4352BF331C2F4467F819--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> <!--80AB4F4D0FBE4352BF331C2F4467F819--></AD_REF_LIST> +<!--86A147DD51D041729DDD7EFD12C54B1C--><AD_REF_LIST> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <AD_REF_LIST_ID><![CDATA[86A147DD51D041729DDD7EFD12C54B1C]]></AD_REF_LIST_ID> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <VALUE><![CDATA[OBMOBC_SynchronizedData]]></VALUE> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <NAME><![CDATA[Synchronized Data]]></NAME> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <DESCRIPTION><![CDATA[Common message containing several actions which are to be executed synchronized]]></DESCRIPTION> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <AD_REFERENCE_ID><![CDATA[11F86B630ECB4A57B28927193F8AB99D]]></AD_REFERENCE_ID> +<!--86A147DD51D041729DDD7EFD12C54B1C--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--86A147DD51D041729DDD7EFD12C54B1C--></AD_REF_LIST> + <!--92882D283E614160A1BEE6DB99A354BE--><AD_REF_LIST> <!--92882D283E614160A1BEE6DB99A354BE--> <AD_REF_LIST_ID><![CDATA[92882D283E614160A1BEE6DB99A354BE]]></AD_REF_LIST_ID> <!--92882D283E614160A1BEE6DB99A354BE--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> @@ -316,6 +328,18 @@ <!--D7110BA3D93D4EC693E27F867B196A24--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> <!--D7110BA3D93D4EC693E27F867B196A24--></AD_REF_LIST> +<!--E279FC43FF7540A9881519B81C15E8C4--><AD_REF_LIST> +<!--E279FC43FF7540A9881519B81C15E8C4--> <AD_REF_LIST_ID><![CDATA[E279FC43FF7540A9881519B81C15E8C4]]></AD_REF_LIST_ID> +<!--E279FC43FF7540A9881519B81C15E8C4--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--E279FC43FF7540A9881519B81C15E8C4--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--E279FC43FF7540A9881519B81C15E8C4--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--E279FC43FF7540A9881519B81C15E8C4--> <VALUE><![CDATA[OBMOBC_SynchronizedMode]]></VALUE> +<!--E279FC43FF7540A9881519B81C15E8C4--> <NAME><![CDATA[WebPOS Synchronized Mode]]></NAME> +<!--E279FC43FF7540A9881519B81C15E8C4--> <DESCRIPTION><![CDATA[Determines if webpos is run in synchronized mode]]></DESCRIPTION> +<!--E279FC43FF7540A9881519B81C15E8C4--> <AD_REFERENCE_ID><![CDATA[A26BA480E2014707B47257024C3CBFF7]]></AD_REFERENCE_ID> +<!--E279FC43FF7540A9881519B81C15E8C4--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--E279FC43FF7540A9881519B81C15E8C4--></AD_REF_LIST> + <!--E2E70AA926FA43EFB24014784724AA88--><AD_REF_LIST> <!--E2E70AA926FA43EFB24014784724AA88--> <AD_REF_LIST_ID><![CDATA[E2E70AA926FA43EFB24014784724AA88]]></AD_REF_LIST_ID> <!--E2E70AA926FA43EFB24014784724AA88--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> diff --git a/src-db/database/sourcedata/OBMOBC_SERVICES.xml b/src-db/database/sourcedata/OBMOBC_SERVICES.xml --- a/src-db/database/sourcedata/OBMOBC_SERVICES.xml +++ b/src-db/database/sourcedata/OBMOBC_SERVICES.xml @@ -1,5 +1,16 @@ <?xml version='1.0' encoding='UTF-8'?> <data> +<!--0C097F5EE22249758CA26F8CDF4C61F9--><OBMOBC_SERVICES> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <OBMOBC_SERVICES_ID><![CDATA[0C097F5EE22249758CA26F8CDF4C61F9]]></OBMOBC_SERVICES_ID> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <AD_ORG_ID><![CDATA[0]]></AD_ORG_ID> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <AD_MODULE_ID><![CDATA[08943B85ADF64E708797A753E5B6AAEE]]></AD_MODULE_ID> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <ISACTIVE><![CDATA[Y]]></ISACTIVE> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <SERVICE><![CDATA[org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller]]></SERVICE> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <DESCRIPTION><![CDATA[Is used as a fail over request for synchronized mode combining several requests in one call]]></DESCRIPTION> +<!--0C097F5EE22249758CA26F8CDF4C61F9--> <ROUTINGTYPE><![CDATA[Failover]]></ROUTINGTYPE> +<!--0C097F5EE22249758CA26F8CDF4C61F9--></OBMOBC_SERVICES> + <!--35BC4C9BE6624E76AE57395FD8AF11E4--><OBMOBC_SERVICES> <!--35BC4C9BE6624E76AE57395FD8AF11E4--> <OBMOBC_SERVICES_ID><![CDATA[35BC4C9BE6624E76AE57395FD8AF11E4]]></OBMOBC_SERVICES_ID> <!--35BC4C9BE6624E76AE57395FD8AF11E4--> <AD_CLIENT_ID><![CDATA[0]]></AD_CLIENT_ID> diff --git a/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java b/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java --- a/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java +++ b/src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java @@ -37,6 +37,8 @@ import org.openbravo.dal.core.TriggerHandler; import org.openbravo.dal.service.OBDal; import org.openbravo.dal.service.OBQuery; +import org.openbravo.mobile.core.utils.OBMOBCUtils; +import org.openbravo.service.db.DbUtility; import org.openbravo.service.importprocess.ImportEntryManager; import org.openbravo.service.importprocess.ImportProcessUtils; import org.openbravo.service.json.JsonConstants; @@ -204,8 +206,10 @@ } if (i % 1 == 0) { OBDal.getInstance().flush(); - OBDal.getInstance().getConnection(false).commit(); - OBDal.getInstance().getSession().clear(); + if (!isRunInSynchronizedMode()) { + OBDal.getInstance().getConnection(false).commit(); + OBDal.getInstance().getSession().clear(); + } } log.debug("Total process " + this.getClass().getName() + " time: " + (System.currentTimeMillis() - t1)); @@ -218,6 +222,14 @@ error = true; } + // in synched mode return the error to the caller + // don't do anything more + if (isRunInSynchronizedMode()) { + Throwable localThrowable = DbUtility.getUnderlyingSQLException(t); + log.error(localThrowable.getMessage(), localThrowable); + return OBMOBCUtils.createSimpleErrorJson(localThrowable.getMessage()); + } + // check if there is a record with the same id. If it exists it means that it is a // duplicated record. Then, this error will not be stored List<Object> parameters = new ArrayList<Object>(); diff --git a/src/org/openbravo/mobile/core/process/MobileService.java b/src/org/openbravo/mobile/core/process/MobileService.java --- a/src/org/openbravo/mobile/core/process/MobileService.java +++ b/src/org/openbravo/mobile/core/process/MobileService.java @@ -15,14 +15,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.util.AnnotationLiteral; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -33,7 +26,6 @@ import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; -import org.openbravo.base.session.OBPropertiesProvider; import org.openbravo.base.weld.WeldUtils; import org.openbravo.service.json.JsonUtils; import org.openbravo.service.web.InvalidRequestException; @@ -51,12 +43,8 @@ private static String SERVLET_PATH = "org.openbravo.mobile.core.service.jsonrest"; - private boolean bypassImportEntry = false; - public void init(ServletConfig config) { super.init(config); - bypassImportEntry = OBPropertiesProvider.getInstance().getBooleanProperty( - "import.bypass.entry.logic"); } @Override @@ -98,7 +86,7 @@ // writer final Writer w = new StringWriter(); w.write("{\"response\":{"); - execServiceName(w, pathparts[1], (JSONObject) jsonsent); + new MobileServiceProcessor().execServiceName(w, pathparts[1], (JSONObject) jsonsent); w.write("}}"); w.close(); @@ -163,7 +151,7 @@ if (jsonsent.has("className")) { try { - execServiceName(w, jsonsent.getString("className"), jsonsent); + new MobileServiceProcessor().execServiceName(w, jsonsent.getString("className"), jsonsent); } catch (JSONException e) { JSONRowConverter.addJSONExceptionFields(w, e); } catch (ClassNotFoundException e) { @@ -178,128 +166,6 @@ } /** - * Executes the JSONProcess implementing the serviceName. The JSONProcesses are sorted by priority - * and each one can define if it is needed to call the next JSONProcess or not. The response - * writer is filled with the result of the last executed JSONProcess. Each JSONProcess can - * determine if the next class has to be executed. - * - * @param w - * Writer where the result is stored. - * @param serviceName - * the name of the Mobile Service to execute. - * @param jsonsent - * JSONObject with the Mobile Service input parameters. - * - */ - private void execServiceName(Writer w, String serviceName, JSONObject jsonsent) throws Exception { - List<? extends JSONProcess> processes = getServiceClassInstances(serviceName); - // Create a new writer for each process. Only write on the given writer the last execution - // result. - Writer tmpwriter = null; - int i = 0; - for (JSONProcess process : processes) { - i++; - tmpwriter = new StringWriter(); - try { - execProcess(tmpwriter, process, jsonsent); - } catch (Exception e) { - if (processes.size() == i - || (process instanceof SecuredJSONProcess && !((SecuredJSONProcess) process) - .executeNextServiceClassOnFailure())) { - tmpwriter.close(); - throw e; - } - } - tmpwriter.close(); - if (!(process instanceof SecuredJSONProcess && ((SecuredJSONProcess) process) - .executeNextServiceClass())) { - break; - } - } - if (tmpwriter != null) { - w.write(tmpwriter.toString()); - } - } - - /** - * Executes a JSONProcess with the data sent in the JSONObject. - * - * @param w - * Writer where the result is stored. - * @param process - * JSONProcess to execute. - * @param jsonsent - * JSONObject with the process input parameters. - */ - private void execProcess(Writer w, JSONProcess process, JSONObject jsonsent) throws IOException, - ServletException { - - if (process instanceof SecuredJSONProcess) { - if (!bypassImportEntry && process instanceof DataSynchronizationImportProcess) { - ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent); - } else { - ((SecuredJSONProcess) process).secureExec(w, jsonsent); - } - } else { - log.warn("Executing unsecure process " + process.getClass()); - if (process instanceof DataSynchronizationImportProcess) { - ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent); - } else { - process.exec(w, jsonsent); - } - } - } - - /** - * Builds a sorted List of instances that implement the serviceName. The implementation is done - * using the MobileServiceClassSelector. To ensure backwards compatibility in case that exists a - * class with the same name than the service name and that it does not implement the - * MobileServiceClassSelector it is also added to the List. - * - * @param serviceName - * The Mobile Service name that is going to be executed. - * @return The sorted list of classes implementing the Mobile Service. - * @throws ClassNotFoundException - * Exception thrown when no class implementing the service name is found. - */ - private List<? extends JSONProcess> getServiceClassInstances(String serviceName) - throws ClassNotFoundException { - BeanManager bm = WeldUtils.getStaticInstanceBeanManager(); - List<JSONProcess> processes = new ArrayList<JSONProcess>(); - boolean isDefaultClassMissing = true; - Set<Bean<?>> beans = bm.getBeans(JSONProcess.class, WeldUtils.ANY_LITERAL, - new MobileServiceClassSelector(serviceName)); - for (Bean<?> bean : beans) { - processes.add((JSONProcess) bm.getReference(bean, JSONProcess.class, - bm.createCreationalContext(bean))); - if (bean.getBeanClass().getName().equals(serviceName)) { - isDefaultClassMissing = false; - } - } - // If no bean with classname like the service name is added try to add to the list. This is - // added for backwards compatibility to include service classes that are not implementing the - // qualifier. - try { - if (isDefaultClassMissing) { - @SuppressWarnings("unchecked") - Class<JSONProcess> process = (Class<JSONProcess>) Class.forName(serviceName); - JSONProcess proc = WeldUtils.getInstanceFromStaticBeanManager(process); - - processes.add(proc); - } - } catch (ClassNotFoundException ignore) { - // Only throw ClassNotFoundException if no JSONProcess is found implementing the service name. - } - - if (processes.isEmpty()) { - throw new ClassNotFoundException(); - } - Collections.sort(processes, new ServiceProcessComparator()); - - return processes; - } - - /** * Executes the Procedure set in the jsonsent JSONObject. * * @param w @@ -340,21 +206,6 @@ return pathParts; } - private static class ServiceProcessComparator implements Comparator<JSONProcess> { - private int getProcessPriority(JSONProcess proc) { - if (proc instanceof SecuredJSONProcess) { - return ((SecuredJSONProcess) proc).getPriority(); - } - return 100; - } - - @Override - public int compare(JSONProcess proc1, JSONProcess proc2) { - return getProcessPriority(proc1) - getProcessPriority(proc2); - } - - } - @javax.inject.Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE }) diff --git a/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java b/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java new file mode 100644 --- /dev/null +++ b/src/org/openbravo/mobile/core/process/MobileServiceProcessor.java @@ -0,0 +1,199 @@ +/* + ************************************************************************************ + * Copyright (C) 2016 Openbravo S.L.U. + * Licensed under the Openbravo Commercial License version 1.0 + * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html + * or in the legal folder of this module distribution. + ************************************************************************************ + */ +package org.openbravo.mobile.core.process; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; + +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.servlet.ServletException; + +import org.apache.log4j.Logger; +import org.codehaus.jettison.json.JSONObject; +import org.openbravo.base.session.OBPropertiesProvider; +import org.openbravo.base.weld.WeldUtils; + +/** + * A class which finds the implementation for a service and executes it. + * + * @author mtaal + */ +public class MobileServiceProcessor { + + private static final Logger log = Logger.getLogger(MobileServiceProcessor.class); + + private boolean bypassImportEntry; + private boolean synchronizedMode; + + public boolean isSynchronizedMode() { + return synchronizedMode; + } + + public void setSynchronizedMode(boolean synchronizedMode) { + this.synchronizedMode = synchronizedMode; + } + + public MobileServiceProcessor() { + bypassImportEntry = OBPropertiesProvider.getInstance().getBooleanProperty( + "import.bypass.entry.logic"); + } + + /** + * Executes the JSONProcess implementing the serviceName. The JSONProcesses are sorted by priority + * and each one can define if it is needed to call the next JSONProcess or not. The response + * writer is filled with the result of the last executed JSONProcess. Each JSONProcess can + * determine if the next class has to be executed. + * + * @param w + * Writer where the result is stored. + * @param serviceName + * the name of the Mobile Service to execute. + * @param jsonsent + * JSONObject with the Mobile Service input parameters. + * + */ + public void execServiceName(Writer w, String serviceName, JSONObject jsonsent) throws Exception { + List<? extends JSONProcess> processes = getServiceClassInstances(serviceName); + + // Create a new writer for each process. Only write on the given writer the last execution + // result. + Writer tmpwriter = null; + int i = 0; + for (JSONProcess process : processes) { + i++; + tmpwriter = new StringWriter(); + try { + execProcess(tmpwriter, process, jsonsent); + } catch (Exception e) { + if (processes.size() == i + || (process instanceof SecuredJSONProcess && !((SecuredJSONProcess) process) + .executeNextServiceClassOnFailure())) { + tmpwriter.close(); + throw e; + } + } + tmpwriter.close(); + if (!(process instanceof SecuredJSONProcess && ((SecuredJSONProcess) process) + .executeNextServiceClass())) { + break; + } + } + if (tmpwriter != null) { + w.write(tmpwriter.toString()); + } + } + + /** + * Executes a JSONProcess with the data sent in the JSONObject. + * + * @param w + * Writer where the result is stored. + * @param process + * JSONProcess to execute. + * @param jsonsent + * JSONObject with the process input parameters. + */ + private void execProcess(Writer w, JSONProcess process, JSONObject jsonsent) throws IOException, + ServletException { + + if (process instanceof SecuredJSONProcess) { + if (!synchronizedMode && !bypassImportEntry + && process instanceof DataSynchronizationImportProcess) { + ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent); + } else { + ((SecuredJSONProcess) process).secureExec(w, jsonsent); + } + } else { + log.warn("Executing unsecure process " + process.getClass()); + if (!synchronizedMode && process instanceof DataSynchronizationImportProcess) { + ((DataSynchronizationImportProcess) process).executeCreateImportEntry(w, jsonsent); + } else { + process.exec(w, jsonsent); + } + } + } + + /** + * Builds a sorted List of instances that implement the serviceName. The implementation is done + * using the MobileServiceClassSelector. To ensure backwards compatibility in case that exists a + * class with the same name than the service name and that it does not implement the + * MobileServiceClassSelector it is also added to the List. + * + * @param serviceName + * The Mobile Service name that is going to be executed. + * @return The sorted list of classes implementing the Mobile Service. + * @throws ClassNotFoundException + * Exception thrown when no class implementing the service name is found. + */ + private List<? extends JSONProcess> getServiceClassInstances(String serviceName) + throws ClassNotFoundException { + BeanManager bm = WeldUtils.getStaticInstanceBeanManager(); + List<JSONProcess> processes = new ArrayList<JSONProcess>(); + boolean isDefaultClassMissing = true; + Set<Bean<?>> beans = bm.getBeans(JSONProcess.class, WeldUtils.ANY_LITERAL, + new MobileService.MobileServiceClassSelector(serviceName)); + for (Bean<?> bean : beans) { + processes.add((JSONProcess) bm.getReference(bean, JSONProcess.class, + bm.createCreationalContext(bean))); + if (bean.getBeanClass().getName().equals(serviceName)) { + isDefaultClassMissing = false; + } + } + // If no bean with classname like the service name is added try to add to the list. This is + // added for backwards compatibility to include service classes that are not implementing the + // qualifier. + try { + if (isDefaultClassMissing) { + @SuppressWarnings("unchecked") + Class<JSONProcess> process = (Class<JSONProcess>) Class.forName(serviceName); + JSONProcess proc = WeldUtils.getInstanceFromStaticBeanManager(process); + + processes.add(proc); + } + } catch (ClassNotFoundException ignore) { + // Only throw ClassNotFoundException if no JSONProcess is found implementing the service name. + } + + if (processes.isEmpty()) { + throw new ClassNotFoundException(); + } + Collections.sort(processes, new ServiceProcessComparator()); + + // set synchronized mode + for (JSONProcess proc : processes) { + if (proc instanceof JSONProcessSimple) { + ((JSONProcessSimple) proc).setRunInSynchronizedMode(synchronizedMode); + } + } + + return processes; + } + + private static class ServiceProcessComparator implements Comparator<JSONProcess> { + private int getProcessPriority(JSONProcess proc) { + if (proc instanceof SecuredJSONProcess) { + return ((SecuredJSONProcess) proc).getPriority(); + } + return 100; + } + + @Override + public int compare(JSONProcess proc1, JSONProcess proc2) { + return getProcessPriority(proc1) - getProcessPriority(proc2); + } + + } +} diff --git a/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java b/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java --- a/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java +++ b/src/org/openbravo/mobile/core/process/SecuredJSONProcess.java @@ -33,6 +33,16 @@ private final String secureKey = "SECURE_JSON" + this.getClass().getName(); + private boolean runInSynchronizedMode = false; + + public boolean isRunInSynchronizedMode() { + return runInSynchronizedMode; + } + + public void setRunInSynchronizedMode(boolean runInSynchronizedMode) { + this.runInSynchronizedMode = runInSynchronizedMode; + } + @Override public abstract void exec(Writer w, JSONObject jsonsent) throws IOException, ServletException; diff --git a/src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java b/src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java new file mode 100644 --- /dev/null +++ b/src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java @@ -0,0 +1,184 @@ +/* + ************************************************************************************ + * Copyright (C) 2016 Openbravo S.L.U. + * Licensed under the Openbravo Commercial License version 1.0 + * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html + * or in the legal folder of this module distribution. + ************************************************************************************ + */ +package org.openbravo.mobile.core.servercontroller; + +import java.io.StringWriter; +import java.io.Writer; + +import javax.enterprise.context.ApplicationScoped; + +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.hibernate.Query; +import org.openbravo.base.exception.OBException; +import org.openbravo.base.weld.WeldUtils; +import org.openbravo.dal.core.DalUtil; +import org.openbravo.dal.core.OBContext; +import org.openbravo.dal.service.OBDal; +import org.openbravo.mobile.core.process.JSONProcessSimple; +import org.openbravo.mobile.core.process.MobileImportEntryProcessorRunnable; +import org.openbravo.mobile.core.process.MobileServiceProcessor; +import org.openbravo.service.importprocess.ImportEntry; +import org.openbravo.service.importprocess.ImportEntryManager.ImportEntryQualifier; +import org.openbravo.service.importprocess.ImportEntryProcessor; +import org.openbravo.service.json.JsonConstants; + +/** + * Handler which receives a json which calls other json processes in order and does one commit at + * the end. Exceptions are returned directly to the client. + * + * The class has a main flow logic which calls central server or processes locally depending on + * being online or offline or being store or central server. + * + * For more information see these wiki pages: + * http://wiki.openbravo.com/wiki/Multi-Server_Process_Calls_Concept + * http://wiki.openbravo.com/wiki/Retail:Store_Server#Synchronized_Transactions + * + * @author mtaal + */ +public class SynchronizedServerProcessCaller extends MultiServerJSONProcess { + + public static final String SYNCHRONIZED_DATA_TYPE = "OBMOBC_SynchronizedData"; + + @Override + protected String getImportEntryDataType() { + return SYNCHRONIZED_DATA_TYPE; + } + + protected boolean executeFirstInCentral(JSONObject json) throws JSONException { + return true; + } + + protected JSONObject execute(JSONObject jsonSent) { + try { + final MobileServiceProcessor processor = new MobileServiceProcessor(); + processor.setSynchronizedMode(true); + + final Writer w = new StringWriter(); + w.write("{\"result\":["); + final JSONArray data = jsonSent.getJSONArray("data"); + for (int i = 0; i < data.length(); i++) { + final JSONObject content = data.getJSONObject(i); + final String serviceName = content.getString("_serviceName"); + if (i > 0) { + w.write(","); + } + + final StringWriter localWriter = new StringWriter(); + localWriter.write("{"); + localWriter.write("\"_serviceName\": \"" + serviceName + "\","); + processor.execServiceName(localWriter, serviceName, content); + + localWriter.write("}"); + final JSONObject checkResult = new JSONObject(localWriter.toString()); + // if error then return it + if (isErrorJson(checkResult)) { + return checkResult; + } + w.write(localWriter.toString()); + } + w.write("]"); + w.write("}"); + w.close(); + + final JSONObject result = new JSONObject(w.toString()); + // important to put the same message id in the return! + // this so that symmetric ds can detect that the message + // has already been replicated/created + result.put("messageId", jsonSent.getString("messageId")); + // note: this is mobile core, posterminal is a strange one + // to have here, to solve one day + if (jsonSent.has("posTerminal")) { + result.put("posTerminal", jsonSent.getString("posTerminal")); + } + result.put("source", + (MobileServerController.getInstance().isThisACentralServer() ? SOURCE_CENTRAL + : SOURCE_STORE)); + result.put(JsonConstants.RESPONSE_STATUS, JsonConstants.RPCREQUEST_STATUS_SUCCESS); + + return result; + } catch (Exception e) { + throw new OBException(e); + } + } + + @ImportEntryQualifier(entity = SYNCHRONIZED_DATA_TYPE) + @ApplicationScoped + public static class SynchronizedProcessImportEntryProcessor extends ImportEntryProcessor { + + protected ImportEntryProcessRunnable createImportEntryProcessRunnable() { + return WeldUtils.getInstanceFromStaticBeanManager(SynchronizedProcessRunnable.class); + } + + protected boolean canHandleImportEntry(ImportEntry importEntryInformation) { + return SYNCHRONIZED_DATA_TYPE.equals(importEntryInformation.getTypeofdata()); + } + + protected String getProcessSelectionKey(ImportEntry importEntry) { + return (String) DalUtil.getId(importEntry.getOrganization()); + } + } + + private static class SynchronizedProcessRunnable extends MobileImportEntryProcessorRunnable { + protected Class<? extends JSONProcessSimple> getJSONProcessorClass() { + return SynchronizedServerProcessCaller.class; + } + + protected void processEntry(ImportEntry importEntry) throws Exception { + // check that there are no other import entries for the terminal + // which have not yet been processed + + try { + OBContext.setAdminMode(false); + if (thereIsDataInImportQueue(importEntry)) { + // close and commit + OBDal.getInstance().commitAndClose(); + return; + } + + } finally { + OBContext.restorePreviousMode(); + } + super.processEntry(importEntry); + } + + private boolean thereIsDataInImportQueue(ImportEntry importEntry) { + try { + OBContext.setAdminMode(false); + + if (0 < countEntries("Error", importEntry)) { + // if there are related error entries before this one then this is an error + // throw an exception to move this entry also to error status + throw new OBException("There are error records before this record " + importEntry + + ", moving this entry also to error status."); + } + + return 0 < countEntries("Initial", importEntry); + } finally { + OBContext.restorePreviousMode(); + } + } + + private int countEntries(String importStatus, ImportEntry importEntry) { + final String whereClause = ImportEntry.PROPERTY_IMPORTSTATUS + "='" + importStatus + "' and " + + ImportEntry.PROPERTY_TYPEOFDATA + "='OBMOBC_SynchronizedData' and " + + ImportEntry.PROPERTY_CREATIONDATE + "<:creationDate and " + + ImportEntry.PROPERTY_ORGANIZATION + "=:org and id!=:id"; + final Query qry = OBDal.getInstance().getSession() + .createQuery("select count(*) from " + ImportEntry.ENTITY_NAME + " where " + whereClause); + qry.setParameter("id", importEntry.getId()); + qry.setTimestamp("creationDate", importEntry.getCreationDate()); + qry.setParameter("org", importEntry.getOrganization()); + + return ((Number) qry.uniqueResult()).intValue(); + } + } + +} diff --git a/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js b/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js --- a/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js +++ b/web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js @@ -588,6 +588,10 @@ this.$.header.setContent(this.header); } + if (this.hideCloseButton) { + this.$.headerCloseButton.hide(); + } + if (this.maxheight) { this.$.bodyParent.setStyle('max-height: ' + this.maxheight + ';'); } diff --git a/web/org.openbravo.mobile.core/source/component/ob-menu.js b/web/org.openbravo.mobile.core/source/component/ob-menu.js --- a/web/org.openbravo.mobile.core/source/component/ob-menu.js +++ b/web/org.openbravo.mobile.core/source/component/ob-menu.js @@ -205,7 +205,12 @@ if (args && args.cancellation && args.cancellation === true) { return true; } - if (me.route) { + var window = _.filter(args.windows, function (wind) { + return wind.route === args.context.route; + }); + if (window && window[0] && window[0].navigateTo) { + window[0].navigateTo(args); + } else if (me.route) { OB.MobileApp.model.navigate(me.route); } if (me.url) { diff --git a/web/org.openbravo.mobile.core/source/data/ob-dal.js b/web/org.openbravo.mobile.core/source/data/ob-dal.js --- a/web/org.openbravo.mobile.core/source/data/ob-dal.js +++ b/web/org.openbravo.mobile.core/source/data/ob-dal.js @@ -7,7 +7,7 @@ ************************************************************************************ */ -/*global OB, _, console, Backbone, enyo, localStorage */ +/*global OB, _, console, Backbone, enyo, localStorage, Promise */ OB.Dal = OB.Dal || {}; @@ -431,7 +431,7 @@ data.parameters = {}; } data.parameters.forceRemote = whereClause && whereClause.forceRemote; - + //replace _filter column with all columns marked as filterable if (whereClause && whereClause.remoteFilters) { var filter = _.find(whereClause.remoteFilters, function (filter) { @@ -1067,6 +1067,71 @@ } }; + OB.Dal.createDataDump = function (models, callback) { + var result = [], + cnt = 0, + promises = []; + + if (models.length === 0) { + if (callback) { + callback(); + } + return; + } + + _.each(models, function (model) { + promises.push(new Promise(function (resolve, reject) { + OB.Dal.find(model, null, function (data) { + cnt++; + // arbitrary high number we can't load more in memory + if (cnt > 5000) { + var msg = "Creating backup of more 5000 records, this it probably not supported, last record " + JSON.stringify(data); + OB.UTIL.showError(msg); + OB.error(msg); + throw msg; + } + result.push({ + 'model': model, + 'data': data.models + }); + resolve(); + }, function () { + reject(); + }); + })); + }); + + Promise.all(promises).then(function () { + if (callback) { + callback(result); + } + }); + }; + + OB.Dal.restoreDataDump = function (dataDump, callback) { + if (!dataDump) { + if (callback) { + callback(); + } + return; + } + + OB.Dal.transaction(function (tx) { + _.each(dataDump, function (dataDumpEntry) { + OB.Dal.removeAllInTransaction(tx, dataDumpEntry.model); + _.each(dataDumpEntry.data, function (dataEntry) { + OB.Dal.saveInTransaction(tx, dataEntry, null, null, true); + }); + }); + }, function () { + OB.error("The restore dump failed failed to be commited. data: " + JSON.stringify(dataDump)); + }, function () { + if (callback) { + callback(); + } + }); + }; + OB.Dal.remove = function (model, success, error, currentTransaction) { if (OB.Data.localDB) { var modelDefinition = OB.Model[model.constructor.prototype.modelName], diff --git a/web/org.openbravo.mobile.core/source/data/ob-datasource.js b/web/org.openbravo.mobile.core/source/data/ob-datasource.js --- a/web/org.openbravo.mobile.core/source/data/ob-datasource.js +++ b/web/org.openbravo.mobile.core/source/data/ob-datasource.js @@ -67,6 +67,8 @@ } exception.invalidPermission = response.error.invalidPermission; exception.message = response.error.message; + } else if (response.error) { + exception.message = response.error; } // argument checks @@ -196,7 +198,7 @@ this.source = source; }; - OB.DS.Process.prototype.exec = function (params, callback, callbackError, async, timeout) { + OB.DS.Process.prepareData = function (params) { var data = {}, i, attr; @@ -215,8 +217,45 @@ } data.appName = OB.MobileApp.model.get('appName') || 'OBMOBC'; + return data; + }; - servicePOST(this.source, data, callback, callbackError, async, timeout); + OB.DS.Process.prototype.exec = function (params, callback, callbackError, async, timeout) { + var data = OB.DS.Process.prepareData(params); + + // run all transactional services synchronized if synchronized mode is enabled + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true) && OB.RR.RequestRouter.isTransactionalService(this.source)) { + var contentData = []; + data._serviceName = this.source; + + contentData.push(data); + + OB.MobileApp.model.showSynchronizingDialog(); + this.source = 'org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller'; + var syncData = { + messageId: params.messageId ? params.messageId : OB.UTIL.get_UUID(), + _source: 'WEBPOS', + posTerminal: OB.MobileApp.model.get('terminal').id, + data: contentData + }; + syncData = OB.DS.Process.prepareData(syncData); + + servicePOST(this.source, syncData, function (args) { + if (callback) { + callback(args); + } + OB.MobileApp.model.hideSynchronizingDialog(); + }, function (args) { + OB.MobileApp.model.hideSynchronizingDialog(); + if (callbackError) { + callbackError(args); + } + }, async, timeout); + + } else { + servicePOST(this.source, data, callback, callbackError, async, timeout); + } + }; // Source object diff --git a/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js b/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js --- a/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js +++ b/web/org.openbravo.mobile.core/source/data/ob-requestrouter.js @@ -816,7 +816,29 @@ OB.UTIL.localStorage.setItem('authenticationToken', encodeURIComponent(data.authenticationToken)); } }, function () {}, true, 20000); + }, + + isTransactionalService: function (serviceName) { + var service, services = _.filter(OB.RR.RequestRouter.availableServices.models, function (srvc) { + return serviceName.indexOf(srvc.get('name')) !== -1; + }); + if (services.length > 1) { + //In case of having more than one service, get longest name service. Longest name service will be the most similar to serviceName + _.each(services, function (iterSrvc) { + if (!service || service.get('name').length < iterSrvc.get('name').length) { + service = iterSrvc; + } + }); + + } else { + service = services[0]; + } + if (!service) { + return false; + } + return service.get('type') === OB.RR.ServTypeTransaction; } + }; OB.RR.RequestRouter.initialize(); diff --git a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js b/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js --- a/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js +++ b/web/org.openbravo.mobile.core/source/model/ob-terminal-model.js @@ -13,6 +13,9 @@ OB.MobileApp = OB.MobileApp || {}; OB.Data = OB.Data || {}; +// used for test purposes to keep track that sync dialog was shown +OB.Data.showSynchronizedDialogChangeTime = 0; + OB.MobileApp.windowRegistry = new(Backbone.Model.extend({ registeredWindows: [], @@ -761,6 +764,152 @@ }); }, + + /** + * Is used by the synchronized mode logic to reset tables to their previous state + * before making the synchronized call to the server. So if the user then + * refreshes the browser during the call at least the tables are in their previous + * versions. This is mainly relevant for cashup information which gets updated + * along the way and needs to be reversed if needed. + * + * If the synchronized call fails then the old cashup information still applies. + * + * The flow is as follows: + * # application code calls saveBackupBeforeChange function, it stores all the relevant tables + * for that action + * # application then changes what it wants + * # then calls runsync process + * # runsyncprocess will just before calling the server backup the new version of the + * tables (saveBackupBeforeSyncRestorePreChangeBackup function) and restore the + * before change version + * # when the server encounters an error or something else then nothing is changed as + * all the data is already in the previous version + * # when the server returns correctly the backup tables are restored to their state just + * before the send to the server + * + */ + _synchronizedCheckpointModels: [], + addSyncCheckpointModel: function (model) { + this._synchronizedCheckpointModels.push(model); + }, + _prechangeCheckpoint: null, + _presyncCheckpoint: null, + setSynchronizedCheckpoint: function (callback) { + var me = OB.MobileApp.model; + + if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + return; + } + + // already show the dialog now + me.showSynchronizingDialog(); + + OB.Dal.createDataDump(me._synchronizedCheckpointModels, function (checkPoint) { + me._prechangeCheckpoint = checkPoint; + if (callback) { + callback(); + } + }); + }, + showSynchronizingDialog: function () { + var me = OB.MobileApp.model; + + me.showSynchronizedDialog = OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBMOBC_ProcessingTransactionTitle'), OB.I18N.getLabel('OBMOBC_ProcessingTransaction'), [], { + hideCloseButton: true, + autoDismiss: false, + closeOnEscKey: false + }); + OB.Data.showSynchronizedDialogChangeTime = new Date().getTime(); + + }, + hideSynchronizingDialog: function () { + var me = OB.MobileApp.model; + if (me.showSynchronizedDialog) { + me.showSynchronizedDialog.hide(); + me.showSynchronizedDialog = null; + } + }, + createPresyncCheckpoint: function (callback) { + var me = OB.MobileApp.model; + + OB.Dal.createDataDump(me._synchronizedCheckpointModels, function (checkPoint) { + me._presyncCheckpoint = checkPoint; + if (callback) { + callback(); + } + }); + }, + moveToPrechangeCheckpoint: function (callback) { + var me = OB.MobileApp.model, + dataDump = me._prechangeCheckpoint; + if (!dataDump) { + if (callback) { + callback(); + } + return; + } + // be on the save side, set it to null if it fails we won't get it + // back anyway + me._prechangeCheckpoint = null; + OB.Dal.restoreDataDump(dataDump, function () { + me._prechangeCheckpoint = null; + if (callback) { + callback(); + } + }); + }, + resetCheckpointData: function () { + var me = OB.MobileApp.model; + + me._presyncCheckpoint = null; + me._prechangeCheckpoint = null; + }, + moveToPresyncCheckpoint: function (callback) { + var me = OB.MobileApp.model; + // reset this one also + me._prechangeCheckpoint = null; + + if (!me._presyncCheckpoint) { + if (callback) { + callback(); + } + return; + } + OB.Dal.restoreDataDump(me._presyncCheckpoint, function () { + me._presyncCheckpoint = null; + if (callback) { + callback(); + } + }); + }, + + preSyncPromises: [], + doPreSynchronizedCallActions: function (callback) { + var me = OB.MobileApp.model; + new Promise(function (resolve, reject) { + me.createPresyncCheckpoint(function () { + resolve(); + }); + }).then(function () { + return new Promise(function (resolve, reject) { + me.moveToPrechangeCheckpoint(function () { + resolve(); + }); + }); + }).then(function () { + return Promise.all(me.preSyncPromises); + }).then( + + function () { + me.preSyncPromises = []; + if (callback) { + callback(); + } + }, function (reason) { + OB.error("Error while processing promise " + reason); + }); + }, + /** * Should not be called directly. syncAllModels should be used instead * @@ -777,8 +926,46 @@ // stop the recursion when the queue of syncModels is empty // the rest of the actions are in the removeSyncedElemsCallback if (me.syncModelQueue.length === 0) { - //There aren't element to synchronize - me.syncModelExecuteSuccessCallbacks(); + //There aren't anymore elements to synchronize + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + + // clean up in any case after success or error + // note: moveToPresyncCheckpoint must be called before the reset + me.syncModelSuccessCallbacks.unshift(function () { + me.resetCheckpointData(); + }); + me.syncModelErrorCallbacks.push(function () { + me.resetCheckpointData(); + }); + + // nothing to do go away + if (me.synchronizedData.length === 0) { + me.syncModelExecuteSuccessCallbacks(); + return; + } + + // already show the dialog now + me.showSynchronizingDialog(); + + //now send all the collected json as one request + var syncProc = new OB.DS.Process('org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller'); + var syncData = { + messageId: OB.UTIL.get_UUID(), + _source: 'WEBPOS', + posTerminal: OB.MobileApp.model.get('terminal').id, + data: me.synchronizedData + }; + + // clear some memory + me.synchronizedData = []; + + // and execute the complete request, first do the presync actions + me.doPreSynchronizedCallActions(function () { + syncProc.exec(syncData, me.syncModelExecuteSuccessCallbacks, me.syncModelExecuteErrorCallbacks, null, me.synchronizedTimeOut); + }); + } else { + me.syncModelExecuteSuccessCallbacks(); + } return; } @@ -844,77 +1031,127 @@ } }); - var proc = new OB.DS.Process(className); var timeout = modelObj.timeout || 20000; var timePerRecord = modelObj.timePerRecord || 1000; - proc.exec({ + var data = { messageId: OB.UTIL.get_UUID(), data: dataToSend - }, function (data, message) { - // error - if (data && data.exception) { - OB.warn("The model '" + OB.Dal.getTableName(model) + "'' has not been synchronized with the server"); - if (data.exception.invalidPermission && !me.get('displayedInvalidPermission')) { - // invalid permission message only will be displayed once time - me.set('displayedInvalidPermission', true); - OB.UTIL.showConfirmation.display('Info', OB.I18N.getLabel('OBMOBC_NoPermissionToSyncModel', [OB.Dal.getTableName(model), OB.Dal.getTableName(model)]), [{ - label: OB.I18N.getLabel('OBMOBC_LblOk'), - isConfirmButton: true, - action: function () {} - }]); + }; + + // add an additional pre-sync action, remove any non-persistent data + // before really going to the server + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + newDataToSync.each(function (record) { + me.preSyncPromises.push(new Promise(function (resolve, reject) { + if (!modelObj.isPersistent) { + OB.Dal.remove(record, function () { + resolve(); + }, function (tx, err) { + OB.UTIL.showError(err); + reject(); + }); + } else { + resolve(); + } + })); + }); + } + + var procErrorCallBack = function () { + var promises = []; + + // proc.exec mcallbackerror + OB.warn("Error while synchronizing model '" + OB.Dal.getTableName(model) + "'"); + + me.syncModelExecuteErrorCallbacks(); + }; + + var procSuccessCallBack = function (data, message) { + + // error + if (data && data.exception) { + OB.warn("The model '" + OB.Dal.getTableName(model) + "'' has not been synchronized with the server"); + if (data.exception.invalidPermission && !me.get('displayedInvalidPermission')) { + // invalid permission message only will be displayed once time + me.set('displayedInvalidPermission', true); + OB.UTIL.showConfirmation.display('Info', OB.I18N.getLabel('OBMOBC_NoPermissionToSyncModel', [OB.Dal.getTableName(model), OB.Dal.getTableName(model)]), [{ + label: OB.I18N.getLabel('OBMOBC_LblOk'), + isConfirmButton: true, + action: function () {} + }]); + } + me.syncModelExecuteErrorCallbacks(); + return; } - me.syncModelExecuteErrorCallbacks(); - return; - } - // success. Elements can be now deleted from the database - var removeSyncedElemsCallback = function () { - OB.info("Purging the '" + OB.Dal.getTableName(model) + "' table"); - var promises = []; - newDataToSync.each(function (record) { - promises.push(new Promise(function (resolve, reject) { - if (modelObj.isPersistent) { - // Persistent model. Do not delete, just mark it as processed. - OB.Dal.updateRecordColumn(record, "isbeingprocessed", "Y", function () { - resolve(); - }, function (tx, err) { - reject(); - }); - } else { - // no persistent model (Default). - OB.Dal.remove(record, function () { - resolve(); - }, function (tx, err) { - OB.UTIL.showError(err); - reject(); - }); + // success. Elements can be now deleted from the database + var removeSyncedElemsCallback = function () { + OB.info("Purging the '" + OB.Dal.getTableName(model) + "' table"); + var promises = []; + + if (modelObj.successSendModel) { + promises.push(new Promise(function (resolve, reject) { + modelObj.successSendModel(); + resolve(); + })); + } + + newDataToSync.each(function (record) { + promises.push(new Promise(function (resolve, reject) { + if (modelObj.isPersistent) { + // Persistent model. Do not delete, just mark it as processed. + OB.Dal.updateRecordColumn(record, "isbeingprocessed", "Y", function () { + resolve(); + }, function (tx, err) { + reject(); + }); + } else { + // no persistent model (Default). + OB.Dal.remove(record, function () { + resolve(); + }, function (tx, err) { + OB.UTIL.showError(err); + reject(); + }); + } + })); + }); + + Promise.all(promises).then(function () { + // if the model has been partitioned + if (modelNotFullySynced) { + OB.info(newDataToSync.length + " records of the table '" + OB.Dal.getTableName(model) + "' have been successfully synchronized with the server. " + (dataToSync.length - newDataToSync.length) + " records remaining to be synchronized."); + me.syncModel(); + return; } - })); - }); + OB.info("The table '" + OB.Dal.getTableName(model) + "' has been fully synchronized with the server"); + }, function (err) { + OB.error("Could not purge the '" + OB.Dal.getTableName(model) + "' table. Error message: " + err); + }); + // not synchronized mode do the next in the success callback + // with synchronized mode the recall syncmodel is below in the code + if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + me.syncModel(); + } + }; + if (modelObj.postProcessingFunction) { + modelObj.postProcessingFunction(newDataToSync, removeSyncedElemsCallback); + } else { + removeSyncedElemsCallback(); + } + }; - Promise.all(promises).then(function () { - // if the model has been partitioned - if (modelNotFullySynced) { - OB.info(newDataToSync.length + " records of the table '" + OB.Dal.getTableName(model) + "' have been successfully synchronized with the server. " + (dataToSync.length - newDataToSync.length) + " records remaining to be synchronized."); - me.syncModel(); - return; - } - OB.info("The table '" + OB.Dal.getTableName(model) + "' has been fully synchronized with the server"); - }, function (err) { - OB.error("Could not purge the '" + OB.Dal.getTableName(model) + "' table. Error message: " + err); - }); - me.syncModel(); - }; - if (modelObj.postProcessingFunction) { - modelObj.postProcessingFunction(newDataToSync, removeSyncedElemsCallback); - } else { - removeSyncedElemsCallback(); - } - }, function () { - // proc.exec mcallbackerror - OB.warn("Error while synchronizing model '" + OB.Dal.getTableName(model) + "'"); - me.syncModelExecuteErrorCallbacks(); - }, null, timeout + timePerRecord * newDataToSync.length); - }, function () { + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + me.collectSyncData(className, data, timeout + timePerRecord * newDataToSync.length); + me.syncModelSuccessCallbacks.push(procSuccessCallBack); + me.syncModel(); + } else { + var proc = new OB.DS.Process(className); + proc.exec(data, procSuccessCallBack, procErrorCallBack, null, timeout + timePerRecord * newDataToSync.length); + } + }, + + + function () { // there is no model in the local database. this is ok. move to the next model me.syncModel(); }, { @@ -924,21 +1161,65 @@ }, syncModelSuccessCallbacks: [], syncModelErrorCallbacks: [], - syncModelExecuteSuccessCallbacks: function () { + syncModelExecuteSuccessCallbacks: function (result) { OB.UTIL.Debug.execute(function () { if (OB.MobileApp.model.syncModelQueue && OB.MobileApp.model.syncModelQueue.length > 0) { throw "The 'syncModelQueue' should be empty at this point"; } }); + + // exception occurred but was returned in the json as a valid response + if (result && result.exception) { + OB.MobileApp.model.syncModelExecuteErrorCallbacks(arguments); + return; + } + + OB.MobileApp.model.hideSynchronizingDialog(); + OB.MobileApp.model.syncModelQueue = []; OB.MobileApp.model.syncModelErrorCallbacks = []; - OB.UTIL.executeCallbackQueue(OB.MobileApp.model.syncModelSuccessCallbacks); + new Promise(function (resolve, reject) { + // is only doing anything in case of synchronized mode + OB.MobileApp.model.moveToPresyncCheckpoint(function () { + resolve(); + }); + }).then(function () { + OB.UTIL.executeCallbackQueue(OB.MobileApp.model.syncModelSuccessCallbacks, result); + }); }, syncModelExecuteErrorCallbacks: function () { OB.MobileApp.model.syncModelQueue = []; OB.MobileApp.model.syncModelSuccessCallbacks = []; + + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + var msg = arguments[0][0] && arguments[0][0].exception ? arguments[0][0].exception.message : "No Details"; + + OB.MobileApp.model.hideSynchronizingDialog(); + + OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBMOBC_TransactionFailedTitle'), OB.I18N.getLabel('OBMOBC_TransactionFailed', [msg]), [{ + isConfirmButton: true, + label: OB.I18N.getLabel('OBMOBC_LblOk'), + action: function () { + OB.POS.navigate('retail.pointofsale'); + return true; + } + }]); + } + OB.UTIL.executeCallbackQueue(OB.MobileApp.model.syncModelErrorCallbacks); }, + + // collect the data to sync + collectSyncData: function (source, params, timeout) { + var data = OB.DS.Process.prepareData(params); + + data._serviceName = source; + + this.synchronizedTimeOut = this.synchronizedTimeOut + timeout; + + this.synchronizedData.push(data); + }, + /** * Synchronizes all dataSyncModels (models which data is kept localy until flushed to the server) * @@ -969,6 +1250,9 @@ return; } + me.syncModelSuccessCallbacks = []; + me.syncModelErrorCallbacks = []; + // remember the callbacks in the callbacks queue me.syncModelSuccessCallbacks.push(successCallback); me.syncModelErrorCallbacks.push(errorCallback); @@ -984,8 +1268,13 @@ var modelObj = this.get('dataSyncModels')[i]; me.syncModelQueue.push(modelObj); } + // start the synchronization if it was not already in progress if (!isCurrentlySynchronizing) { + // reset some members used in synchronized comms + me.synchronizedData = []; + me.synchronizedTimeOut = 0; + me.syncModel(this.syncModelExecuteSuccessCallbacks, this.syncModelExecuteErrorCallbacks); } }, diff --git a/web/org.openbravo.mobile.core/source/utils/ob-utilities.js b/web/org.openbravo.mobile.core/source/utils/ob-utilities.js --- a/web/org.openbravo.mobile.core/source/utils/ob-utilities.js +++ b/web/org.openbravo.mobile.core/source/utils/ob-utilities.js @@ -771,11 +771,11 @@ } }; - OB.UTIL.executeCallbackQueue = function (queue) { + OB.UTIL.executeCallbackQueue = function (queue, arg) { while (queue.length > 0) { var f = queue.shift(); if (f) { - f(); + f(arg); } } }; diff --git a/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js b/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js --- a/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js +++ b/web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js @@ -240,6 +240,7 @@ name: 'dynamicConfirmationPopup', header: title, bodyContent: bodyContent, + hideCloseButton: options && options.hideCloseButton, autoDismiss: !OB.UTIL.isNullOrUndefined(options) && !OB.UTIL.isNullOrUndefined(options.autoDismiss) ? options.autoDismiss : true, executeOnShow: function () { if (options && options.onShowFunction) { @@ -330,6 +331,7 @@ dialog.show(); OB.UTIL.showLoading(false); + return dialog; } } }); 1505-retail.diff [^] (83,686 bytes) 2016-05-15 16:48 [Show Content] [Hide Content] diff --git a/src/org/openbravo/retail/posterminal/LoginUtilsServlet.java b/src/org/openbravo/retail/posterminal/LoginUtilsServlet.java --- a/src/org/openbravo/retail/posterminal/LoginUtilsServlet.java +++ b/src/org/openbravo/retail/posterminal/LoginUtilsServlet.java @@ -1,6 +1,6 @@ /* ************************************************************************************ - * Copyright (C) 2012-2013 Openbravo S.L.U. + * Copyright (C) 2012-2016 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. @@ -22,7 +22,6 @@ import org.openbravo.base.secureApp.LoginUtils; import org.openbravo.base.secureApp.VariablesSecureApp; import org.openbravo.client.kernel.RequestContext; -import org.openbravo.dal.core.OBContext; import org.openbravo.dal.service.OBCriteria; import org.openbravo.dal.service.OBDal; import org.openbravo.dal.service.OBQuery; @@ -32,6 +31,7 @@ import org.openbravo.mobile.core.MobileServerDefinition; import org.openbravo.mobile.core.MobileServerOrganization; import org.openbravo.mobile.core.login.MobileCoreLoginUtilsServlet; +import org.openbravo.mobile.core.servercontroller.MobileServerUtils; import org.openbravo.model.ad.access.FormAccess; import org.openbravo.model.ad.access.User; import org.openbravo.model.ad.access.UserRoles; @@ -340,19 +340,7 @@ protected JSONArray getServers(OBPOSApplications terminal) throws JSONException { JSONArray respArray = new JSONArray(); - boolean multiServerEnabled = false; - try { - OBContext.setAdminMode(false); - multiServerEnabled = "Y".equals(Preferences.getPreferenceValue( - "OBMOBC_MultiServerArchitecture", true, terminal.getClient(), terminal.getOrganization(), - null, null, null).trim()); - } catch (PropertyException ignore) { - // ignore on purpose - } finally { - OBContext.restorePreviousMode(); - } - - if (!multiServerEnabled) { + if (!MobileServerUtils.isMultiServerEnabled(terminal.getClient(), terminal.getOrganization())) { return respArray; } diff --git a/src/org/openbravo/retail/posterminal/importprocess/POSImportEntryProcessor.java b/src/org/openbravo/retail/posterminal/importprocess/POSImportEntryProcessor.java --- a/src/org/openbravo/retail/posterminal/importprocess/POSImportEntryProcessor.java +++ b/src/org/openbravo/retail/posterminal/importprocess/POSImportEntryProcessor.java @@ -22,6 +22,7 @@ import org.openbravo.client.kernel.event.EntityNewEvent; import org.openbravo.client.kernel.event.EntityPersistenceEventObserver; import org.openbravo.dal.service.OBDal; +import org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller; import org.openbravo.retail.posterminal.OBPOSApplications; import org.openbravo.service.importprocess.ImportEntry; import org.openbravo.service.importprocess.ImportProcessUtils; @@ -38,7 +39,8 @@ private static List<String> POSTTYPEOFDATA = Arrays.asList("Order", "BusinessPartner", "BusinessPartnerLocation", "OBPOS_App_Cashup", "FIN_Finacc_Transaction", - "OBPOS_RejectQuotation", "OBPOS_VoidLayaway"); + "OBPOS_RejectQuotation", "OBPOS_VoidLayaway", + SynchronizedServerProcessCaller.SYNCHRONIZED_DATA_TYPE); @Override protected Entity[] getObservedEntities() { diff --git a/src/org/openbravo/retail/posterminal/master/CashupSynchronized.java b/src/org/openbravo/retail/posterminal/master/CashupSynchronized.java new file mode 100644 --- /dev/null +++ b/src/org/openbravo/retail/posterminal/master/CashupSynchronized.java @@ -0,0 +1,103 @@ +/* + ************************************************************************************ + * Copyright (C) 2016 Openbravo S.L.U. + * Licensed under the Openbravo Commercial License version 1.0 + * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html + * or in the legal folder of this module distribution. + ************************************************************************************ + */ +package org.openbravo.retail.posterminal.master; + +import javax.servlet.ServletException; + +import org.apache.log4j.Logger; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.hibernate.Query; +import org.openbravo.base.exception.OBException; +import org.openbravo.dal.core.SessionHandler; +import org.openbravo.mobile.core.servercontroller.MobileServerController; +import org.openbravo.mobile.core.servercontroller.MobileServerRequestExecutor; +import org.openbravo.mobile.core.servercontroller.MobileServerUtils; +import org.openbravo.mobile.core.servercontroller.SynchronizedServerProcessCaller; +import org.openbravo.model.common.order.Order; +import org.openbravo.retail.posterminal.OBPOSErrors; +import org.openbravo.retail.posterminal.ProcessCashClose; +import org.openbravo.service.importprocess.ImportEntry; + +/** + * A read cashup information class which is used in case of running in synchronized mode. First call + * the central server to get the latest cashup information and return that if available. + * + * @author mtaal + */ +public class CashupSynchronized extends Cashup { + private static final Logger log = Logger.getLogger(ProcessCashClose.class); + + @Override + public JSONObject exec(JSONObject json) throws JSONException, ServletException { + if (MobileServerController.getInstance().isThisACentralServer()) { + return executeLocal(json); + } else if (MobileServerController.getInstance().isCentralServerOnline()) { + log.debug("Central server is online, first see if there are errors in the queue"); + if (isDataInQueue(json)) { + // errors in local, so call central + log.debug("errors in queue, try central"); + try { + return MobileServerRequestExecutor.getInstance().executeCentralRequest( + MobileServerUtils.OBWSPATH + this.getClass().getName(), json); + } catch (Throwable t) { + // something goes wrong on central, try local + // should fail as there are errors in the import queue + return executeLocal(json); + } + } else { + // no local errors, take from local + return executeLocal(json); + } + } else { + return executeLocal(json); + } + } + + private JSONObject executeLocal(JSONObject json) throws JSONException, ServletException { + if (isDataInQueue(json)) { + throw new OBException( + "Data on the server is in error/initial state, cashup information can not be retrieved"); + } + return super.exec(json); + } + + private boolean isDataInQueue(JSONObject json) throws JSONException { + final String posId = json.getString("pos"); + { + final Query qry = SessionHandler + .getInstance() + .getSession() + .createQuery( + "select count(*) from " + ImportEntry.ENTITY_NAME + " where (" + + ImportEntry.PROPERTY_IMPORTSTATUS + "='Error' or " + + ImportEntry.PROPERTY_IMPORTSTATUS + "='Initial') and " + + ImportEntry.PROPERTY_TYPEOFDATA + "='" + + SynchronizedServerProcessCaller.SYNCHRONIZED_DATA_TYPE + "' and " + + ImportEntry.PROPERTY_OBPOSPOSTERMINAL + "='" + posId + "'"); + if (((Number) qry.uniqueResult()).intValue() > 0) { + return true; + } + } + { + final Query qry = SessionHandler + .getInstance() + .getSession() + .createQuery( + "select count(*) from " + OBPOSErrors.ENTITY_NAME + " where " + + OBPOSErrors.PROPERTY_ORDERSTATUS + "='N' and " + + OBPOSErrors.PROPERTY_TYPEOFDATA + "='" + Order.ENTITY_NAME + "' and " + + OBPOSErrors.PROPERTY_OBPOSAPPLICATIONS + "='" + posId + "'"); + if (((Number) qry.uniqueResult()).intValue() > 0) { + return true; + } + } + return false; + } +} diff --git a/web/org.openbravo.retail.posterminal/js/cashmgmt/model/cashmgmt-model.js b/web/org.openbravo.retail.posterminal/js/cashmgmt/model/cashmgmt-model.js --- a/web/org.openbravo.retail.posterminal/js/cashmgmt/model/cashmgmt-model.js +++ b/web/org.openbravo.retail.posterminal/js/cashmgmt/model/cashmgmt-model.js @@ -82,103 +82,120 @@ }, null, this); }, this); - this.depsdropstosave.on('makeDeposits', function () { - // Done button has been clicked - me = this; - TestRegistry.CashMgmt = TestRegistry.CashMgmt || {}; - TestRegistry.CashMgmt.isCashDepositPrinted = false; + var makeDepositsFunction = function (me) { + TestRegistry.CashMgmt = TestRegistry.CashMgmt || {}; + TestRegistry.CashMgmt.isCashDepositPrinted = false; - OB.UTIL.showLoading(true); + OB.UTIL.showLoading(true); - if (this.depsdropstosave.length === 0) { - // Nothing to do go to main window - OB.POS.navigate('retail.pointofsale'); - return true; - } + if (me.depsdropstosave.length === 0) { + // Nothing to do go to main window + OB.POS.navigate('retail.pointofsale'); + return true; + } - this.printCashMgmt = new OB.OBPOSCashMgmt.Print.CashMgmt(); + me.printCashMgmt = new OB.OBPOSCashMgmt.Print.CashMgmt(); - TestRegistry.CashMgmt.isCashDepositPrinted = true; + TestRegistry.CashMgmt.isCashDepositPrinted = true; - function runSync() { - if (OB.MobileApp.model.get('connectedToERP')) { - OB.MobileApp.model.runSyncProcess(function () { + function runSync() { + if (OB.MobileApp.model.get('connectedToERP')) { + OB.MobileApp.model.runSyncProcess(function () { + OB.UTIL.showLoading(false); + me.set("finished", true); + if (OB.MobileApp.model.hasPermission('OBPOS_print.cashmanagement')) { + me.printCashMgmt.print(me.depsdropstosave.toJSON()); + } + }, function () { + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + // fail, remove everything and go away + OB.Dal.removeAll(OB.Model.CashManagement, null, function () { + OB.UTIL.calculateCurrentCash(); + me.depsdropstosave = new Backbone.Collection(); + }); + } + }); + } else { OB.UTIL.showLoading(false); me.set("finished", true); if (OB.MobileApp.model.hasPermission('OBPOS_print.cashmanagement')) { me.printCashMgmt.print(me.depsdropstosave.toJSON()); } - }); - } else { - OB.UTIL.showLoading(false); - me.set("finished", true); - if (OB.MobileApp.model.hasPermission('OBPOS_print.cashmanagement')) { - me.printCashMgmt.print(me.depsdropstosave.toJSON()); } } - } - var paymentList = new Backbone.Collection(), - found = false, - i; + var paymentList = new Backbone.Collection(), + found = false, + i; - function addAttributes(depdrop) { - var payment = new OB.Model.PaymentMethodCashUp(); - if (depdrop.get('type') === 'deposit') { - payment.set('paymentMethodId', depdrop.get('paymentMethodId')); - payment.set('cashup_id', depdrop.get('cashup_id')); - payment.set('totalDeposits', depdrop.get('amount')); - payment.set('totalDrops', 0); - } else { - payment.set('paymentMethodId', depdrop.get('paymentMethodId')); - payment.set('cashup_id', depdrop.get('cashup_id')); - payment.set('totalDrops', depdrop.get('amount')); - payment.set('totalDeposits', 0); + function addAttributes(depdrop) { + var payment = new OB.Model.PaymentMethodCashUp(); + if (depdrop.get('type') === 'deposit') { + payment.set('paymentMethodId', depdrop.get('paymentMethodId')); + payment.set('cashup_id', depdrop.get('cashup_id')); + payment.set('totalDeposits', depdrop.get('amount')); + payment.set('totalDrops', 0); + } else { + payment.set('paymentMethodId', depdrop.get('paymentMethodId')); + payment.set('cashup_id', depdrop.get('cashup_id')); + payment.set('totalDrops', depdrop.get('amount')); + payment.set('totalDeposits', 0); + } + return payment; } - return payment; - } - _.each(this.depsdropstosave.models, function (depdrop) { - if (paymentList.length > 0) { - for (i = 0; i < paymentList.length; i++) { - found = false; - if (paymentList.models[i].get('paymentMethodId') === depdrop.get('paymentMethodId')) { - var paymentMethod = paymentList.models[i], - totalDeposits = 0, - totalDrops = 0, - depos = paymentMethod.get('totalDeposits'), - drop = paymentMethod.get('totalDrops'); - if (depdrop.get('type') === 'deposit') { - totalDeposits = OB.DEC.add(depos, depdrop.get('amount')); - paymentMethod.set('totalDeposits', totalDeposits); - } else { - totalDrops = OB.DEC.add(drop, depdrop.get('amount')); - paymentMethod.set('totalDrops', totalDrops); + _.each(me.depsdropstosave.models, function (depdrop) { + if (paymentList.length > 0) { + for (i = 0; i < paymentList.length; i++) { + found = false; + if (paymentList.models[i].get('paymentMethodId') === depdrop.get('paymentMethodId')) { + var paymentMethod = paymentList.models[i], + totalDeposits = 0, + totalDrops = 0, + depos = paymentMethod.get('totalDeposits'), + drop = paymentMethod.get('totalDrops'); + if (depdrop.get('type') === 'deposit') { + totalDeposits = OB.DEC.add(depos, depdrop.get('amount')); + paymentMethod.set('totalDeposits', totalDeposits); + } else { + totalDrops = OB.DEC.add(drop, depdrop.get('amount')); + paymentMethod.set('totalDrops', totalDrops); + } + found = true; + break; } - found = true; - break; } - } - if (!found) { + if (!found) { + paymentList.add(addAttributes(depdrop)); + } + } else { paymentList.add(addAttributes(depdrop)); } - } else { - paymentList.add(addAttributes(depdrop)); - } - }, this); + }, this); - var runSyncProcessCM = _.after(this.depsdropstosave.models.length, runSync); - // Sending drops/deposits to backend - _.each(this.depsdropstosave.models, function (depdrop, index) { - OB.Dal.save(depdrop, function () { - OB.UTIL.sumCashManagementToCashup(paymentList.models[index]); - OB.UTIL.calculateCurrentCash(); - runSyncProcessCM(); - }, function () { - OB.UTIL.showLoading(false); - me.set("finishedWrongly", true); - return; - }, true); - }, this); + var runSyncProcessCM = _.after(me.depsdropstosave.models.length, runSync); + // Sending drops/deposits to backend + _.each(me.depsdropstosave.models, function (depdrop, index) { + OB.Dal.save(depdrop, function () { + OB.UTIL.sumCashManagementToCashup(paymentList.models[index]); + OB.UTIL.calculateCurrentCash(); + runSyncProcessCM(); + }, function () { + OB.UTIL.showLoading(false); + me.set("finishedWrongly", true); + return; + }, true); + }, this); + }; + + this.depsdropstosave.on('makeDeposits', function (receipt) { + var me = this; + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.MobileApp.model.setSynchronizedCheckpoint(function () { + makeDepositsFunction(me); + }); + } else { + makeDepositsFunction(me); + } }, this); // effective entry point diff --git a/web/org.openbravo.retail.posterminal/js/closecash/model/cashup-model.js b/web/org.openbravo.retail.posterminal/js/closecash/model/cashup-model.js --- a/web/org.openbravo.retail.posterminal/js/closecash/model/cashup-model.js +++ b/web/org.openbravo.retail.posterminal/js/closecash/model/cashup-model.js @@ -730,12 +730,19 @@ me.printCashUp.print(me.get('cashUpReport').at(0), me.getCountCashSummary(), true); } }; + var callbackFinishedWrongly = function () { + // reset to N + cashUp.at(0).set('isprocessed', 'N'); + OB.Dal.save(cashUp.at(0)); + me.set("finishedWrongly", true); + }; + var callbackFunc = function () { OB.UTIL.SynchronizationHelper.finished(synchId, 'processAndFinishCashUp'); OB.MobileApp.model.runSyncProcess(function () { callbackFinishedSuccess(); }, function () { - callbackFinishedSuccess(); + callbackFinishedWrongly(); }); }; callbackFunc(); diff --git a/web/org.openbravo.retail.posterminal/js/closecash/view/closecash.js b/web/org.openbravo.retail.posterminal/js/closecash/view/closecash.js --- a/web/org.openbravo.retail.posterminal/js/closecash/view/closecash.js +++ b/web/org.openbravo.retail.posterminal/js/closecash/view/closecash.js @@ -352,6 +352,11 @@ }, this); //finishedWrongly this.model.on('change:finishedWrongly', function (model) { + // in case of synchronized mode then don't do specific things + // message is already displayed + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + return; + } var message = ""; if (model.get('errorMessage')) { message = OB.I18N.getLabel(model.get('errorMessage'), [model.get('errorDetail')]); @@ -567,8 +572,6 @@ } }); - - OB.POS.registerWindow({ windowClass: OB.OBPOSCashUp.UI.CashUp, route: 'retail.cashup', @@ -576,10 +579,22 @@ menuPosition: 20, menuI18NLabel: 'OBPOS_LblCloseCash', permission: 'OBPOS_retail.cashup', - approvalType: 'OBPOS_approval.cashup' + approvalType: 'OBPOS_approval.cashup', + navigateTo: function () { + var me = this; + // in case of synchronized mode reload the cashup from the server + // this is needed because there is a slight change that the cashup on the client + // is out of date + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.UTIL.rebuildCashupFromServer(function () { + OB.MobileApp.model.navigate(me.route); + }); + } else { + OB.MobileApp.model.navigate(me.route); + } + } }); - enyo.kind({ name: 'OB.OBPOSCashUp.UI.CashUpPartial', kind: 'OB.OBPOSCashUp.UI.CashUp', diff --git a/web/org.openbravo.retail.posterminal/js/data/datacustomeraddrsave.js b/web/org.openbravo.retail.posterminal/js/data/datacustomeraddrsave.js --- a/web/org.openbravo.retail.posterminal/js/data/datacustomeraddrsave.js +++ b/web/org.openbravo.retail.posterminal/js/data/datacustomeraddrsave.js @@ -1,6 +1,6 @@ /* ************************************************************************************ - * Copyright (C) 2012-2015 Openbravo S.L.U. + * Copyright (C) 2012-2016 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. @@ -18,49 +18,57 @@ OB.DATA.CustomerAddrSave = function (model) { this.context = model; this.customerAddr = model.get('customerAddr'); + + // trigger is from previous code, keeping it for backward compat this.customerAddr.on('customerAddrSaved', function () { - var me = this, - customerAddrList, customerAddrId = this.customerAddr.get('id'), + OB.DATA.executeCustomerAddressSave(this.customerAddr); + }, this); + + OB.DATA.executeCustomerAddressSave = function (customerAddr, callback) { + var customerAddrList, customerAddrId = this.customerAddr.get('id'), isNew = false, bpLocToSave = new OB.Model.ChangedBPlocation(), customerAddrListToChange; bpLocToSave.set('isbeingprocessed', 'N'); - this.customerAddr.set('createdBy', OB.MobileApp.model.get('orgUserId')); + customerAddr.set('createdBy', OB.MobileApp.model.get('orgUserId')); bpLocToSave.set('createdBy', OB.MobileApp.model.get('orgUserId')); if (customerAddrId) { - this.customerAddr.set('posTerminal', OB.MobileApp.model.get('terminal').id); - bpLocToSave.set('json', JSON.stringify(this.customerAddr.serializeToJSON())); - bpLocToSave.set('c_bpartner_location_id', this.customerAddr.get('id')); + customerAddr.set('posTerminal', OB.MobileApp.model.get('terminal').id); + bpLocToSave.set('json', JSON.stringify(customerAddr.serializeToJSON())); + bpLocToSave.set('c_bpartner_location_id', customerAddr.get('id')); } else { isNew = true; } if (OB.MobileApp.model.hasPermission('OBPOS_remote.customer', true)) { //With high volume we only save adress we it is assigned to the order if (isNew) { - me.customerAddr.set('posTerminal', OB.MobileApp.model.get('terminal').id); + customerAddr.set('posTerminal', OB.MobileApp.model.get('terminal').id); var uuid = OB.UTIL.get_UUID(); - me.customerAddr.set('id', uuid); - me.customerAddr.id = uuid; - bpLocToSave.set('json', JSON.stringify(me.customerAddr.serializeToJSON())); - bpLocToSave.set('id', me.customerAddr.get('id')); + customerAddr.set('id', uuid); + customerAddr.id = uuid; + bpLocToSave.set('json', JSON.stringify(customerAddr.serializeToJSON())); + bpLocToSave.set('id', customerAddr.get('id')); } bpLocToSave.set('isbeingprocessed', 'Y'); OB.Dal.save(bpLocToSave, function () { - bpLocToSave.set('json', me.customerAddr.serializeToJSON()); + bpLocToSave.set('json', customerAddr.serializeToJSON()); var successCallback, errorCallback, List; successCallback = function () { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerAddrSaved', [me.customerAddr.get('_identifier')])); + if (callback) { + callback(); + } + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerAddrSaved', [customerAddr.get('_identifier')])); }; customerAddrListToChange = new OB.Collection.ChangedBPlocationList(); customerAddrListToChange.add(bpLocToSave); OB.MobileApp.model.runSyncProcess(successCallback); }, function () { //error saving BP changes with changes in changedbusinesspartners - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrChn', [me.customerAddr.get('_identifier')])); + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrChn', [customerAddr.get('_identifier')])); }, isNew); } else { //save that the customer address is being processed by server - OB.Dal.save(this.customerAddr, function () { + OB.Dal.save(customerAddr, function () { // Update Default Address function errorCallback(tx, error) { @@ -69,9 +77,9 @@ function successCallbackBPs(dataBps) { if (dataBps.length === 0) { - OB.Dal.get(OB.Model.BusinessPartner, me.customerAddr.get('bpartner'), function success(dataBps) { - dataBps.set('locId', me.customerAddr.get('id')); - dataBps.set('locName', me.customerAddr.get('name')); + OB.Dal.get(OB.Model.BusinessPartner, customerAddr.get('bpartner'), function success(dataBps) { + dataBps.set('locId', customerAddr.get('id')); + dataBps.set('locName', customerAddr.get('name')); OB.Dal.save(dataBps, function () {}, function (tx) { OB.error(tx); }); @@ -81,35 +89,38 @@ } } var criteria = {}; - criteria._whereClause = "where c_bpartner_id = '" + me.customerAddr.get('bpartner') + "' and c_bpartnerlocation_id > '" + me.customerAddr.get('id') + "'"; + criteria._whereClause = "where c_bpartner_id = '" + customerAddr.get('bpartner') + "' and c_bpartnerlocation_id > '" + customerAddr.get('id') + "'"; criteria.params = []; OB.Dal.find(OB.Model.BusinessPartner, criteria, successCallbackBPs, errorCallback); if (isNew) { - me.customerAddr.set('posTerminal', OB.MobileApp.model.get('terminal').id); - bpLocToSave.set('json', JSON.stringify(me.customerAddr.serializeToJSON())); - bpLocToSave.set('c_bpartner_location_id', me.customerAddr.get('id')); + customerAddr.set('posTerminal', OB.MobileApp.model.get('terminal').id); + bpLocToSave.set('json', JSON.stringify(customerAddr.serializeToJSON())); + bpLocToSave.set('c_bpartner_location_id', customerAddr.get('id')); } bpLocToSave.set('isbeingprocessed', 'Y'); OB.Dal.save(bpLocToSave, function () { - bpLocToSave.set('json', me.customerAddr.serializeToJSON()); + bpLocToSave.set('json', customerAddr.serializeToJSON()); var successCallback, errorCallback, List; successCallback = function () { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerAddrSaved', [me.customerAddr.get('_identifier')])); + if (callback) { + callback(); + } + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerAddrSaved', [customerAddr.get('_identifier')])); }; customerAddrListToChange = new OB.Collection.ChangedBPlocationList(); customerAddrListToChange.add(bpLocToSave); OB.MobileApp.model.runSyncProcess(successCallback); }, function () { //error saving BP changes with changes in changedbusinesspartners - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrChn', [me.customerAddr.get('_identifier')])); + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrChn', [customerAddr.get('_identifier')])); }); }, function () { //error saving BP Location with new values in c_bpartner_location OB.error(arguments); - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrLocally', [me.customerAddr.get('_identifier')])); + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerAddrLocally', [customerAddr.get('_identifier')])); }); } - }, this); + }; }; }()); \ No newline at end of file diff --git a/web/org.openbravo.retail.posterminal/js/data/datacustomersave.js b/web/org.openbravo.retail.posterminal/js/data/datacustomersave.js --- a/web/org.openbravo.retail.posterminal/js/data/datacustomersave.js +++ b/web/org.openbravo.retail.posterminal/js/data/datacustomersave.js @@ -17,34 +17,37 @@ this.context = model; this.customer = model.get('customer'); + // trigger is from previous code, keeping it for backward compat + this.customer.on('customerSaved', function () { + OB.DATA.executeCustomerSave(this.customer); + }, this); - this.customer.on('customerSaved', function () { - var me = this, - customersList, customerId = this.customer.get('id'), + OB.DATA.executeCustomerSave = function (customer, callback) { + var customersList, customerId = this.customer.get('id'), isNew = false, bpToSave = new OB.Model.ChangedBusinessPartners(), bpLocation, bpLocToSave = new OB.Model.BPLocation(), customersListToChange; bpToSave.set('isbeingprocessed', 'N'); - this.customer.set('createdBy', OB.MobileApp.model.get('orgUserId')); + customer.set('createdBy', OB.MobileApp.model.get('orgUserId')); bpToSave.set('createdBy', OB.MobileApp.model.get('orgUserId')); if (customerId) { - this.customer.set('posTerminal', OB.MobileApp.model.get('terminal').id); - bpToSave.set('json', JSON.stringify(this.customer.serializeEditedToJSON())); - bpToSave.set('c_bpartner_id', this.customer.get('id')); + customer.set('posTerminal', OB.MobileApp.model.get('terminal').id); + bpToSave.set('json', JSON.stringify(customer.serializeEditedToJSON())); + bpToSave.set('c_bpartner_id', customer.get('id')); } else { isNew = true; } if (OB.MobileApp.model.hasPermission('OBPOS_remote.customer', true)) { //With high volume we only save localy when it is assigned to the order if (isNew) { - me.customer.set('posTerminal', OB.MobileApp.model.get('terminal').id); + customer.set('posTerminal', OB.MobileApp.model.get('terminal').id); var uuid = OB.UTIL.get_UUID(); - me.customer.set('id', uuid); - me.customer.id = uuid; - bpToSave.set('json', JSON.stringify(me.customer.serializeToJSON())); - bpToSave.set('id', me.customer.get('id')); + customer.set('id', uuid); + customer.id = uuid; + bpToSave.set('json', JSON.stringify(customer.serializeToJSON())); + bpToSave.set('id', customer.get('id')); } // the location is sent to the server as part of the BP save, but when the BP is @@ -54,12 +57,12 @@ // but this takes another request, that's why it is created here as an object if (!bpToSave.get('locationModel')) { bpLocation = new OB.Model.BPLocation(); - bpLocation.set('id', me.customer.get('locId')); - bpLocation.set('bpartner', me.customer.get('id')); - bpLocation.set('name', me.customer.get('locName')); - bpLocation.set('postalCode', me.customer.get('postalCode')); - bpLocation.set('cityName', me.customer.get('cityName')); - bpLocation.set('_identifier', me.customer.get('locName')); + bpLocation.set('id', customer.get('locId')); + bpLocation.set('bpartner', customer.get('id')); + bpLocation.set('name', customer.get('locName')); + bpLocation.set('postalCode', customer.get('postalCode')); + bpLocation.set('cityName', customer.get('cityName')); + bpLocation.set('_identifier', customer.get('locName')); bpLocation.set('countryName', OB.MobileApp.model.get('terminal').defaultbp_bpcountry_name); bpLocation.set('countryId', OB.MobileApp.model.get('terminal').defaultbp_bpcountry); bpToSave.set('locationModel', bpLocation); @@ -67,33 +70,36 @@ bpToSave.set('isbeingprocessed', 'Y'); OB.UTIL.HookManager.executeHooks('OBPOS_PostCustomerSave', { - customer: me.customer, + customer: customer, bpToSave: bpToSave }, function (args) { OB.Dal.save(bpToSave, function () { - bpToSave.set('json', me.customer.serializeToJSON()); + bpToSave.set('json', customer.serializeToJSON()); var successCallback = function () { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSaved', [me.customer.get('_identifier')])); + if (callback) { + callback(); + } + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSaved', [customer.get('_identifier')])); }; OB.MobileApp.model.runSyncProcess(successCallback); }, function () { //error saving BP changes with changes in changedbusinesspartners - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerChanges', [me.customer.get('_identifier')])); + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerChanges', [customer.get('_identifier')])); }, isNew); }); } else { //save that the customer is being processed by server - OB.Dal.save(this.customer, function () { - //OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSavedSuccessfullyLocally',[me.customer.get('_identifier')])); + OB.Dal.save(customer, function () { + //OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSavedSuccessfullyLocally',[customer.get('_identifier')])); // Saving Customer Address locally if (!isNew) { //load the BPlocation and then update it - OB.Dal.get(OB.Model.BPLocation, me.customer.get('locId'), function (bpLocToUpdate) { + OB.Dal.get(OB.Model.BPLocation, customer.get('locId'), function (bpLocToUpdate) { if (bpLocToUpdate) { - bpLocToUpdate.set('name', me.customer.get('locName')); - bpLocToUpdate.set('postalCode', me.customer.get('postalCode')); - bpLocToUpdate.set('cityName', me.customer.get('cityName')); - bpLocToUpdate.set('_identifier', me.customer.get('locName')); + bpLocToUpdate.set('name', customer.get('locName')); + bpLocToUpdate.set('postalCode', customer.get('postalCode')); + bpLocToUpdate.set('cityName', customer.get('cityName')); + bpLocToUpdate.set('_identifier', customer.get('locName')); OB.Dal.save(bpLocToUpdate, function () { //customer location updated successfully. Nothing to do here. }, function () { @@ -107,12 +113,12 @@ }); } else { //create bploc from scratch - bpLocToSave.set('id', me.customer.get('locId')); - bpLocToSave.set('bpartner', me.customer.get('id')); - bpLocToSave.set('name', me.customer.get('locName')); - bpLocToSave.set('postalCode', me.customer.get('postalCode')); - bpLocToSave.set('cityName', me.customer.get('cityName')); - bpLocToSave.set('_identifier', me.customer.get('locName')); + bpLocToSave.set('id', customer.get('locId')); + bpLocToSave.set('bpartner', customer.get('id')); + bpLocToSave.set('name', customer.get('locName')); + bpLocToSave.set('postalCode', customer.get('postalCode')); + bpLocToSave.set('cityName', customer.get('cityName')); + bpLocToSave.set('_identifier', customer.get('locName')); bpLocToSave.set('countryName', OB.MobileApp.model.get('terminal').defaultbp_bpcountry_name); bpLocToSave.set('countryId', OB.MobileApp.model.get('terminal').defaultbp_bpcountry); OB.Dal.save(bpLocToSave, function () { @@ -123,33 +129,36 @@ } if (isNew) { - me.customer.set('posTerminal', OB.MobileApp.model.get('terminal').id); - bpToSave.set('json', JSON.stringify(me.customer.serializeToJSON())); - bpToSave.set('c_bpartner_id', me.customer.get('id')); + customer.set('posTerminal', OB.MobileApp.model.get('terminal').id); + bpToSave.set('json', JSON.stringify(customer.serializeToJSON())); + bpToSave.set('c_bpartner_id', customer.get('id')); } bpToSave.set('isbeingprocessed', 'Y'); OB.UTIL.HookManager.executeHooks('OBPOS_PostCustomerSave', { - customer: me.customer, + customer: customer, bpToSave: bpToSave }, function (args) { OB.Dal.save(bpToSave, function () { - bpToSave.set('json', me.customer.serializeToJSON()); + bpToSave.set('json', customer.serializeToJSON()); var successCallback, errorCallback, List; successCallback = function () { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSaved', [me.customer.get('_identifier')])); + if (callback) { + callback(); + } + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_customerSaved', [customer.get('_identifier')])); }; OB.MobileApp.model.runSyncProcess(successCallback); }, function () { //error saving BP changes with changes in changedbusinesspartners - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerChanges', [me.customer.get('_identifier')])); + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerChanges', [customer.get('_identifier')])); }); }); }, function () { //error saving BP with new values in c_bpartner - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerLocally', [me.customer.get('_identifier')])); + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_errorSavingCustomerLocally', [customer.get('_identifier')])); }); } - }, this); + }; }; }()); \ No newline at end of file diff --git a/web/org.openbravo.retail.posterminal/js/data/dataordersave.js b/web/org.openbravo.retail.posterminal/js/data/dataordersave.js --- a/web/org.openbravo.retail.posterminal/js/data/dataordersave.js +++ b/web/org.openbravo.retail.posterminal/js/data/dataordersave.js @@ -69,292 +69,413 @@ }); // finished receipt verifications - this.receipt.on('closed', function (eventParams) { - this.receipt = model.get('order'); + var mainReceiptCloseFunction = function (eventParams) { + this.receipt = model.get('order'); + if (this.receipt.get('isbeingprocessed') === 'Y') { - if (this.receipt.get('isbeingprocessed') === 'Y') { - //The receipt has already been sent, it should not be sent again - return; - } + // clean up some synched data as this method is called in synchronized mode also + OB.MobileApp.model.resetCheckpointData(); + //The receipt has already been sent, it should not be sent again + return; + } - OB.info('Ticket closed: ', OB.UTIL.argumentsToStringifyed(this.receipt.getOrderDescription()), "caller: " + OB.UTIL.getStackTrace('Backbone.Events.trigger', true)); + OB.info('Ticket closed: ', OB.UTIL.argumentsToStringifyed(this.receipt.getOrderDescription()), "caller: " + OB.UTIL.getStackTrace('Backbone.Events.trigger', true)); - var orderDate = new Date(); - var normalizedCreationDate = OB.I18N.normalizeDate(this.receipt.get('creationDate')); - var creationDate; - if (normalizedCreationDate === null) { - creationDate = new Date(); - normalizedCreationDate = OB.I18N.normalizeDate(creationDate); - } else { - creationDate = new Date(normalizedCreationDate); - } + var orderDate = new Date(); + var normalizedCreationDate = OB.I18N.normalizeDate(this.receipt.get('creationDate')); + var creationDate; + if (normalizedCreationDate === null) { + creationDate = new Date(); + normalizedCreationDate = OB.I18N.normalizeDate(creationDate); + } else { + creationDate = new Date(normalizedCreationDate); + } - OB.trace('Executing pre order save hook.'); + OB.trace('Executing pre order save hook.'); - OB.UTIL.HookManager.executeHooks('OBPOS_PreOrderSave', { - context: this, - model: model, - receipt: model.get('order') - }, function (args) { - var receipt = args.context.receipt; - if (args && args.cancellation && args.cancellation === true) { - args.context.receipt.set('isbeingprocessed', 'N'); - args.context.receipt.set('hasbeenpaid', 'N'); - args.context.receipt.trigger('paymentCancel'); - if (eventParams && eventParams.callback) { - eventParams.callback({ - frozenReceipt: receipt, - isCancelled: true + OB.UTIL.HookManager.executeHooks('OBPOS_PreOrderSave', { + context: this, + model: model, + receipt: model.get('order') + }, function (args) { + var receipt = args.context.receipt; + if (args && args.cancellation && args.cancellation === true) { + args.context.receipt.set('isbeingprocessed', 'N'); + args.context.receipt.set('hasbeenpaid', 'N'); + args.context.receipt.trigger('paymentCancel'); + if (eventParams && eventParams.callback) { + eventParams.callback({ + frozenReceipt: receipt, + isCancelled: true + }); + } + args.context.receipt.setIsCalculateReceiptLockState(false); + args.context.receipt.setIsCalculateGrossLockState(false); + return true; + } + + if (OB.UTIL.RfidController.isRfidConfigured()) { + OB.UTIL.RfidController.processRemainingCodes(receipt); + OB.UTIL.RfidController.updateEpcBuffers(); + } + + OB.trace('Execution of pre order save hook OK.'); + delete receipt.attributes.json; + receipt.set('creationDate', normalizedCreationDate); + receipt.set('timezoneOffset', creationDate.getTimezoneOffset()); + receipt.set('created', creationDate.getTime()); + receipt.set('obposCreatedabsolute', OB.I18N.formatDateISO(creationDate)); + receipt.set('orderDate', orderDate); + receipt.set('movementDate', OB.I18N.normalizeDate(new Date())); + receipt.set('accountingDate', OB.I18N.normalizeDate(new Date())); + + // multiterminal support + // be sure that the active terminal is the one set as the order proprietary + receipt.set('posTerminal', OB.MobileApp.model.get('terminal').id); + receipt.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.MobileApp.model.get('terminal')._identifier); + + receipt.get("approvals").forEach(function (approval) { + if (typeof (approval.approvalType) === 'object') { + approval.approvalMessage = OB.I18N.getLabel(approval.approvalType.message, approval.approvalType.params); + approval.approvalType = approval.approvalType.approval; + } + }); + + receipt.set('obposAppCashup', OB.MobileApp.model.get('terminal').cashUpId); + // convert returns + if (receipt.getGross() < 0) { + _.forEach(receipt.get('payments').models, function (item) { + item.set('amount', -item.get('amount')); + item.set('origAmount', -item.get('origAmount')); + item.set('paid', -item.get('paid')); }); } - args.context.receipt.setIsCalculateReceiptLockState(false); - args.context.receipt.setIsCalculateGrossLockState(false); - return true; - } + receipt.set('json', JSON.stringify(receipt.serializeToJSON())); - if (OB.UTIL.RfidController.isRfidConfigured()) { - OB.UTIL.RfidController.processRemainingCodes(receipt); - OB.UTIL.RfidController.updateEpcBuffers(); - } + OB.trace('Calculationg cashup information.'); - OB.trace('Execution of pre order save hook OK.'); - delete receipt.attributes.json; - receipt.set('creationDate', normalizedCreationDate); - receipt.set('timezoneOffset', creationDate.getTimezoneOffset()); - receipt.set('created', creationDate.getTime()); - receipt.set('obposCreatedabsolute', OB.I18N.formatDateISO(creationDate)); - receipt.set('orderDate', orderDate); - receipt.set('movementDate', OB.I18N.normalizeDate(new Date())); - receipt.set('accountingDate', OB.I18N.normalizeDate(new Date())); - - // multiterminal support - // be sure that the active terminal is the one set as the order proprietary - receipt.set('posTerminal', OB.MobileApp.model.get('terminal').id); - receipt.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.MobileApp.model.get('terminal')._identifier); - - receipt.get("approvals").forEach(function (approval) { - if (typeof (approval.approvalType) === 'object') { - approval.approvalMessage = OB.I18N.getLabel(approval.approvalType.message, approval.approvalType.params); - approval.approvalType = approval.approvalType.approval; - } - }); - - receipt.set('obposAppCashup', OB.MobileApp.model.get('terminal').cashUpId); - // convert returns - if (receipt.getGross() < 0) { - _.forEach(receipt.get('payments').models, function (item) { - item.set('amount', -item.get('amount')); - item.set('origAmount', -item.get('origAmount')); - item.set('paid', -item.get('paid')); - }); - } - receipt.set('json', JSON.stringify(receipt.serializeToJSON())); - - OB.trace('Calculationg cashup information.'); - - // Important: at this point, the receipt is considered final. Nothing must alter it - var frozenReceipt = new OB.Model.Order(); - OB.UTIL.clone(receipt, frozenReceipt); - OB.info("[receipt.closed] Starting transaction. ReceiptId: " + receipt.get('id')); - OB.Dal.transaction(function (tx) { - receipt.set('hasbeenpaid', 'Y'); - frozenReceipt.set('hasbeenpaid', 'Y'); - // when all the properties of the receipt have been set, keep a copy - OB.UTIL.cashUpReport(receipt, function () { - OB.UTIL.calculateCurrentCash(null, tx); - OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(receipt.get('documentnoSuffix'), receipt.get('quotationnoSuffix'), receipt.get('returnnoSuffix'), function () { - OB.trace('Saving receipt.'); - OB.Dal.saveInTransaction(tx, receipt, function () { - // the trigger is fired on the receipt object, as there is only 1 that is being updated - receipt.trigger('integrityOk'); // Is important for module print last receipt. This module listen trigger. - }); + // Important: at this point, the receipt is considered final. Nothing must alter it + var frozenReceipt = new OB.Model.Order(); + OB.UTIL.clone(receipt, frozenReceipt); + OB.info("[receipt.closed] Starting transaction. ReceiptId: " + receipt.get('id')); + OB.Dal.transaction(function (tx) { + receipt.set('hasbeenpaid', 'Y'); + frozenReceipt.set('hasbeenpaid', 'Y'); + // when all the properties of the receipt have been set, keep a copy + OB.UTIL.cashUpReport(receipt, function () { + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.Dal.saveInTransaction(tx, receipt); + } else { + OB.UTIL.calculateCurrentCash(null, tx); + OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(receipt.get('documentnoSuffix'), receipt.get('quotationnoSuffix'), receipt.get('returnnoSuffix'), function () { + OB.trace('Saving receipt.'); + OB.Dal.saveInTransaction(tx, receipt, function () { + // the trigger is fired on the receipt object, as there is only 1 that is being updated + receipt.trigger('integrityOk'); // Is important for module print last receipt. This module listen trigger. + }); + }, tx); + } }, tx); - }, tx); - }, function () { - // the transaction failed - OB.error("[receipt.closed] The transaction failed to be commited. ReceiptId: " + receipt.get('id')); - // rollback other changes - receipt.set('hasbeenpaid', 'N'); - frozenReceipt.set('hasbeenpaid', 'N'); - if (eventParams && eventParams.callback) { - eventParams.callback({ - frozenReceipt: frozenReceipt, - isCancelled: false - }); - } - }, function () { - // success transaction... - OB.info("[receipt.closed] Transaction success. ReceiptId: " + receipt.get('id')); - - function serverMessageForQuotation(receipt) { - var isLayaway = (receipt.get('orderType') === 2 || receipt.get('isLayaway')); - var currentDocNo = receipt.get('documentNo'); - if (receipt && receipt.get('isQuotation')) { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_QuotationSaved', [currentDocNo])); - } else { - if (isLayaway) { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgLayawaySaved', [currentDocNo])); - } else { - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgReceiptSaved', [currentDocNo])); - } - } - - OB.trace('Order successfully removed.'); - } - - // create a clone of the receipt to be used when executing the final callback - if (OB.UTIL.HookManager.get('OBPOS_PostSyncReceipt')) { - // create a clone of the receipt to be used within the hook - var receiptForPostSyncReceipt = new OB.Model.Order(); - OB.UTIL.clone(receipt, receiptForPostSyncReceipt); - //If there are elements in the hook, we are forced to execute the callback only after the synchronization process - //has been executed, to prevent race conditions with the callback processes (printing and deleting the receipt) - OB.trace('Execution Sync process.'); - - OB.MobileApp.model.runSyncProcess(function () { - OB.UTIL.HookManager.executeHooks('OBPOS_PostSyncReceipt', { - receipt: receiptForPostSyncReceipt - }, function () { - serverMessageForQuotation(receipt); - if (eventParams && eventParams.callback) { - eventParams.callback({ - frozenReceipt: frozenReceipt, - isCancelled: false - }); - } - }); - }, function () { - OB.UTIL.HookManager.executeHooks('OBPOS_PostSyncReceipt', { - receipt: receiptForPostSyncReceipt - }, function () { - if (eventParams && eventParams.callback) { - eventParams.callback({ - frozenReceipt: frozenReceipt, - isCancelled: false - }); - } - }); - }); - } else { - OB.trace('Execution Sync process.'); - //If there are no elements in the hook, we can execute the callback asynchronusly with the synchronization process + }, function () { + // the transaction failed + OB.error("[receipt.closed] The transaction failed to be commited. ReceiptId: " + receipt.get('id')); + // rollback other changes + receipt.set('hasbeenpaid', 'N'); + frozenReceipt.set('hasbeenpaid', 'N'); if (eventParams && eventParams.callback) { eventParams.callback({ frozenReceipt: frozenReceipt, isCancelled: false }); } - OB.MobileApp.model.runSyncProcess(function () { - serverMessageForQuotation(frozenReceipt); - OB.debug("Ticket closed: runSyncProcess executed"); - }); + }, function () { + // success transaction... + OB.info("[receipt.closed] Transaction success. ReceiptId: " + receipt.get('id')); + + function serverMessageForQuotation(receipt) { + var isLayaway = (receipt.get('orderType') === 2 || receipt.get('isLayaway')); + var currentDocNo = receipt.get('documentNo'); + if (receipt && receipt.get('isQuotation')) { + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_QuotationSaved', [currentDocNo])); + } else { + if (isLayaway) { + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgLayawaySaved', [currentDocNo])); + } else { + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgReceiptSaved', [currentDocNo])); + } + } + + OB.trace('Order successfully removed.'); + } + + var synErrorCallback = function () { + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + // rollback other changes + receipt.set('hasbeenpaid', 'N'); + frozenReceipt.set('hasbeenpaid', 'N'); + + OB.Dal.save(receipt, function () { + OB.UTIL.calculateCurrentCash(); + + if (eventParams && eventParams.callback) { + eventParams.callback({ + frozenReceipt: frozenReceipt, + isCancelled: true + }); + receipt.trigger('paymentCancel'); + } + }, null, false); + } else if (eventParams && eventParams.callback) { + eventParams.callback({ + frozenReceipt: frozenReceipt, + isCancelled: false + }); + } + }; + + // create a clone of the receipt to be used when executing the final callback + if (OB.UTIL.HookManager.get('OBPOS_PostSyncReceipt')) { + // create a clone of the receipt to be used within the hook + var receiptForPostSyncReceipt = new OB.Model.Order(); + OB.UTIL.clone(receipt, receiptForPostSyncReceipt); + //If there are elements in the hook, we are forced to execute the callback only after the synchronization process + //has been executed, to prevent race conditions with the callback processes (printing and deleting the receipt) + OB.trace('Execution Sync process.'); + + OB.MobileApp.model.runSyncProcess(function () { + var successStep = function () { + OB.UTIL.HookManager.executeHooks('OBPOS_PostSyncReceipt', { + receipt: receiptForPostSyncReceipt + }, function () { + serverMessageForQuotation(receipt); + if (eventParams && eventParams.callback) { + eventParams.callback({ + frozenReceipt: frozenReceipt, + isCancelled: false + }); + } + }); + }; + + // in synchronized mode do the doc sequence update in the success + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.UTIL.calculateCurrentCash(); + OB.Dal.transaction(function (tx) { + OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(receipt.get('documentnoSuffix'), receipt.get('quotationnoSuffix'), receipt.get('returnnoSuffix'), function () { + OB.trace('Saving receipt.'); + OB.Dal.saveInTransaction(tx, receipt, function () { + // the trigger is fired on the receipt object, as there is only 1 that is being updated + receipt.trigger('integrityOk'); // Is important for module print last receipt. This module listen trigger. + successStep(); + }); + }, tx); + }); + } else { + successStep(); + } + }, function () { + OB.UTIL.HookManager.executeHooks('OBPOS_PostSyncReceipt', { + receipt: receiptForPostSyncReceipt + }, synErrorCallback); + }); + } else { + OB.trace('Execution Sync process.'); + //If there are no elements in the hook, we can execute the callback asynchronusly with the synchronization process + // for non-sync do it here, for sync do it in the success callback of runsyncprocess + if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true) && eventParams && eventParams.callback) { + eventParams.callback({ + frozenReceipt: frozenReceipt, + isCancelled: false + }); + } + OB.MobileApp.model.runSyncProcess(function () { + // in synchronized mode do the doc sequence update in the success and navigate back + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.UTIL.calculateCurrentCash(); + OB.Dal.transaction(function (tx) { + OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(receipt.get('documentnoSuffix'), receipt.get('quotationnoSuffix'), receipt.get('returnnoSuffix'), function () { + OB.trace('Saving receipt.'); + OB.Dal.saveInTransaction(tx, receipt, function () { + // the trigger is fired on the receipt object, as there is only 1 that is being updated + receipt.trigger('integrityOk'); // Is important for module print last receipt. This module listen trigger. + if (eventParams && eventParams.callback) { + eventParams.callback({ + frozenReceipt: frozenReceipt, + isCancelled: false + }); + } + }); + }, tx); + }); + } + + serverMessageForQuotation(frozenReceipt); + OB.debug("Ticket closed: runSyncProcess executed"); + }, synErrorCallback); + } + }); + }); + }; + + this.receipt.on('closed', function (eventParams) { + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.MobileApp.model.setSynchronizedCheckpoint(function () { + mainReceiptCloseFunction(eventParams); + }); + } else { + mainReceiptCloseFunction(eventParams); + } + }, this); + + var multiOrdersFunction = function (receipt, me) { + var synchId = OB.UTIL.SynchronizationHelper.busyUntilFinishes("multiOrdersClosed"); + + OB.info('Multiorders ticket closed', receipt, "caller: " + OB.UTIL.getStackTrace('Backbone.Events.trigger', true)); + + if (!_.isUndefined(receipt)) { + me.receipt = receipt; + } + var receiptId = me.receipt.get('id'); + + var normalizedCreationDate = OB.I18N.normalizeDate(me.receipt.get('creationDate')); + var creationDate; + if (normalizedCreationDate === null) { + creationDate = new Date(); + normalizedCreationDate = OB.I18N.normalizeDate(creationDate); + } else { + creationDate = new Date(normalizedCreationDate); + } + + me.receipt.set('creationDate', normalizedCreationDate); + me.receipt.set('movementDate', OB.I18N.normalizeDate(new Date())); + me.receipt.set('accountingDate', OB.I18N.normalizeDate(new Date())); + me.receipt.set('hasbeenpaid', 'Y'); + me.context.get('multiOrders').trigger('integrityOk', me.receipt); + + if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.UTIL.calculateCurrentCash(); + me.context.get('multiOrders').trigger('integrityOk', me.receipt); + OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(me.receipt.get('documentnoSuffix'), me.receipt.get('quotationnoSuffix'), receipt.get('returnnoSuffix')); + } + + delete me.receipt.attributes.json; + me.receipt.set('timezoneOffset', creationDate.getTimezoneOffset()); + me.receipt.set('created', creationDate.getTime()); + me.receipt.set('obposCreatedabsolute', OB.I18N.formatDateISO(creationDate)); // Absolute date in ISO format + // multiterminal support + // be sure that the active terminal is the one set as the order proprietary + receipt.set('posTerminal', OB.MobileApp.model.get('terminal').id); + receipt.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.MobileApp.model.get('terminal')._identifier); + + me.receipt.set('obposAppCashup', OB.MobileApp.model.get('terminal').cashUpId); + me.receipt.set('json', JSON.stringify(me.receipt.serializeToJSON())); + + OB.trace('Executing pre order save hook.'); + + OB.UTIL.HookManager.executeHooks('OBPOS_PreOrderSave', { + context: this, + model: model, + receipt: me.receipt + }, function (args) { + + OB.trace('Execution of pre order save hook OK.'); + if (args && args.cancellation && args.cancellation === true) { + args.context.receipt.set('isbeingprocessed', 'N'); + OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); + return true; } + + OB.trace('Saving receipt.'); + + OB.Dal.save(me.receipt, function () { + OB.Dal.get(OB.Model.Order, receiptId, function (receipt) { + + var successCallback = function () { + OB.trace('Sync process success.'); + + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + + enyo.$.scrim.hide(); + + OB.UTIL.calculateCurrentCash(); + _.each(model.get('multiOrders').get('multiOrdersList').models, function (theReceipt) { + me.context.get('multiOrders').trigger('print', theReceipt, { + offline: true + }); + me.context.get('multiOrders').trigger('integrityOk', theReceipt); + OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(theReceipt.get('documentnoSuffix'), theReceipt.get('quotationnoSuffix'), receipt.get('returnnoSuffix')); + }); + + OB.UTIL.cashUpReport(model.get('multiOrders').get('multiOrdersList').models); + + //this logic executed when all orders are ready to be sent + me.context.get('leftColumnViewManager').setOrderMode(); + if (me.context.get('orderList').length > _.filter(me.context.get('multiOrders').get('multiOrdersList').models, function (order) { + return !order.get('isLayaway'); + }).length) { + me.context.get('orderList').addNewOrder(); + } + } + + model.get('multiOrders').resetValues(); + + OB.UTIL.showLoading(false); + if (me.hasInvLayaways) { + OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_noInvoiceIfLayaway')); + me.hasInvLayaways = false; + } + OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgAllReceiptSaved')); + OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); + }; + + var errorCallback = function () { + OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgAllReceiptNotSaved')); + OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); + + + // recalculate after an error also + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.UTIL.calculateCurrentCash(); + } + model.get('multiOrders').resetValues(); + }; + + if (!_.isUndefined(receipt.get('amountToLayaway')) && !_.isNull(receipt.get('amountToLayaway')) && receipt.get('generateInvoice')) { + me.hasInvLayaways = true; + } + model.get('orderList').current = receipt; + model.get('orderList').deleteCurrent(); + me.ordersToSend += 1; + if (model.get('multiOrders').get('multiOrdersList').length === me.ordersToSend) { + OB.trace('Execution Sync process.'); + + OB.MobileApp.model.runSyncProcess(successCallback, errorCallback); + me.ordersToSend = OB.DEC.Zero; + } else { + OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); + } + + }, null); + }, function () { + // We do nothing: + // we don't need to alert the user, as the order is still present in the database, so it will be resent as soon as the user logs in again + OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); + }); }); - }); - }, this); + }; this.context.get('multiOrders').on('closed', function (receipt) { - var synchId = OB.UTIL.SynchronizationHelper.busyUntilFinishes("multiOrdersClosed"); + var me = this; - OB.info('Multiorders ticket closed', receipt, "caller: " + OB.UTIL.getStackTrace('Backbone.Events.trigger', true)); - - var me = this; - if (!_.isUndefined(receipt)) { - this.receipt = receipt; + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true) && me.ordersToSend === 0) { + OB.MobileApp.model.setSynchronizedCheckpoint(function () { + multiOrdersFunction(receipt, me); + }); + } else { + multiOrdersFunction(receipt, me); } - var receiptId = this.receipt.get('id'); - - var normalizedCreationDate = OB.I18N.normalizeDate(this.receipt.get('creationDate')); - var creationDate; - if (normalizedCreationDate === null) { - creationDate = new Date(); - normalizedCreationDate = OB.I18N.normalizeDate(creationDate); - } else { - creationDate = new Date(normalizedCreationDate); - } - - this.receipt.set('creationDate', normalizedCreationDate); - this.receipt.set('movementDate', OB.I18N.normalizeDate(new Date())); - this.receipt.set('accountingDate', OB.I18N.normalizeDate(new Date())); - this.receipt.set('hasbeenpaid', 'Y'); - this.context.get('multiOrders').trigger('integrityOk', this.receipt); - OB.UTIL.calculateCurrentCash(); - OB.MobileApp.model.updateDocumentSequenceWhenOrderSaved(this.receipt.get('documentnoSuffix'), this.receipt.get('quotationnoSuffix'), this.receipt.get('returnnoSuffix')); - - delete this.receipt.attributes.json; - this.receipt.set('timezoneOffset', creationDate.getTimezoneOffset()); - this.receipt.set('created', creationDate.getTime()); - this.receipt.set('obposCreatedabsolute', OB.I18N.formatDateISO(creationDate)); // Absolute date in ISO format - // multiterminal support - // be sure that the active terminal is the one set as the order proprietary - receipt.set('posTerminal', OB.MobileApp.model.get('terminal').id); - receipt.set('posTerminal' + OB.Constants.FIELDSEPARATOR + OB.Constants.IDENTIFIER, OB.MobileApp.model.get('terminal')._identifier); - - this.receipt.set('obposAppCashup', OB.MobileApp.model.get('terminal').cashUpId); - this.receipt.set('json', JSON.stringify(this.receipt.serializeToJSON())); - - OB.trace('Executing pre order save hook.'); - - OB.UTIL.HookManager.executeHooks('OBPOS_PreOrderSave', { - context: this, - model: model, - receipt: this.receipt - }, function (args) { - - OB.trace('Execution of pre order save hook OK.'); - if (args && args.cancellation && args.cancellation === true) { - args.context.receipt.set('isbeingprocessed', 'N'); - OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); - return true; - } - - OB.trace('Saving receipt.'); - - OB.Dal.save(me.receipt, function () { - OB.Dal.get(OB.Model.Order, receiptId, function (receipt) { - - var successCallback = function () { - OB.trace('Sync process success.'); - OB.UTIL.showLoading(false); - if (me.hasInvLayaways) { - OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_noInvoiceIfLayaway')); - me.hasInvLayaways = false; - } - OB.UTIL.showSuccess(OB.I18N.getLabel('OBPOS_MsgAllReceiptSaved')); - OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); - }; - - var errorCallback = function () { - OB.UTIL.showError(OB.I18N.getLabel('OBPOS_MsgAllReceiptNotSaved')); - OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); - }; - - if (!_.isUndefined(receipt.get('amountToLayaway')) && !_.isNull(receipt.get('amountToLayaway')) && receipt.get('generateInvoice')) { - me.hasInvLayaways = true; - } - model.get('orderList').current = receipt; - model.get('orderList').deleteCurrent(); - me.ordersToSend += 1; - if (model.get('multiOrders').get('multiOrdersList').length === me.ordersToSend) { - model.get('multiOrders').resetValues(); - - OB.trace('Execution Sync process.'); - - OB.MobileApp.model.runSyncProcess(successCallback, errorCallback); - me.ordersToSend = OB.DEC.Zero; - } else { - OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); - } - - }, null); - }, function () { - // We do nothing: - // we don't need to alert the user, as the order is still present in the database, so it will be resent as soon as the user logs in again - OB.UTIL.SynchronizationHelper.finished(synchId, "multiOrdersClosed"); - }); - }); }, this); }; diff --git a/web/org.openbravo.retail.posterminal/js/login/model/login-model.js b/web/org.openbravo.retail.posterminal/js/login/model/login-model.js --- a/web/org.openbravo.retail.posterminal/js/login/model/login-model.js +++ b/web/org.openbravo.retail.posterminal/js/login/model/login-model.js @@ -360,13 +360,23 @@ if (dataToSync.length === 1 && this.model === OB.Model.CashUp && localStorage.lastCashupInfo === dataToSync.models[0].get('objToSend')) { me.skipSyncModel = true; } - localStorage.lastCashupInfo = dataToSync.models[0].get('objToSend'); + localStorage.lastCashupSendInfo = dataToSync.models[0].get('objToSend'); + }, + // keep track of successfull send + successSendModel: function () { + localStorage.lastCashupInfo = localStorage.lastCashupSendInfo; } }); this.on('ready', function () { OB.debug("next process: 'retail.pointofsale' window"); + // register models which are cached during synchronized transactions + OB.MobileApp.model.addSyncCheckpointModel(OB.Model.Order); + OB.MobileApp.model.addSyncCheckpointModel(OB.Model.PaymentMethodCashUp); + OB.MobileApp.model.addSyncCheckpointModel(OB.Model.TaxCashUp); + OB.MobileApp.model.addSyncCheckpointModel(OB.Model.CashUp); + var terminal = this.get('terminal'); OB.UTIL.initCashUp(OB.UTIL.calculateCurrentCash); // Set Hardware.. diff --git a/web/org.openbravo.retail.posterminal/js/model/bplocation.js b/web/org.openbravo.retail.posterminal/js/model/bplocation.js --- a/web/org.openbravo.retail.posterminal/js/model/bplocation.js +++ b/web/org.openbravo.retail.posterminal/js/model/bplocation.js @@ -1,6 +1,6 @@ /* ************************************************************************************ - * Copyright (C) 2012-2015 Openbravo S.L.U. + * Copyright (C) 2012-2016 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. @@ -21,14 +21,19 @@ dataLimit: OB.Dal.DATALIMIT, local: false, remote: 'OBPOS_remote.customer', - saveCustomerAddr: function (silent) { + saveCustomerAddr: function (callback) { var nameLength, newSk; this.set('_identifier', this.get('name')); - this.trigger('customerAddrSaved'); + + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.DATA.executeCustomerAddressSave(this, callback); + } else { + this.trigger('customerAddrSaved'); + callback(); + } + return true; - //datacustomeraddrsave will catch this event and save this locally with changed = 'Y' - //Then it will try to send to the backend }, loadById: function (CusAddrId, userCallback) { //search data in local DB and load it to this diff --git a/web/org.openbravo.retail.posterminal/js/model/businesspartner.js b/web/org.openbravo.retail.posterminal/js/model/businesspartner.js --- a/web/org.openbravo.retail.posterminal/js/model/businesspartner.js +++ b/web/org.openbravo.retail.posterminal/js/model/businesspartner.js @@ -18,7 +18,7 @@ source: 'org.openbravo.retail.posterminal.master.BusinessPartner', dataLimit: OB.Dal.DATALIMIT, remote: 'OBPOS_remote.customer', - saveCustomer: function (silent) { + saveCustomer: function (callback) { var nameLength, newSk; if (!this.get("name")) { @@ -50,9 +50,13 @@ this.set('_identifier', this.get('name')); - this.trigger('customerSaved'); - //datacustomersave will catch this event and save this locally with changed = 'Y' - //Then it will try to send to the backend + // in case of synchronized then directly call customer save with the callback + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + OB.DATA.executeCustomerSave(this, callback); + } else { + this.trigger('customerSaved'); + callback(); + } return true; }, loadById: function (CusId, userCallback) { diff --git a/web/org.openbravo.retail.posterminal/js/pointofsale/model/pointofsale-model.js b/web/org.openbravo.retail.posterminal/js/pointofsale/model/pointofsale-model.js --- a/web/org.openbravo.retail.posterminal/js/pointofsale/model/pointofsale-model.js +++ b/web/org.openbravo.retail.posterminal/js/pointofsale/model/pointofsale-model.js @@ -496,16 +496,18 @@ } } me.get('multiOrders').trigger('closed', order); - enyo.$.scrim.hide(); - me.get('multiOrders').trigger('print', order, { - offline: true - }); // to guaranty execution order - SyncReadyToSendFunction(); + if (!OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + enyo.$.scrim.hide(); + me.get('multiOrders').trigger('print', order, { + offline: true + }); // to guaranty execution order + SyncReadyToSendFunction(); - auxReceiptList.push(auxReceipt); - if (auxReceiptList.length === me.get('multiOrders').get('multiOrdersList').length) { - OB.UTIL.cashUpReport(auxReceiptList); - auxReceiptList = []; + auxReceiptList.push(auxReceipt); + if (auxReceiptList.length === me.get('multiOrders').get('multiOrdersList').length) { + OB.UTIL.cashUpReport(auxReceiptList); + auxReceiptList = []; + } } } var i, j; diff --git a/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customeraddress/components/sharedcomponents.js b/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customeraddress/components/sharedcomponents.js --- a/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customeraddress/components/sharedcomponents.js +++ b/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customeraddress/components/sharedcomponents.js @@ -1,6 +1,6 @@ /* ************************************************************************************ - * Copyright (C) 2012 Openbravo S.L.U. + * Copyright (C) 2012-2016 Openbravo S.L.U. * Licensed under the Openbravo Commercial License version 1.0 * You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html * or in the legal folder of this module distribution. @@ -174,11 +174,14 @@ if (this.model.get('customerAddr').get('name') === '') { OB.UTIL.showWarning('Address is required for BPartner'); return false; - } else if (this.model.get('customerAddr').saveCustomerAddr()) { - goToViewWindow(sw, { - customer: OB.UTIL.clone(this.customer), - customerAddr: OB.UTIL.clone(this.model.get('customerAddr')) - }); + } else { + var callback = function () { + goToViewWindow(sw, { + customer: OB.UTIL.clone(me.customer), + customerAddr: OB.UTIL.clone(me.model.get('customerAddr')) + }); + }; + this.model.get('customerAddr').saveCustomerAddr(callback); } } else { this.model.get('customerAddr').loadById(this.customerAddr.get('id'), function (customerAddr) { @@ -186,28 +189,30 @@ OB.UTIL.showWarning(OB.I18N.getLabel('OBPOS_BPartnerAddressRequired')); return false; } else { + var callback = function () { + goToViewWindow(sw, { + customer: me.customer, + customerAddr: customerAddr + }); + if (customerAddr.get('id') === me.customer.get("locId")) { + me.customer.set('locId', customerAddr.get('id')); + me.customer.set('locName', customerAddr.get('name')); + me.customer.set('locationModel', customerAddr); + OB.Dal.save(me.customer, function success(tx) { + me.doChangeBusinessPartner({ + businessPartner: me.customer + }); + }, function error(tx) { + OB.error(tx); + }); + + } + + }; getCustomerAddrValues({ customerAddr: customerAddr }); - if (customerAddr.saveCustomerAddr()) { - goToViewWindow(sw, { - customer: me.customer, - customerAddr: customerAddr - }); - if (customerAddr.get('id') === me.customer.get("locId")) { - me.customer.set('locId', customerAddr.get('id')); - me.customer.set('locName', customerAddr.get('name')); - me.customer.set('locationModel', customerAddr); - OB.Dal.save(me.customer, function success(tx) { - me.doChangeBusinessPartner({ - businessPartner: me.customer - }); - }, function error(tx) { - OB.error(tx); - }); - - } - } + customerAddr.saveCustomerAddr(callback); } }); } diff --git a/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customers/components/sharedcomponents.js b/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customers/components/sharedcomponents.js --- a/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customers/components/sharedcomponents.js +++ b/web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customers/components/sharedcomponents.js @@ -244,12 +244,11 @@ if (args && args.cancellation && args.cancellation === true) { return true; } - var success = args.customer.saveCustomer(); - if (success) { + args.customer.saveCustomer(function () { goToViewWindow(sw, { customer: OB.UTIL.clone(args.customer) }); - } + }); }); } else { var that = this; @@ -265,12 +264,11 @@ if (args && args.cancellation && args.cancellation === true) { return true; } - var success = args.customer.saveCustomer(); - if (success) { + args.customer.saveCustomer(function () { goToViewWindow(sw, { customer: args.customer }); - } + }); }); }); } diff --git a/web/org.openbravo.retail.posterminal/js/utils/cashUpReportUtils.js b/web/org.openbravo.retail.posterminal/js/utils/cashUpReportUtils.js --- a/web/org.openbravo.retail.posterminal/js/utils/cashUpReportUtils.js +++ b/web/org.openbravo.retail.posterminal/js/utils/cashUpReportUtils.js @@ -359,6 +359,45 @@ }, this); }; + // 1. call server for cashup info + // 2. when returns delete current cashup info + // 3. recreate + OB.UTIL.rebuildCashupFromServer = function (callback) { + var service = 'org.openbravo.retail.posterminal.master.Cashup'; + if (OB.MobileApp.model.hasPermission('OBMOBC_SynchronizedMode', true)) { + service = 'org.openbravo.retail.posterminal.master.CashupSynchronized'; + } + new OB.DS.Process(service).exec({ + isprocessed: 'N', + isprocessedbo: 'N' + }, function (data) { + var afterDeleteCallback = function () { + // Found non processed cashups + if (data[0]) { + var cashUp = new OB.Model.CashUp(); + cashUp.set(data[0]); + var cashUpCollection = new Backbone.Collection(); + cashUpCollection.push(cashUp); + OB.UTIL.createNewCashupFromServer(cashUp, function () { + OB.UTIL.composeCashupInfo(cashUpCollection, null, null); + OB.UTIL.calculateCurrentCash(callback); + }); + } else { + OB.UTIL.createNewCashup(callback); + } + }; + + // remove the current cashup + OB.Dal.transaction(function (tx) { + OB.Dal.removeAllInTransaction(tx, OB.Model.PaymentMethodCashUp); + OB.Dal.removeAllInTransaction(tx, OB.Model.TaxCashUp); + OB.Dal.removeAllInTransaction(tx, OB.Model.CashUp); + OB.Dal.removeAllInTransaction(tx, OB.Model.CashManagement); + }, null, afterDeleteCallback); + + }); + }; + OB.UTIL.initCashUp = function (callback, errorCallback, skipSearchBackend) { //1. Search non processed cashup in local DB | |||||||
Relationships [ Relation Graph ] [ Dependency Graph ] | |||||||||||||||||||||||||||||
|
Notes | |
(0083921) hgbot (developer) 2016-02-04 11:26 |
Repository: tools/automation/pi-mobile Changeset: eb20d02a4e51f0a8b80e493b58fd3c6fb6900552 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Thu Feb 04 11:26:23 2016 +0100 URL: http://code.openbravo.com/tools/automation/pi-mobile/rev/eb20d02a4e51f0a8b80e493b58fd3c6fb6900552 [^] Related to issue 31655: Process a synchronious order --- A src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java --- |
(0083988) hgbot (developer) 2016-02-05 19:30 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: b296383fd9f307d2bc4d980edddd58b2c62da796 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Fri Feb 05 19:29:20 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/b296383fd9f307d2bc4d980edddd58b2c62da796 [^] Fixed issue 0031655: WebPOS Synchronous transactions - Create the reference for the OrderLoader preference - Set it in the model --- M src-db/database/sourcedata/AD_REF_LIST.xml M web/org.openbravo.retail.posterminal/js/login/model/login-model.js --- |
(0083989) hgbot (developer) 2016-02-05 19:31 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: b4f987dcae8ef3ea097c57505c3cd9aad80c38de Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Fri Feb 05 19:28:02 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/b4f987dcae8ef3ea097c57505c3cd9aad80c38de [^] Fixed issue 0031655: WebPOS Synchronous transactions - Check if the request is shynchronized and in that case, process the import Entry and send bach the response - Set error = true to send back the message error - If it is a synchronized request, show Loading... window in the call and hide in the response - In the response, show error message if exists and continue executing the callback - Set in the request if is synched or not depending on the preference defined on the model - Save the status of the Loading... window and the change time --- M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M web/org.openbravo.mobile.core/source/data/ob-requestrouter.js M web/org.openbravo.mobile.core/source/model/ob-terminal-model.js M web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js --- |
(0084004) Orekaria (administrator) 2016-02-08 15:18 |
Null pointer exception when running the 'I30897_InactiveStorageBinConsidered' test: java.lang.AssertionError: 1 Errors in the OBPOS_Errors table while importing POS data: >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ORG --> D270A5AC50874F8BA67A88EE977F8E3B TYPEOFDATA --> Order ERROR --> java.lang.NullPointerException at org.openbravo.mobile.core.process.DataSynchronizationProcess.isSynchronizedRequest(DataSynchronizationProcess.java:107) at org.openbravo.mobile.core.process.DataSynchronizationProcess.saveRecord(DataSynchronizationProcess.java:282) at org.openbravo.mobile.core.process.DataSynchronizationProcess.exec(DataSynchronizationProcess.java:198) at org.openbravo.mobile.core.process.DataSynchronizationProcess.exec(DataSynchronizationProcess.java:98) at org.openbravo.mobile.core.process.MobileImportEntryProcessorRunnable.processEntry(MobileImportEntryProcessorRunnable.java:41) at org.openbravo.retail.posterminal.importprocess.OrderImportEntryProcessor$OrderLoaderRunnable.processEntry(OrderImportEntryProcessor.java:59) at org.openbravo.service.importprocess.ImportEntryProcessor$ImportEntryProcessRunnable.doRunCycle(ImportEntryProcessor.java:370) at org.openbravo.service.importprocess.ImportEntryProcessor$ImportEntryProcessRunnable.run(ImportEntryProcessor.java:292) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) |
(0084024) hgbot (developer) 2016-02-09 08:30 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: f0a9d720baf1aa2f0a6395853d52bd897a4e65b8 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Feb 09 08:30:17 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/f0a9d720baf1aa2f0a6395853d52bd897a4e65b8 [^] Fixed issue 0031655: WebPOS Synchronous transactions - Access to isSynchronized from Utils --- M src/org/openbravo/retail/posterminal/ExternalOrderLoader.java M src/org/openbravo/retail/posterminal/ExternalOrderLoaderErrorHandler.java --- |
(0084025) hgbot (developer) 2016-02-09 08:31 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: 2f792e3dea76183e6f509f7d8e00c245c449c52a Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Feb 09 08:29:09 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/2f792e3dea76183e6f509f7d8e00c245c449c52a [^] Fixed issue 0031655: WebPOS Synchronous transactions - Check if request is null - Put isSynchronized in utils --- M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M src/org/openbravo/mobile/core/utils/OBMOBCUtils.java --- |
(0084293) migueldejuana (developer) 2016-02-17 15:53 |
When an order fails, we must see the sent order in Web POS and be able to fix whatever we need. |
(0084420) hgbot (developer) 2016-02-23 13:13 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: 3bf463fe8806345b3f83ee212312708d43a27c5b Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Mon Feb 22 16:49:22 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/3bf463fe8806345b3f83ee212312708d43a27c5b [^] Fixed issue 0031655: WebPOS Synchronous transactions - Handle order error in requestrouter --- M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M web/org.openbravo.mobile.core/source/data/ob-requestrouter.js M web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js --- |
(0084421) hgbot (developer) 2016-02-23 13:14 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: 33e591f858d262185703fed85d0db09f0993f683 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Mon Feb 22 16:53:05 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/33e591f858d262185703fed85d0db09f0993f683 [^] Fixed issue 0031655: WebPOS Synchronous transactions - Handle order loader error --- M src/org/openbravo/retail/posterminal/OBPOSComponentProvider.java M web/org.openbravo.retail.posterminal/js/data/dataordersave.js A web/org.openbravo.retail.posterminal/js/data/synchronizedorder.js --- |
(0084430) hgbot (developer) 2016-02-23 14:07 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: abb22a9df9f9749d3fac366001c472ec155faeff Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Feb 23 14:06:33 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/abb22a9df9f9749d3fac366001c472ec155faeff [^] Fixed issue 0031655: WebPOS Synchronous transactions - Update copyright --- M web/org.openbravo.retail.posterminal/js/data/dataordersave.js --- |
(0084574) mtaal (manager) 2016-02-27 08:53 |
http://wiki.openbravo.com/wiki/Retail:Configuration_Guide#Synchronized_order [^] |
(0084586) mtaal (manager) 2016-02-29 11:12 |
I tested on multi-server with two servers, I forced an exception in the Orderloader if the order has more than 2 lines (central) or more than 1 line (store). In this way I can force errors on different servers. What I noticed: - when I force an error on central but not on store I get a message: 'Some records can not be saved'. This eventhough the order was correctly saved on the store server - in this case the order remains in webpos but with the done button disabled. The order should have gone away as at least one message succeeded. - when I force an error on both central and store I get a js error (see below). In this case the message should have been displayed, the done button should remain green. Also it should be possible to change the order, add/remove lines. I felt that when I added lines after the message that the order amount was not updated. TypeError: Cannot read property 'scale' of undefined at toNumber (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:10648:14 [^]) at Object.OB.DEC.toNumber (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:10708:12 [^]) at null.<anonymous> (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:21407:53 [^]) at Array.forEach (native) at Function._.each._.forEach (http://store1.openbravo.com:8080/openbravo/web/org.openbravo.mobile.core/lib/vendor/underscore-1.3.3.js:76:11 [^]) at Collection.(anonymous function) [as each] (http://store1.openbravo.com:8080/openbravo/web/org.openbravo.mobile.core/lib/vendor/backbone-0.9.2.js:859:24 [^]) at Backbone.Model.extend.adjustPrices (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:21363:25 [^]) at Backbone.Model.extend.prepareToSend (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:21354:12 [^]) at null.<anonymous> (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:41076:15 [^]) at Backbone.Events.trigger (http://store1.openbravo.com:8080/openbravo/web/org.openbravo.mobile.core/lib/vendor/backbone-0.9.2.js:163:27 [^]); line: Object.OB.UTIL.showError (http://store1.openbravo.com:8080/openbravo/web/js/gen/b76329f659e11b7887488d647958ba58_WebPOS.js:10373:6 [^]) (*,+)processConsoleLevel @ b76329f659e11b7887488d647958ba58_WebPOS.js:2589 b76329f659e11b7887488d647958ba58_WebPOS.js:10648 Uncaught TypeError: Cannot read property 'scale' of undefined |
(0084623) hgbot (developer) 2016-03-01 14:29 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: a9e5e34471e3ffede3f5b1c3cd7909e5e20de1e8 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:20:31 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/a9e5e34471e3ffede3f5b1c3cd7909e5e20de1e8 [^] Related to issue 31655: Backout 1903 --- M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M web/org.openbravo.mobile.core/source/data/ob-requestrouter.js M web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js --- |
(0084624) hgbot (developer) 2016-03-01 14:29 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: 927c7ca3e632890655137288d36c0ea836475f9f Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:21:17 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/927c7ca3e632890655137288d36c0ea836475f9f [^] Related to issue 31655: Backout 1886 --- M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M src/org/openbravo/mobile/core/utils/OBMOBCUtils.java --- |
(0084625) hgbot (developer) 2016-03-01 14:29 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: 84c3efd8a98efc47d317d36e71480ed790484f69 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:22:07 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/84c3efd8a98efc47d317d36e71480ed790484f69 [^] Related to issue 31655: Backout 1883 --- M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M web/org.openbravo.mobile.core/source/data/ob-requestrouter.js M web/org.openbravo.mobile.core/source/model/ob-terminal-model.js M web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js --- |
(0084626) hgbot (developer) 2016-03-01 14:33 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: b4ec1d5fc24f3e2515fc500bbcdb19f57461db69 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:17:59 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/b4ec1d5fc24f3e2515fc500bbcdb19f57461db69 [^] Related to issue 31655: Backout 6105 --- M web/org.openbravo.retail.posterminal/js/data/dataordersave.js --- |
(0084627) hgbot (developer) 2016-03-01 14:33 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: 23f9bbcc549bbdbd62fb15c78f15193cb3f322af Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:18:06 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/23f9bbcc549bbdbd62fb15c78f15193cb3f322af [^] Related to issue 31655: Backout 6104 --- M src/org/openbravo/retail/posterminal/OBPOSComponentProvider.java M web/org.openbravo.retail.posterminal/js/data/dataordersave.js R web/org.openbravo.retail.posterminal/js/data/synchronizedorder.js --- |
(0084628) hgbot (developer) 2016-03-01 14:33 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: 1c41944e99ea95a25e1b604516cae76e750099d0 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:18:39 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/1c41944e99ea95a25e1b604516cae76e750099d0 [^] Related to issue 31655: Backout 6059 --- M src/org/openbravo/retail/posterminal/ExternalOrderLoader.java M src/org/openbravo/retail/posterminal/ExternalOrderLoaderErrorHandler.java --- |
(0084629) hgbot (developer) 2016-03-01 14:33 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: 0c0c7e2ec600e185f724b57454a8a2cef1cdd458 Author: Miguel de Juana <miguel.dejuana <at> openbravo.com> Date: Tue Mar 01 14:19:08 2016 +0100 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/0c0c7e2ec600e185f724b57454a8a2cef1cdd458 [^] Related to issue 31655: Backout 6049 --- M src-db/database/sourcedata/AD_REF_LIST.xml M web/org.openbravo.retail.posterminal/js/login/model/login-model.js --- |
(0084631) migueldejuana (developer) 2016-03-01 15:30 |
Backout: This change has been postponed to the next release to do a more generic solution. |
(0084638) hgbot (developer) 2016-03-01 17:42 |
Repository: tools/automation/pi-mobile Changeset: b20fe3e9a091daf579693e20d484d1b130e66cbf Author: Rafa Alonso <ral <at> openbravo.com> Date: Tue Mar 01 17:19:06 2016 +0100 URL: http://code.openbravo.com/tools/automation/pi-mobile/rev/b20fe3e9a091daf579693e20d484d1b130e66cbf [^] Related to issue 31655: Link the 'I31655_CreateSynchronizedSale' to its issue status --- M src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java --- |
(0084865) migueldejuana (developer) 2016-03-10 11:07 |
Attached diffs with the solution. |
(0086098) mtaal (manager) 2016-05-01 15:30 edited on: 2016-05-01 15:46 |
Documentation: http://wiki.openbravo.com/wiki/Retail:Store_Server#Synchronized_Transactions [^] All previous commits (except test) have been backed out. Only new commits after this comment apply to this issue. Only testcase is retained from previous commits and adapted: https://code.openbravo.com/tools/automation/pi-mobile/file/b20fe3e9a091/src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java [^] |
(0086568) hgbot (developer) 2016-05-19 00:44 |
Repository: erp/pmods/org.openbravo.mobile.core Changeset: 6a10c0a2dd157a64ab121e6b6d95ffd9c462f700 Author: Martin Taal <martin.taal <at> openbravo.com> Date: Thu May 19 00:43:38 2016 +0200 URL: http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/6a10c0a2dd157a64ab121e6b6d95ffd9c462f700 [^] Related to issue 31655: WebPOS Synchronous transactions Main synchronized transaction behavior, also added preferences for offline wait time Summary of changes: src-db changes: new title/texts for popup, new import entry type, new preferences for offline wait time and synchronized mode, new service definition DataSynchronizationProcess.java: in case of synchronized mode: prevent commit and always return error/exception no specific error handling MobileService.java: move service processing to separate class MobileServiceProcessor MobileServiceProcessor.java: contains the code which was previously in MobileService, so that it can be called from other classes, set synchronized mode in class and pass on to process class SecuredJSONProcess.java: add synchronized and jsonresult members in this class/level, is really used by subclasses, some changes to prevent NPE if class is called through MobileServiceProcessor, which will always call execSecure MobileMainServerCheck.java: implement preference for offline wait time MobileServerController.java: added checks for more defensive coding MobileServerUtils.java: new utils methods SynchronizedServerProcessCaller.java: main new class for synchronized processing of synced data, unpacks the json to call individual services. ob-dal.js: contain code to create and restore in-memory datadump/backup ob-commonbuttons.js: add a possibility to hide the close button, for unhideable modal confirmation boxes ob-datasource.js: handle one more way that error/exception is returned in json, automatically do all transaction services synchronized (if synchronized mode is enabled) ob-requestrouter.js: added utility method ob-terminal-model.js: main flow change to collect all data which needs to be synced and send them as one request to server using new service ob-utilitiesui.js: add possibility to create non-closeable modal, return the model so it can be used for show/hide by caller --- M src-db/database/sourcedata/AD_MESSAGE.xml M src-db/database/sourcedata/AD_REF_LIST.xml M src-db/database/sourcedata/OBMOBC_SERVICES.xml M src/org/openbravo/mobile/core/process/DataSynchronizationProcess.java M src/org/openbravo/mobile/core/process/MobileService.java M src/org/openbravo/mobile/core/process/SecuredJSONProcess.java M web/org.openbravo.mobile.core/source/component/ob-commonbuttons.js M web/org.openbravo.mobile.core/source/component/ob-menu.js M web/org.openbravo.mobile.core/source/data/ob-dal.js M web/org.openbravo.mobile.core/source/data/ob-datasource.js M web/org.openbravo.mobile.core/source/data/ob-requestrouter.js M web/org.openbravo.mobile.core/source/model/ob-terminal-model.js M web/org.openbravo.mobile.core/source/utils/ob-utilities.js M web/org.openbravo.mobile.core/source/utils/ob-utilitiesui.js A src/org/openbravo/mobile/core/process/MobileServiceProcessor.java A src/org/openbravo/mobile/core/servercontroller/SynchronizedServerProcessCaller.java --- |
(0086569) hgbot (developer) 2016-05-19 00:52 |
Repository: erp/pmods/org.openbravo.retail.posterminal Changeset: e7408dbbf02795b2403656fabaf2ec8caaf08135 Author: Martin Taal <martin.taal <at> openbravo.com> Date: Thu May 19 00:51:42 2016 +0200 URL: http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/e7408dbbf02795b2403656fabaf2ec8caaf08135 [^] Fixes issue 31655: WebPOS Synchronous transactions Changes to the UI to navigate UI view only after succesfull transaction on server. Summary of changes: LoginUtilsServlet.java: moved code to utils class CashupSynchronized: service which is called to load cashup information, if there are errors in the queue will read the cashup info from the central server POSImportEntryProcessor.java: added OBMOBC_SynchronizedData as import entry type cashmgmt-model.js: if transaction fails then remove cash management entries, user has to re-enter them, call postsync actions in success callback cashup-model.js: do a real error callback, when the server returns an error closecash.js: when in synchronized mode there is an error then don't show error message, it is already displayed datacustomeraddrsave.js: move code to global function which can be called from UI, keep trigger for backward compat datacustomersave.js: move code to global function which can be called from UI, keep trigger for backward compat dataordersave.js: in synchronized mode only clean the ui if success return from the server, some code is maintained to retain same UI behavior in case of non-synchronized mode login-model.js: specify which models are checkpointed bplocation.js: call global function to save location instead of calling trigger businesspartner.js: call global function to save bp instead of using trigger pointofsale-model.js: for multi-order wait with printing until success callback customeraddress/components/sharedcomponents.js: move the code which changes UI to a callback, called when server succeeds customers/components/sharedcomponents.js: move the code which changes UI to a callback, called when server succeeds cashupreportutils.js: in case of synchronized mode, reread the cashup from the server --- M src/org/openbravo/retail/posterminal/LoginUtilsServlet.java M src/org/openbravo/retail/posterminal/importprocess/POSImportEntryProcessor.java M web/org.openbravo.retail.posterminal/js/cashmgmt/model/cashmgmt-model.js M web/org.openbravo.retail.posterminal/js/closecash/model/cashup-model.js M web/org.openbravo.retail.posterminal/js/closecash/view/closecash.js M web/org.openbravo.retail.posterminal/js/data/datacustomeraddrsave.js M web/org.openbravo.retail.posterminal/js/data/datacustomersave.js M web/org.openbravo.retail.posterminal/js/data/dataordersave.js M web/org.openbravo.retail.posterminal/js/login/model/login-model.js M web/org.openbravo.retail.posterminal/js/model/bplocation.js M web/org.openbravo.retail.posterminal/js/model/businesspartner.js M web/org.openbravo.retail.posterminal/js/pointofsale/model/pointofsale-model.js M web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customeraddress/components/sharedcomponents.js M web/org.openbravo.retail.posterminal/js/pointofsale/view/subwindows/customers/components/sharedcomponents.js M web/org.openbravo.retail.posterminal/js/utils/cashUpReportUtils.js A src/org/openbravo/retail/posterminal/master/CashupSynchronized.java --- |
(0086591) migueldejuana (developer) 2016-05-20 08:54 |
Tested and reviewed |
(0086595) hgbot (developer) 2016-05-20 10:06 |
Repository: tools/automation/pi-mobile Changeset: 54c2e66c65f5411027c0d475a91517043696bdff Author: Martin Taal <martin.taal <at> openbravo.com> Date: Fri May 20 10:06:16 2016 +0200 URL: http://code.openbravo.com/tools/automation/pi-mobile/rev/54c2e66c65f5411027c0d475a91517043696bdff [^] Related to issue 31655 Synchronized Transactions Remove out dated test --- R src-test/org/openbravo/test/mobile/retail/pack/selenium/tests/sales/I31655_CreateSynchronizedSale.java --- |
(0087325) hgbot (developer) 2016-06-16 08:40 |
Repository: tools/automation/pi-mobile Changeset: b25342989139431b916e3835b7c68ed9feb10616 Author: Martin Taal <martin.taal <at> openbravo.com> Date: Thu Jun 16 08:40:05 2016 +0200 URL: http://code.openbravo.com/tools/automation/pi-mobile/rev/b25342989139431b916e3835b7c68ed9feb10616 [^] Related to issue 31655: WebPOS Synchronous transactions Added synchronized transaction test cases --- M src-test/org/openbravo/test/mobile/common/junit/toolbox/OBWildcardPatternSuite.java M src-test/org/openbravo/test/mobile/common/selenium/utils/AllowedErrorsHelper.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/BaseSynchronizedTransactionTest.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/SynchronizedCashupWithDeposit.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/SynchronizedCashupWithSaleAndReturn.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I25623_VerifiedReturnsAvoidMoreThanOrdered.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I27476_SameDocumentNoAfterPayAndReload.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I27615_PartiallyPaidLayaway.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I30412_QuotationsAndPromotions.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I31323_LayawayPayOpenTicket.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I31462_VoidLayaway.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_I31892_VoidLayawayAndCashUp.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/Synchronized_RejectQuotations.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/TestNonSynchronizedSale.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/TestSynchronizedSaleWithError.java A src-test/org/openbravo/test/mobile/quarantine/pack/MTA/synchronizedtransactions/TestSynchronizedTransaction.java --- |
Issue History | |||
Date Modified | Username | Field | Change |
2015-12-07 14:59 | mtaal | New Issue | |
2015-12-07 14:59 | mtaal | Assigned To | => mtaal |
2015-12-07 14:59 | mtaal | Triggers an Emergency Pack | => No |
2016-02-04 11:26 | hgbot | Checkin | |
2016-02-04 11:26 | hgbot | Note Added: 0083921 | |
2016-02-05 19:30 | hgbot | Checkin | |
2016-02-05 19:30 | hgbot | Note Added: 0083988 | |
2016-02-05 19:30 | hgbot | Status | new => resolved |
2016-02-05 19:30 | hgbot | Resolution | open => fixed |
2016-02-05 19:30 | hgbot | Fixed in SCM revision | => http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/b296383fd9f307d2bc4d980edddd58b2c62da796 [^] |
2016-02-05 19:31 | hgbot | Checkin | |
2016-02-05 19:31 | hgbot | Note Added: 0083989 | |
2016-02-05 19:31 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/b296383fd9f307d2bc4d980edddd58b2c62da796 [^] => http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/b4f987dcae8ef3ea097c57505c3cd9aad80c38de [^] |
2016-02-08 12:02 | migueldejuana | Review Assigned To | => mtaal |
2016-02-08 15:18 | Orekaria | Assigned To | mtaal => migueldejuana |
2016-02-08 15:18 | Orekaria | Note Added: 0084004 | |
2016-02-08 15:18 | Orekaria | Status | resolved => new |
2016-02-08 15:18 | Orekaria | Resolution | fixed => open |
2016-02-08 15:18 | Orekaria | Status | new => scheduled |
2016-02-08 15:23 | Orekaria | Relationship added | related to 0030897 |
2016-02-08 16:50 | Orekaria | Relationship added | blocks 0032162 |
2016-02-09 08:30 | hgbot | Checkin | |
2016-02-09 08:30 | hgbot | Note Added: 0084024 | |
2016-02-09 08:30 | hgbot | Status | scheduled => resolved |
2016-02-09 08:30 | hgbot | Resolution | open => fixed |
2016-02-09 08:30 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/b4f987dcae8ef3ea097c57505c3cd9aad80c38de [^] => http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/f0a9d720baf1aa2f0a6395853d52bd897a4e65b8 [^] |
2016-02-09 08:31 | hgbot | Checkin | |
2016-02-09 08:31 | hgbot | Note Added: 0084025 | |
2016-02-09 08:31 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/f0a9d720baf1aa2f0a6395853d52bd897a4e65b8 [^] => http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/2f792e3dea76183e6f509f7d8e00c245c449c52a [^] |
2016-02-17 15:53 | migueldejuana | Note Added: 0084293 | |
2016-02-17 15:53 | migueldejuana | Status | resolved => new |
2016-02-17 15:53 | migueldejuana | Resolution | fixed => open |
2016-02-23 13:13 | hgbot | Checkin | |
2016-02-23 13:13 | hgbot | Note Added: 0084420 | |
2016-02-23 13:13 | hgbot | Status | new => resolved |
2016-02-23 13:13 | hgbot | Resolution | open => fixed |
2016-02-23 13:13 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/2f792e3dea76183e6f509f7d8e00c245c449c52a [^] => http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/3bf463fe8806345b3f83ee212312708d43a27c5b [^] |
2016-02-23 13:14 | hgbot | Checkin | |
2016-02-23 13:14 | hgbot | Note Added: 0084421 | |
2016-02-23 13:14 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.mobile.core/rev/3bf463fe8806345b3f83ee212312708d43a27c5b [^] => http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/33e591f858d262185703fed85d0db09f0993f683 [^] |
2016-02-23 14:07 | hgbot | Checkin | |
2016-02-23 14:07 | hgbot | Note Added: 0084430 | |
2016-02-23 14:07 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/33e591f858d262185703fed85d0db09f0993f683 [^] => http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/abb22a9df9f9749d3fac366001c472ec155faeff [^] |
2016-02-27 08:53 | mtaal | Note Added: 0084574 | |
2016-02-29 11:12 | mtaal | Note Added: 0084586 | |
2016-02-29 11:12 | mtaal | Status | resolved => new |
2016-02-29 11:12 | mtaal | Resolution | fixed => open |
2016-03-01 14:29 | hgbot | Checkin | |
2016-03-01 14:29 | hgbot | Note Added: 0084623 | |
2016-03-01 14:29 | hgbot | Checkin | |
2016-03-01 14:29 | hgbot | Note Added: 0084624 | |
2016-03-01 14:29 | hgbot | Checkin | |
2016-03-01 14:29 | hgbot | Note Added: 0084625 | |
2016-03-01 14:33 | hgbot | Checkin | |
2016-03-01 14:33 | hgbot | Note Added: 0084626 | |
2016-03-01 14:33 | hgbot | Checkin | |
2016-03-01 14:33 | hgbot | Note Added: 0084627 | |
2016-03-01 14:33 | hgbot | Checkin | |
2016-03-01 14:33 | hgbot | Note Added: 0084628 | |
2016-03-01 14:33 | hgbot | Checkin | |
2016-03-01 14:33 | hgbot | Note Added: 0084629 | |
2016-03-01 15:30 | migueldejuana | Note Added: 0084631 | |
2016-03-01 17:42 | hgbot | Checkin | |
2016-03-01 17:42 | hgbot | Note Added: 0084638 | |
2016-03-10 11:06 | migueldejuana | File Added: issue31655Core.diff | |
2016-03-10 11:06 | migueldejuana | File Added: issue31655Posterminal.diff | |
2016-03-10 11:07 | migueldejuana | Note Added: 0084865 | |
2016-03-14 17:46 | migueldejuana | File Deleted: issue31655Core.diff | |
2016-03-14 17:46 | migueldejuana | File Added: issue31655Core.diff | |
2016-03-16 10:42 | migueldejuana | File Deleted: issue31655Posterminal.diff | |
2016-03-16 10:42 | migueldejuana | File Deleted: issue31655Core.diff | |
2016-03-16 10:43 | migueldejuana | File Added: issue31655Core.diff | |
2016-03-16 10:43 | migueldejuana | File Added: issue31655Posterminal.diff | |
2016-04-22 01:20 | mtaal | Assigned To | migueldejuana => mtaal |
2016-05-01 15:30 | mtaal | Note Added: 0086098 | |
2016-05-01 15:46 | mtaal | Note Edited: 0086098 | View Revisions |
2016-05-02 13:18 | mtaal | File Deleted: issue31655Core.diff | |
2016-05-02 13:19 | mtaal | File Deleted: issue31655Posterminal.diff | |
2016-05-02 13:19 | mtaal | File Added: retail-31655.diff | |
2016-05-02 13:19 | mtaal | File Added: core-31655.diff | |
2016-05-02 16:19 | mtaal | Review Assigned To | mtaal => migueldejuana |
2016-05-04 00:42 | mtaal | File Deleted: retail-31655.diff | |
2016-05-04 00:43 | mtaal | File Deleted: core-31655.diff | |
2016-05-04 00:43 | mtaal | File Added: pi-mobile-test.diff | |
2016-05-04 00:43 | mtaal | File Added: retail-v2.diff | |
2016-05-04 00:43 | mtaal | File Added: core-v2.diff | |
2016-05-09 06:32 | mtaal | Relationship added | depends on 0032899 |
2016-05-09 06:32 | mtaal | File Deleted: retail-v2.diff | |
2016-05-09 06:32 | mtaal | File Deleted: pi-mobile-test.diff | |
2016-05-09 06:32 | mtaal | File Deleted: core-v2.diff | |
2016-05-09 08:55 | mtaal | File Added: pi-mobile.diff | |
2016-05-09 09:09 | mtaal | File Added: 31655-core-0905.diff | |
2016-05-09 09:09 | mtaal | File Added: 31655-retail-0905.diff | |
2016-05-10 16:01 | mtaal | File Deleted: 31655-core-0905.diff | |
2016-05-10 16:01 | mtaal | File Deleted: pi-mobile.diff | |
2016-05-10 16:02 | mtaal | File Deleted: 31655-retail-0905.diff | |
2016-05-10 16:02 | mtaal | File Added: core-1005.diff | |
2016-05-10 16:02 | mtaal | File Added: retail-1005.diff | |
2016-05-10 16:02 | mtaal | File Added: pi-mobile-1005.diff | |
2016-05-12 01:14 | mtaal | File Deleted: core-1005.diff | |
2016-05-12 01:14 | mtaal | File Deleted: retail-1005.diff | |
2016-05-12 01:15 | mtaal | File Deleted: pi-mobile-1005.diff | |
2016-05-12 01:15 | mtaal | File Added: retail-1205.diff | |
2016-05-12 01:15 | mtaal | File Added: core-1205.diff | |
2016-05-12 01:15 | mtaal | File Added: pi-mobile-1205.diff | |
2016-05-12 11:36 | mtaal | File Deleted: core-1205.diff | |
2016-05-12 11:36 | mtaal | File Added: core-1205.diff | |
2016-05-14 09:02 | mtaal | File Deleted: core-1205.diff | |
2016-05-14 09:02 | mtaal | File Deleted: retail-1205.diff | |
2016-05-14 09:02 | mtaal | File Added: 1405-retail.diff | |
2016-05-14 09:02 | mtaal | File Added: 1405-core.diff | |
2016-05-15 16:48 | mtaal | File Deleted: pi-mobile-1205.diff | |
2016-05-15 16:48 | mtaal | File Deleted: 1405-retail.diff | |
2016-05-15 16:48 | mtaal | File Deleted: 1405-core.diff | |
2016-05-15 16:48 | mtaal | File Added: 1505-mobile.diff | |
2016-05-15 16:48 | mtaal | File Added: 1505-core.diff | |
2016-05-15 16:48 | mtaal | File Added: 1505-retail.diff | |
2016-05-19 00:44 | hgbot | Checkin | |
2016-05-19 00:44 | hgbot | Note Added: 0086568 | |
2016-05-19 00:52 | hgbot | Checkin | |
2016-05-19 00:52 | hgbot | Note Added: 0086569 | |
2016-05-19 00:52 | hgbot | Status | new => resolved |
2016-05-19 00:52 | hgbot | Resolution | open => fixed |
2016-05-19 00:52 | hgbot | Fixed in SCM revision | http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/abb22a9df9f9749d3fac366001c472ec155faeff [^] => http://code.openbravo.com/erp/pmods/org.openbravo.retail.posterminal/rev/e7408dbbf02795b2403656fabaf2ec8caaf08135 [^] |
2016-05-20 08:54 | migueldejuana | Note Added: 0086591 | |
2016-05-20 08:54 | migueldejuana | Status | resolved => closed |
2016-05-20 10:06 | hgbot | Checkin | |
2016-05-20 10:06 | hgbot | Note Added: 0086595 | |
2016-06-16 08:40 | hgbot | Checkin | |
2016-06-16 08:40 | hgbot | Note Added: 0087325 | |
2019-06-26 09:38 | joniturralde93 | Relationship added | causes 0041178 |
Copyright © 2000 - 2009 MantisBT Group |