# HG changeset patch
# User Jorge Garcia <jorge.garcia@openbravo.com>
# Date 1501572115 -7200
#      Tue Aug 01 09:21:55 2017 +0200
# Node ID 66b27bee8d98b72687323805f0fa5d02462beedf
# Parent  da2d02d3683dd98a1672167d0b57085ae2c35aca
Related to issue 36515: Improve BusinessPartner query performance removing location info from it

Version 4.0

diff --git a/src/org/openbravo/retail/posterminal/CustomerLoader.java b/src/org/openbravo/retail/posterminal/CustomerLoader.java
--- a/src/org/openbravo/retail/posterminal/CustomerLoader.java
+++ b/src/org/openbravo/retail/posterminal/CustomerLoader.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2012-2016 Openbravo S.L.U.
+ * Copyright (C) 2012-2017 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.
@@ -40,8 +40,8 @@
 import org.openbravo.service.json.JsonConstants;
 
 @DataSynchronization(entity = "BusinessPartner")
-public class CustomerLoader extends POSDataSynchronizationProcess implements
-    DataSynchronizationImportProcess {
+public class CustomerLoader extends POSDataSynchronizationProcess
+    implements DataSynchronizationImportProcess {
 
   private static final Logger log = Logger.getLogger(CustomerLoader.class);
 
@@ -60,7 +60,6 @@
   public JSONObject saveRecord(JSONObject jsoncustomer) throws Exception {
     BusinessPartner customer = null;
     User user = null;
-    Location location = null;
     OBContext.setAdminMode(false);
     try {
       customer = getCustomer(jsoncustomer.getString("id"));
@@ -72,13 +71,9 @@
         if (jsoncustomer.has("contactId")) {
           user = OBDal.getInstance().get(User.class, jsoncustomer.getString("contactId"));
         }
-        if (jsoncustomer.has("locId")) {
-          location = OBDal.getInstance().get(Location.class, jsoncustomer.getString("locId"));
-        }
 
         if (!(loaded.compareTo(customer.getUpdated()) >= 0)
-            || !(user != null && (loaded.compareTo(user.getUpdated()) >= 0))
-            || !(user != null && (loaded.compareTo(location.getUpdated()) >= 0))) {
+            || !(user != null && (loaded.compareTo(user.getUpdated()) >= 0))) {
           log.warn(Utility.messageBD(new DalConnectionProvider(false), "OBPOS_outdatedbp",
               OBContext.getOBContext().getLanguage().getLanguage()));
         }
@@ -117,7 +112,8 @@
 
     // customer.setClient(OBDal.getInstance().get(Client.class, jsonCustomer.getString("client")));
     // BP org (required)
-    if (!jsonCustomer.has("organization") || "null".equals(jsonCustomer.getString("organization"))) {
+    if (!jsonCustomer.has("organization")
+        || "null".equals(jsonCustomer.getString("organization"))) {
       String errorMessage = "Business partner organization is a mandatory field to create a new customer from Web Pos";
       log.error(errorMessage);
       throw new OBException(errorMessage, null);
@@ -148,8 +144,8 @@
 
       int bpsWithPossibleSK = 0;
 
-      final OBCriteria<BusinessPartner> bpCriteria = OBDal.getInstance().createCriteria(
-          BusinessPartner.class);
+      final OBCriteria<BusinessPartner> bpCriteria = OBDal.getInstance()
+          .createCriteria(BusinessPartner.class);
       bpCriteria.setFilterOnActive(false);
       bpCriteria.setFilterOnReadableOrganization(false);
       bpCriteria.add(Restrictions.eq("searchKey", possibleSK));
@@ -201,10 +197,10 @@
 
   private void editBPartnerContact(BusinessPartner customer, JSONObject jsonCustomer)
       throws JSONException {
-    Entity userEntity = ModelProvider.getInstance().getEntity(
-        org.openbravo.model.ad.access.User.class);
-    final org.openbravo.model.ad.access.User user = OBDal.getInstance().get(
-        org.openbravo.model.ad.access.User.class, jsonCustomer.getString("contactId"));
+    Entity userEntity = ModelProvider.getInstance()
+        .getEntity(org.openbravo.model.ad.access.User.class);
+    final org.openbravo.model.ad.access.User user = OBDal.getInstance()
+        .get(org.openbravo.model.ad.access.User.class, jsonCustomer.getString("contactId"));
     if (user != null) {
 
       JSONPropertyToEntity.fillBobFromJSON(userEntity, user, jsonCustomer);
@@ -246,8 +242,8 @@
 
       // create the user
 
-      final org.openbravo.model.ad.access.User usr = OBProvider.getInstance().get(
-          org.openbravo.model.ad.access.User.class);
+      final org.openbravo.model.ad.access.User usr = OBProvider.getInstance()
+          .get(org.openbravo.model.ad.access.User.class);
 
       JSONPropertyToEntity.fillBobFromJSON(userEntity, usr, jsonCustomer);
 
@@ -274,23 +270,24 @@
   }
 
   private void editLocation(BusinessPartner customer, JSONObject jsonCustomer) throws Exception {
+    if (jsonCustomer.has("locId")) {
+      final Location location = OBDal.getInstance().get(Location.class,
+          jsonCustomer.getString("locId"));
+      if (location == null) {
+        // location doesn't exist > create location(s) and bplocation(s)
+        final org.openbravo.model.common.geography.Location rootLocation = OBProvider.getInstance()
+            .get(org.openbravo.model.common.geography.Location.class);
+        final org.openbravo.model.common.geography.Location rootShippingLocation = OBProvider
+            .getInstance().get(org.openbravo.model.common.geography.Location.class);
 
-    final Location location = OBDal.getInstance().get(Location.class,
-        jsonCustomer.getString("locId"));
-    if (location == null) {
-      // location doesn't exist > create location(s) and bplocation(s)
-      final org.openbravo.model.common.geography.Location rootLocation = OBProvider.getInstance()
-          .get(org.openbravo.model.common.geography.Location.class);
-      final org.openbravo.model.common.geography.Location rootShippingLocation = OBProvider
-          .getInstance().get(org.openbravo.model.common.geography.Location.class);
-
-      if (!jsonCustomer.has("useSameAddrForShipAndInv")
-          || (jsonCustomer.has("useSameAddrForShipAndInv") && jsonCustomer
-              .getBoolean("useSameAddrForShipAndInv"))) {
-        createBPLoc(rootLocation, customer, jsonCustomer, true, true);
-      } else {
-        createBPLoc(rootLocation, customer, jsonCustomer, true, false);
-        createBPLoc(rootShippingLocation, customer, jsonCustomer, false, true);
+        if (!jsonCustomer.has("useSameAddrForShipAndInv")
+            || (jsonCustomer.has("useSameAddrForShipAndInv")
+                && jsonCustomer.getBoolean("useSameAddrForShipAndInv"))) {
+          createBPLoc(rootLocation, customer, jsonCustomer, true, true);
+        } else {
+          createBPLoc(rootLocation, customer, jsonCustomer, true, false);
+          createBPLoc(rootShippingLocation, customer, jsonCustomer, false, true);
+        }
       }
     }
   }
@@ -298,8 +295,8 @@
   private void createBPLoc(org.openbravo.model.common.geography.Location location,
       BusinessPartner customer, JSONObject jsonCustomer, Boolean isInvoicing, Boolean isShipping)
       throws Exception {
-    Entity baseLocationEntity = ModelProvider.getInstance().getEntity(
-        org.openbravo.model.common.geography.Location.class);
+    Entity baseLocationEntity = ModelProvider.getInstance()
+        .getEntity(org.openbravo.model.common.geography.Location.class);
     Entity locationEntity = ModelProvider.getInstance().getEntity(Location.class);
     // Field mapping:
     String locName = (isInvoicing ? "locName" : "shipLocName");
diff --git a/src/org/openbravo/retail/posterminal/master/BusinessPartner.java b/src/org/openbravo/retail/posterminal/master/BusinessPartner.java
--- a/src/org/openbravo/retail/posterminal/master/BusinessPartner.java
+++ b/src/org/openbravo/retail/posterminal/master/BusinessPartner.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2012-2016 Openbravo S.L.U.
+ * Copyright (C) 2012-2017 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.
@@ -46,52 +46,28 @@
 
   @Override
   protected List<String> getQuery(JSONObject jsonsent) throws JSONException {
-    Long lastUpdated = jsonsent.has("lastUpdated")
-        && !jsonsent.get("lastUpdated").equals("undefined")
-        && !jsonsent.get("lastUpdated").equals("null") ? jsonsent.getLong("lastUpdated") : null;
-    // if it is a total refresh we need to ensure that all(AND) entities are active. In a
-    // incremental refresh, we need to retrieve it if some (OR) ot the entities have changed
-    String operator = lastUpdated == null ? " AND " : " OR ";
     HQLPropertyList regularBusinessPartnerHQLProperties = ModelExtensionUtils
         .getPropertyExtensions(extensions);
     String hql = "SELECT "
         + regularBusinessPartnerHQLProperties.getHqlSelect() //
-        + "FROM BusinessPartnerLocation AS bpl " //
-        + "join bpl.businessPartner AS bp " //
+        + "FROM BusinessPartner AS bp " //
         + "join bp.priceList AS plist " //
         + "left outer join bp.aDUserList AS ulist "
-        + "left outer join bp.businessPartnerLocationList AS bpsl " //
         + "WHERE $filtersCriteria AND " //
-        + "bp.customer = true AND "
-        + "(bpsl is null or bpsl.id in (select max(bpls.id) as bpLocId from BusinessPartnerLocation AS bpls where bpls.active=true AND bpls.shipToAddress = true and bpls.businessPartner.id=bp.id and bpls.$readableSimpleClientCriteria AND "
-        + "bpls.$naturalOrgCriteria)) AND " //
-        + "bpl.$readableSimpleClientCriteria AND "
-        + "bpl.$naturalOrgCriteria AND "
-        + "(bpl.$incrementalUpdateCriteria"
-        + operator
-        + "bp.$incrementalUpdateCriteria) AND "
-        + "bpl.id in (select max(bpls.id) as bpLocId from BusinessPartnerLocation AS bpls where bpls.active=true and bpls.invoiceToAddress = true and bpls.businessPartner.id=bp.id and bpls.$readableSimpleClientCriteria AND "
-        + "bpls.$naturalOrgCriteria) AND "
+        + "bp.customer = true AND " + "(bp.$incrementalUpdateCriteria) AND "
+        + "bp.$readableSimpleClientCriteria AND " + "bp.$naturalOrgCriteria AND "
         + "(not exists (select 1 from ADUser usr where usr.businessPartner = bp)) "
         + "ORDER BY bp.name, bp.id";
     String hql2 = "SELECT"
         + regularBusinessPartnerHQLProperties.getHqlSelect() //
-        + "FROM BusinessPartnerLocation AS bpl " //
-        + "join bpl.businessPartner AS bp " //
+        + "FROM BusinessPartner AS bp " //
         + "join bp.priceList AS plist " //
         + "left outer join bp.aDUserList AS ulist "
-        + "left outer join bp.businessPartnerLocationList AS bpsl " //
         + "WHERE $filtersCriteria AND " //
         + "bp.customer = true AND "
-        + "(bpsl is null or bpsl.id in (select max(bpls.id) as bpLocId from BusinessPartnerLocation AS bpls where bpls.active=true AND bpls.shipToAddress = true and bpls.businessPartner.id=bp.id and bpls.$readableSimpleClientCriteria AND "
-        + "bpls.$naturalOrgCriteria)) AND " //
-        + "bpl.$readableSimpleClientCriteria AND "
-        + "bpl.$naturalOrgCriteria AND " //
-        + "(bpl.$incrementalUpdateCriteria"
-        + operator
-        + "bp.$incrementalUpdateCriteria) AND "
-        + "bpl.id in (select max(bpls.id) as bpLocId from BusinessPartnerLocation AS bpls where bpls.active=true and bpls.invoiceToAddress = true and bpls.businessPartner.id=bp.id and bpls.$readableSimpleClientCriteria AND "
-        + "bpls.$naturalOrgCriteria) AND "
+        + "bp.$readableSimpleClientCriteria AND "
+        + "bp.$naturalOrgCriteria AND "
+        + "(bp.$incrementalUpdateCriteria) AND "
         + "(ulist.id in (select max(ulist2.id) from ADUser as ulist2 where ulist2.businessPartner=bp)) "
         + "ORDER BY bp.name, bp.id";
     return Arrays.asList(new String[] { hql, hql2 });
diff --git a/src/org/openbravo/retail/posterminal/master/BusinessPartnerProperties.java b/src/org/openbravo/retail/posterminal/master/BusinessPartnerProperties.java
--- a/src/org/openbravo/retail/posterminal/master/BusinessPartnerProperties.java
+++ b/src/org/openbravo/retail/posterminal/master/BusinessPartnerProperties.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2015-2016 Openbravo S.L.U.
+ * Copyright (C) 2015-2017 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.
@@ -37,12 +37,6 @@
         add(new HQLProperty("bp.paymentMethod.id", "paymentMethod"));
         add(new HQLProperty("bp.paymentTerms.id", "paymentTerms"));
         add(new HQLProperty("bp.invoiceTerms", "invoiceTerms"));
-        add(new HQLProperty("bpl.id", "locId"));
-        add(new HQLProperty("bpsl.id", "shipLocId"));
-        add(new HQLProperty("bpl.locationAddress.addressLine1", "locName"));
-        add(new HQLProperty(
-            "coalesce(bpsl.locationAddress.addressLine1, bpsl.locationAddress.addressLine2, bpsl.locationAddress.postalCode, bpsl.locationAddress.cityName)",
-            "shipLocName"));
         add(new HQLProperty("ulist.email", "email"));
         add(new HQLProperty("ulist.id", "contactId"));
         add(new HQLProperty("ulist.phone", "phone"));
@@ -50,15 +44,6 @@
         add(new HQLProperty("ulist.lastName", "lastName"));
         add(new HQLProperty("plist.priceIncludesTax", "priceIncludesTax"));
         add(new HQLProperty("plist.name", "priceListName"));
-        add(new HQLProperty("bpl.locationAddress.cityName", "cityName"));
-        add(new HQLProperty("bpsl.locationAddress.cityName", "shipCityName"));
-        add(new HQLProperty("bpl.locationAddress.postalCode", "postalCode"));
-        add(new HQLProperty("bpsl.locationAddress.postalCode", "shipPostalCode"));
-        add(new HQLProperty("bpl.locationAddress.region.id", "regionId"));
-        add(new HQLProperty("bpsl.locationAddress.region.id", "shipRegionId"));
-        add(new HQLProperty("bpl.locationAddress.country.id", "countryId"));
-        add(new HQLProperty("bpsl.locationAddress.country.id", "shipCountryId"));
-        add(new HQLProperty("bpl.locationAddress.country.name", "countryName"));
         add(new HQLProperty("bp.businessPartnerCategory.id", "businessPartnerCategory"));
         add(new HQLProperty("bp.businessPartnerCategory.name", "businessPartnerCategory_name"));
         add(new HQLProperty("bp.creditLimit", "creditLimit"));
@@ -68,8 +53,7 @@
         add(new HQLProperty("bp.salesOrder", "salesOrderBlocking"));
         add(new HQLProperty("bp.birthDay", "birthDay"));
         add(new HQLProperty("bp.birthPlace", "birthPlace"));
-        add(new HQLProperty(
-            "(case when bpl.active = 'Y' and bp.active = 'Y' then true else false end)", "active"));
+        add(new HQLProperty("bp.active", "active"));
         String curDbms = OBPropertiesProvider.getInstance().getOpenbravoProperties()
             .getProperty("bbdd.rdbms");
         if (curDbms.equals("POSTGRE")) {
@@ -77,7 +61,6 @@
         } else if (curDbms.equals("ORACLE")) {
           add(new HQLProperty("TO_CHAR(SYSTIMESTAMP, 'MM-DD-YYYY HH24:MI:SS')", "loaded"));
         }
-
       }
     };
     return list;
diff --git a/src/org/openbravo/retail/posterminal/master/LoadedCustomer.java b/src/org/openbravo/retail/posterminal/master/LoadedCustomer.java
--- a/src/org/openbravo/retail/posterminal/master/LoadedCustomer.java
+++ b/src/org/openbravo/retail/posterminal/master/LoadedCustomer.java
@@ -1,6 +1,6 @@
 /*
  ************************************************************************************
- * Copyright (C) 2016 Openbravo S.L.U.
+ * Copyright (C) 2016-2017 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.
@@ -48,8 +48,12 @@
       Map<String, Object> paramValues = new HashMap<String, Object>();
       paramValues.put("businessPartnerId",
           jsonsent.getJSONObject("parameters").getJSONObject("bpartnerId").get("value"));
-      paramValues.put("bplocId", jsonsent.getJSONObject("parameters").getJSONObject("bpLocationId")
-          .get("value"));
+      paramValues.put("bplocId",
+          jsonsent.getJSONObject("parameters").getJSONObject("bpLocationId").get("value"));
+      if (jsonsent.getJSONObject("parameters").has("bpBillLocationId")) {
+        paramValues.put("bpbilllocId",
+            jsonsent.getJSONObject("parameters").getJSONObject("bpBillLocationId").get("value"));
+      }
 
       return paramValues;
     } finally {
@@ -63,12 +67,9 @@
     HQLPropertyList bpartnerHQLProperties = ModelExtensionUtils.getPropertyExtensions(extensions);
     HQLPropertyList bpartnerLocHQLProperties = ModelExtensionUtils
         .getPropertyExtensions(extensionsLoc);
-    String hql = "SELECT "
-        + bpartnerHQLProperties.getHqlSelect() //
-        + "FROM BusinessPartnerLocation AS bpl "
-        + "join bpl.businessPartner as bp "
-        + "left outer join bp.aDUserList AS ulist "
-        + "left outer join bp.priceList AS plist "
+    String hql = "SELECT " + bpartnerHQLProperties.getHqlSelect() //
+        + "FROM BusinessPartnerLocation AS bpl " + "join bpl.businessPartner as bp "
+        + "left outer join bp.aDUserList AS ulist " + "left outer join bp.priceList AS plist "
         + "left outer join bp.businessPartnerLocationList AS bpsl " //
         + "Where bp.id= :businessPartnerId "
         + " and bpl.id in (select max(bpls.id) as bpLocId from BusinessPartnerLocation AS bpls where bpls.businessPartner.id=bp.id and bpls.invoiceToAddress = true "
@@ -83,6 +84,12 @@
         + " from BusinessPartnerLocation AS bploc " + "Where bploc.id= :bplocId"
         + " ORDER BY bploc.locationAddress.addressLine1";
     customers.add(hql);
+    if (jsonsent.getJSONObject("parameters").has("bpBillLocationId")) {
+      hql = " select" + bpartnerLocHQLProperties.getHqlSelect()
+          + " from BusinessPartnerLocation AS bploc " + "Where bploc.id= :bpbilllocId"
+          + " ORDER BY bploc.locationAddress.addressLine1";
+      customers.add(hql);
+    }
     return customers;
   }
 }
diff --git a/web/org.openbravo.retail.posterminal/js/components/businesspartner_selector.js b/web/org.openbravo.retail.posterminal/js/components/businesspartner_selector.js
--- a/web/org.openbravo.retail.posterminal/js/components/businesspartner_selector.js
+++ b/web/org.openbravo.retail.posterminal/js/components/businesspartner_selector.js
@@ -690,12 +690,12 @@
       var bp = new OB.Model.BusinessPartner({
         id: bpartner.get('bpartnerId')
       });
-      bp.loadBPLocations(shipping, billing, function (shipping, billing) {
-        me.setBPLocation(bpartner, shipping, billing);
+      bp.loadBPLocations(shipping, billing, function (shipping, billing, locations) {
+        me.setBPLocation(bpartner, shipping, billing, locations);
       });
     }
   },
-  setBPLocation: function (bpartner, shipping, billing) {
+  setBPLocation: function (bpartner, shipping, billing, locations) {
     if (OB.MobileApp.model.hasPermission('OBPOS_remote.customer', true)) {
       if (!shipping) {
         OB.UTIL.showError(OB.I18N.getLabel('OBPOS_BPartnerNoShippingAddress', [bpartner.get('_identifier')]));
@@ -710,6 +710,8 @@
     OB.Dal.get(OB.Model.BusinessPartner, bpartner.get('bpartnerId'), function (bp) {
       bp.setBPLocations(shipping, billing, OB.MobileApp.model.hasPermission('OBPOS_remote.customer', true));
 
+      bp.set('locations', locations);
+
       if (me.target.startsWith('filterSelectorButton_')) {
         me.doChangeFilterSelector({
           selector: {
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
@@ -111,11 +111,11 @@
         me.clearModelWith(null);
         userCallback(me);
       } else {
-        OB.Dal.get(OB.Model.BPLocation, customerCol.get('locId'), function (location) { //OB.Dal.find success
-          customerCol.set('locationModel', location);
+        this.loadBPLocations(null, null, function (shipping, billing, locations) {
+          customerCol.set('locationModel', shipping || billing);
           me.clearModelWith(customerCol);
           userCallback(me);
-        });
+        }, customerCol.get('id'));
       }
     },
     loadByModel: function (cusToLoad) {
@@ -199,12 +199,13 @@
     serializeToJSON: function () {
       return JSON.parse(JSON.stringify(this.toJSON()));
     },
-    loadBPLocations: function (shipping, billing, callback) {
+    loadBPLocations: function (shipping, billing, callback, bpId) {
       var criteria = {
         bpartner: {
           operator: OB.Dal.EQ,
-          value: this.get('id')
-        }
+          value: bpId || this.get('id')
+        },
+        '_orderByClause': 'c_bpartner_location_id desc'
       };
       if (OB.MobileApp.model.hasPermission('OBPOS_remote.customer', true)) {
         var filterBpartnerId = {
@@ -226,6 +227,10 @@
             return loc.get('isShipTo');
           });
         }
+        if (!shipping && !billing) {
+          OB.UTIL.showError(OB.I18N.getLabel('OBPOS_BPartnerNoShippingAddress', [bpId]));
+          return;
+        }
         callback(shipping, billing, collection.models);
       });
     },
@@ -235,18 +240,27 @@
         this.set('shipLocName', shipping.get('name'));
         this.set('shipCityName', shipping.get('cityName'));
         this.set('shipPostalCode', shipping.get('postalCode'));
+        this.set('shipRegionId', shipping.get('regionId'));
+        this.set('shipCountryId', shipping.get('countryId'));
       } else {
         this.set('shipLocId', null);
         this.set('shipLocName', null);
         this.set('shipCityName', null);
         this.set('shipPostalCode', null);
+        this.set('shipRegionId', null);
+        this.set('shipCountryId', null);
       }
       if (billing) {
         this.set("locId", billing.get("id"));
         this.set("locName", billing.get("name"));
+        this.set('locationBillModel', billing);
+        this.set('regionId', billing.get('regionId'));
+        this.set('countryId', billing.get('countryId'));
       } else {
         this.set("locId", null);
         this.set("locName", null);
+        this.set('regionId', null);
+        this.set('countryId', null);
       }
       if (locationModel) {
         this.set('locationModel', shipping);
@@ -321,65 +335,6 @@
     column: 'invoicerule',
     type: 'TEXT'
   }, {
-    name: 'locId',
-    column: 'c_bpartnerlocation_id',
-    type: 'TEXT'
-  }, {
-    name: 'locName',
-    column: 'c_bpartnerlocation_name',
-    filter: true,
-    skipremote: true,
-    type: 'TEXT'
-  }, {
-    name: 'postalCode',
-    column: 'postalCode',
-    filter: true,
-    type: 'TEXT'
-  }, {
-    name: 'cityName',
-    column: 'cityName',
-    filter: true,
-    type: 'TEXT'
-  }, {
-    name: 'regionId',
-    column: 'regionId',
-    type: 'TEXT'
-  }, {
-    name: 'countryId',
-    column: 'countryId',
-    type: 'TEXT'
-  }, {
-    name: 'countryName',
-    column: 'countryName',
-    type: 'TEXT'
-  }, {
-    name: 'shipLocId',
-    column: 'shipLocId',
-    type: 'TEXT'
-  }, {
-    name: 'shipLocName',
-    column: 'shipLocName',
-    filter: true,
-    type: 'TEXT'
-  }, {
-    name: 'shipPostalCode',
-    column: 'shipPostalCode',
-    filter: true,
-    type: 'TEXT'
-  }, {
-    name: 'shipCityName',
-    column: 'shipCityName',
-    filter: true,
-    type: 'TEXT'
-  }, {
-    name: 'shipRegionId',
-    column: 'shipRegionId',
-    type: 'TEXT'
-  }, {
-    name: 'shipCountryId',
-    column: 'shipCountryId',
-    type: 'TEXT'
-  }, {
     name: 'contactId',
     column: 'ad_user_id',
     type: 'TEXT'
diff --git a/web/org.openbravo.retail.posterminal/js/model/order.js b/web/org.openbravo.retail.posterminal/js/model/order.js
--- a/web/org.openbravo.retail.posterminal/js/model/order.js
+++ b/web/org.openbravo.retail.posterminal/js/model/order.js
@@ -2390,78 +2390,98 @@
               OB.error(arguments);
             });
           }
-
-          OB.Dal.get(OB.Model.BPLocation, businessPartner.get('shipLocId'), function (location) {
-
-            OB.Dal.saveIfNew(location, function () {
-              businessPartner.set('locationModel', location);
-              me.set('bp', businessPartner);
-              me.save();
-              // copy the modelOrder again, as the get/save are async
-              OB.MobileApp.model.orderList.saveCurrent();
-              finishSaveData(callback);
-            }, function () {
-              OB.error(arguments);
-            });
-
-          }, function () {
-            OB.error(arguments);
-            errorSaveData(callback);
-          }, function () {
-            // Is the result is empty the location is not valid or not exits
-            // Call LoadedCustomer to find the customer and location
-            // if not exist show the information and break the process
-            new OB.DS.Request('org.openbravo.retail.posterminal.master.LoadedCustomer').exec({
-              bpartnerId: businessPartner.id,
-              bpLocationId: businessPartner.get('shipLocId')
-            }, function (data) {
-              var bpLoc = OB.Dal.transform(OB.Model.BPLocation, data[1]);
-              OB.Dal.saveIfNew(bpLoc, function () {
-                businessPartner.set('locationModel', bpLoc);
+        }
+
+        var saveBP = function () {
+            if (!businessPartner.get('locId') || !businessPartner.get('shipLocId')) {
+              businessPartner.loadBPLocations(null, null, function (shipping, billing, locations) {
+                businessPartner.set('locationModel', billing);
+                businessPartner.set('locId', billing.get('id'));
+                businessPartner.set('locName', billing.get('name'));
+                businessPartner.set('postalCode', billing.get('postalCode'));
+                businessPartner.set('cityName', billing.get('cityName'));
+                businessPartner.set('countryName', billing.get('countryName'));
+                if (shipping) {
+                  businessPartner.set('shipLocId', shipping.get('id'));
+                  businessPartner.set('shipLocName', shipping.get('name'));
+                  businessPartner.set('shipPostalCode', shipping.get('postalCode'));
+                  businessPartner.set('shipCityName', shipping.get('cityName'));
+                  businessPartner.set('shipCountryName', shipping.get('countryName'));
+                  businessPartner.set('shipRegionId', shipping.get('regionId'));
+                  businessPartner.set('shipCountryId', shipping.get('countryId'));
+                }
+
                 me.set('bp', businessPartner);
                 me.save();
-                // copy the modelOrder again, as the get/save are async
+                // copy the modelOrder again, as saveIfNew is possibly async
                 OB.MobileApp.model.orderList.saveCurrent();
                 finishSaveData(callback);
-              }, function () {
-                OB.error(arguments);
-              });
-            }, function () {
-              OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_InformationTitle'), OB.I18N.getLabel('OBPOS_NoReceiptLoadedLocation'), [{
-                label: OB.I18N.getLabel('OBPOS_LblOk'),
-                isConfirmButton: true
-              }]);
-            });
-          });
-
-        } else {
-          if (businessPartner.get('locationModel')) { //Location has changed or we are assigning current bp
-            OB.Dal.saveIfNew(businessPartner.get('locationModel'), function () {
+              }, businessPartner.get('id'));
+            } else {
               me.set('bp', businessPartner);
               me.save();
               // copy the modelOrder again, as saveIfNew is possibly async
               OB.MobileApp.model.orderList.saveCurrent();
               finishSaveData(callback);
-            }, function () {
-              OB.UTIL.showError('Error removing');
-            });
-          } else {
-            OB.Dal.get(OB.Model.BPLocation, businessPartner.get('shipLocId'), function (location) {
-              OB.Dal.saveIfNew(location, function () {}, function () {
+            }
+            };
+
+        var saveLocModel = function (locModel, lid, callback) {
+            if (businessPartner.get(locModel)) {
+              OB.Dal.saveIfNew(businessPartner.get(locModel), function () {}, function (tx, error) {
+                OB.UTIL.showError("OBDAL error: " + error);
+              });
+              if (callback) {
+                callback();
+              }
+            } else {
+              OB.Dal.get(OB.Model.BPLocation, businessPartner.get(lid), function (location) {
+                OB.Dal.saveIfNew(location, function () {}, function (tx, error) {
+                  OB.UTIL.showError("OBDAL error: " + error);
+                });
+                businessPartner.set(locModel, location);
+                if (callback) {
+                  callback();
+                }
+              }, function () {
                 OB.error(arguments);
               });
-              businessPartner.set('locationModel', location);
-              me.set('bp', businessPartner);
-              me.save();
-            }, function () {
-              OB.error(arguments);
-            });
-          }
+            }
+            };
+
+        saveLocModel('locationModel', 'shipLocId', function () {
+          saveLocModel('locationBillModel', 'locId', function () {
+            saveBP();
+          });
+        });
+
+      } else {
+        if (!businessPartner.get('locId') || !businessPartner.get('shipLocId')) {
+          businessPartner.loadBPLocations(null, null, function (shipping, billing, locations) {
+            businessPartner.set('locationModel', billing);
+            businessPartner.set('locId', billing.get('id'));
+            businessPartner.set('locName', billing.get('name'));
+            businessPartner.set('postalCode', billing.get('postalCode'));
+            businessPartner.set('cityName', billing.get('cityName'));
+            businessPartner.set('countryName', billing.get('countryName'));
+            if (shipping) {
+              businessPartner.set('shipLocId', shipping.get('id'));
+              businessPartner.set('shipLocName', shipping.get('name'));
+              businessPartner.set('shipPostalCode', shipping.get('postalCode'));
+              businessPartner.set('shipCityName', shipping.get('cityName'));
+              businessPartner.set('shipCountryName', shipping.get('countryName'));
+              businessPartner.set('shipRegionId', shipping.get('regionId'));
+              businessPartner.set('shipCountryId', shipping.get('countryId'));
+            }
+            me.set('bp', businessPartner);
+            me.save();
+            finishSaveData(callback);
+          }, businessPartner.get('id'));
+        } else {
+          me.set('bp', businessPartner);
+          me.save();
+          finishSaveData(callback);
         }
-      } else {
-        this.set('bp', businessPartner);
-        this.save();
-        finishSaveData(callback);
       }
     },
 
@@ -4522,8 +4542,10 @@
         _.each(model.receiptPayments, function (receiptPayment) {
           paidByPayments += receiptPayment.amount;
         });
-        if (model.totalamount > 0 && model.totalamount > paidByPayments && !model.isQuotation) {
-          order.set('creditAmount', model.totalamount - paidByPayments);
+
+        var creditAmount = OB.DEC.sub(model.totalamount, paidByPayments);
+        if (OB.DEC.compare(model.totalamount) > 0 && OB.DEC.compare(creditAmount) > 0 && !model.isQuotation) {
+          order.set('creditAmount', creditAmount);
           if (paidByPayments) {
             order.set('paidPartiallyOnCredit', true);
           }
@@ -4539,24 +4561,7 @@
       bpBillLocId = model.bpBillLocId;
       bpId = model.bp;
       var bpartnerForProduct = function (bp) {
-          var locationForBpartner = function (bpLoc) {
-              bp.set('shipLocName', bpLoc.get('name'));
-              bp.set('shipLocId', bpLoc.get('id'));
-              bp.set('locationModel', bpLoc);
-              order.set('bp', bp);
-              order.set('gross', model.totalamount);
-              order.set('net', model.totalNetAmount);
-              OB.Dal.get(OB.Model.BPLocation, bpBillLocId, function (bpLoc) {
-                bp.set('locName', bpLoc.get('name'));
-                bp.set('locId', bpLoc.get('id'));
-                order.trigger('change:bp', order);
-              }, function () {
-                OB.UTIL.showConfirmation.display(OB.I18N.getLabel('OBPOS_InformationTitle'), OB.I18N.getLabel('OBPOS_NoReceiptLoadedLocation'), [{
-                  label: OB.I18N.getLabel('OBPOS_LblOk'),
-                  isConfirmButton: true
-                }]);
-              });
-
+          var loadProducts = function () {
               var linepos = 0,
                   hasDeliveredProducts = false,
                   hasNotDeliveredProducts = false,
@@ -4623,6 +4628,7 @@
                         description: iter.description,
                         priceIncludesTax: order.get('priceIncludesTax'),
                         hasRelatedServices: hasservices,
+                        attributeValue: iter.attributeValue,
                         warehouse: {
                           id: iter.warehouse,
                           warehousename: iter.warehousename
@@ -4644,6 +4650,9 @@
                       numberOfLines--;
                       orderQty = OB.DEC.add(iter.quantity, orderQty);
                       if (numberOfLines === 0) {
+                        lines.reset(lines.sortBy(function (line) {
+                          return line.get('linepos');
+                        }));
                         order.set('lines', lines);
                         order.set('qty', orderQty);
                         order.set('json', JSON.stringify(order.toJSON()));
@@ -4689,24 +4698,6 @@
                 });
                 linepos++;
               });
-              order.set('isPartiallyDelivered', hasDeliveredProducts && hasNotDeliveredProducts ? true : false);
-              if (hasDeliveredProducts && !hasNotDeliveredProducts) {
-                order.set('isFullyDelivered', true);
-              }
-              if (order.get('isPartiallyDelivered')) {
-                var partiallyPaid = 0;
-                _.each(_.filter(order.get('receiptLines'), function (reciptLine) {
-                  return reciptLine.deliveredQuantity;
-                }), function (deliveredLine) {
-                  partiallyPaid += deliveredLine.deliveredQuantity * deliveredLine.unitPrice;
-                });
-                if (partiallyPaid) {
-                  order.set('deliveredQuantityAmount', partiallyPaid);
-                }
-                if (order.get('deliveredQuantityAmount') && order.get('deliveredQuantityAmount') > order.get('gross')) {
-                  order.set('isDeliveredGreaterThanGross', true);
-                }
-              }
 
               function getReverserPayment(payment, Payments) {
                 return _.filter(model.receiptPayments, function (receiptPayment) {
@@ -4765,6 +4756,23 @@
               order.set('payments', payments);
               order.adjustPayment();
 
+              order.set('isPartiallyDelivered', hasDeliveredProducts && hasNotDeliveredProducts ? true : false);
+              if (hasDeliveredProducts && !hasNotDeliveredProducts) {
+                order.set('isFullyDelivered', true);
+              }
+              if (order.get('isPartiallyDelivered')) {
+                var partiallyPaid = 0;
+                _.each(_.filter(order.get('receiptLines'), function (reciptLine) {
+                  return reciptLine.deliveredQuantity;
+                }), function (deliveredLine) {
+                  partiallyPaid = OB.DEC.add(partiallyPaid, OB.DEC.mul(deliveredLine.deliveredQuantity, deliveredLine.grossUnitPrice));
+                });
+                order.set('deliveredQuantityAmount', partiallyPaid);
+                if (order.get('deliveredQuantityAmount') && order.get('deliveredQuantityAmount') > order.get('payment')) {
+                  order.set('isDeliveredGreaterThanGross', true);
+                }
+              }
+
               taxes = {};
               _.each(model.receiptTaxes, function (iter) {
                 var taxProp;
@@ -4786,15 +4794,70 @@
               }
               };
 
-          if (isLoadedPartiallyFromBackend) {
-            locationForBpartner(bpLoc);
+          var locationForBpartner = function (loc, billLoc) {
+              bp.set('shipLocName', loc.get('name'));
+              bp.set('shipLocId', loc.get('id'));
+              bp.set('shipPostalCode', loc.get('postalCode'));
+              bp.set('shipCityName', loc.get('cityName'));
+              bp.set('shipCountryName', loc.get('countryName'));
+              bp.set('shipCountryId', loc.get('countryId'));
+              bp.set('shipRegionId', loc.get('regionId'));
+              if (billLoc) {
+                bp.set('locName', billLoc.get('name'));
+                bp.set('locId', billLoc.get('id'));
+                bp.set('postalCode', billLoc.get('postalCode'));
+                bp.set('cityName', billLoc.get('cityName'));
+                bp.set('countryName', billLoc.get('countryName'));
+                bp.set('locationModel', billLoc);
+              } else {
+                bp.set('locationModel', loc);
+              }
+
+              order.set('bp', bp);
+              order.set('gross', model.totalamount);
+              order.set('net', model.totalNetAmount);
+              order.trigger('change:bp', order);
+              loadProducts();
+              };
+
+          if (bpLocId === bpBillLocId) {
+            if (isLoadedPartiallyFromBackend) {
+              locationForBpartner(bpLoc, bpLoc);
+            } else {
+              OB.Dal.get(OB.Model.BPLocation, bpLocId, function (bpLoc) {
+                locationForBpartner(bpLoc, bpLoc);
+              }, function (tx, error) {
+                OB.UTIL.showError("OBDAL error: " + error);
+              });
+            }
           } else {
-            OB.Dal.get(OB.Model.BPLocation, bpLocId, function (bpLoc) {
-              locationForBpartner(bpLoc);
-            }, function () {
-              // TODO: Report errors properly
+            var criteria = {};
+            if (OB.MobileApp.model.hasPermission('OBPOS_remote.customer', true)) {
+              var remoteCriteria = [{
+                columns: ['id'],
+                operator: 'equals',
+                value: [bpLocId, bpBillLocId]
+              }];
+              criteria.remoteFilters = remoteCriteria;
+            } else {
+              criteria._whereClause = "where c_bpartner_location_id in (?, ?)";
+              criteria.params = [bpLocId, bpBillLocId];
+            }
+            OB.Dal.find(OB.Model.BPLocation, criteria, function (locations) {
+              var loc, billLoc;
+              _.each(locations.models, function (l) {
+                if (l.id === bpLocId) {
+                  loc = l;
+                } else if (l.id === bpBillLocId) {
+                  billLoc = l;
+                }
+              });
+              locationForBpartner(loc, billLoc);
+            }, function (tx, error) {
+              OB.UTIL.showError("OBDAL error: " + error);
             });
           }
+
           };
       OB.Dal.get(OB.Model.BusinessPartner, bpId, function (bp) {
         bpartnerForProduct(bp);
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
@@ -233,6 +233,10 @@
                 me.customer.set('shipCountryName', customerAddr.get('countryName'));
               }
               me.customer.set('locationModel', customerAddr);
+              //If it an js object, convert in a BPLocation
+              if (me.customer.get('locationBillModel') && !me.customer.get('locationBillModel').get) {
+                me.customer.set('locationBillModel', new OB.Model.BPLocation(me.customer.get('locationBillModel')));
+              }
               if (me.model.get('orderList').length > 1) {
                 for (i = 0; i < me.model.get('orderList').length; i++) {
                   if (me.model.get('orderList').models[i].get('bp').get('id') === me.customer.get('id')) {
@@ -252,6 +256,7 @@
             };
 
         getCustomerAddrValues({
+          customer: me.customer,
           customerAddr: customerAddr
         });
 
