Merge branch '4_7_x' of https://github.com/xtuple/xtuple into i24559_xtlocks
authorGil Moskowitz <gmoskowitz@xtuple.com>
Wed, 17 Sep 2014 21:10:31 +0000 (17:10 -0400)
committerGil Moskowitz <gmoskowitz@xtuple.com>
Wed, 17 Sep 2014 21:10:31 +0000 (17:10 -0400)
and change language of wipe_views to allow building a database

Conflicts:
enyo-client/database/source/delete_system_orms.sql

18 files changed:
.travis.yml
enyo-client/database/source/delete_system_orms.sql
enyo-client/database/source/wipe_views.sql [new file with mode: 0644]
enyo-client/database/source/xt/functions/cust_outstanding_credit.sql
enyo-client/extensions/source/billing/database/source/xt/tables/rptdef.sql
enyo-client/extensions/source/oauth2/client/en/strings.js
foundation-database/public/functions/convertquote.sql
foundation-database/public/functions/createpurchasetosale.sql
foundation-database/public/tables/bankrecimport.sql
foundation-database/public/tables/metasql/bookings-detail.mql
node-datasource/routes/app.js
node-datasource/routes/auth.js
node-datasource/routes/generate_oauth_key.js
npm-shrinkwrap.json
package.json
scripts/lib/build_database.js
scripts/lib/util/process_manifest.js
test/specs/invoice.js

index 10dcc2b..564ef54 100644 (file)
@@ -15,7 +15,3 @@ script:
   - "npm run-script test-datasource"
   - "npm run-script test"
   - "npm run-script jshint"
-
-  # test an upgrade from 4.4.0
-  - "wget http://sourceforge.net/projects/postbooks/files/03%20PostBooks-databases/4.4.0/postbooks_demo-4.4.0.backup"
-  - "./scripts/build_app.js -d upgrade_test -i -b ./postbooks_demo-4.4.0.backup"
index 36cd79b..66ea976 100644 (file)
@@ -2,21 +2,7 @@ do $$
  /* Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
     See www.xtuple.com/CPAL for the full text of the software license. */
 
-  var result,
-    viewname,
-    schemaname,
-    i,
-    sql = "select schemaname, viewname " +
-          "from pg_views " +
-          "where schemaname in ('xm','sys', 'xt');";
-
-  result = plv8.execute(sql);
-  for (i = 0; i < result.length; i++) {
-    viewname = result[i].viewname;
-    schemaname = result[i].schemaname;
-    plv8.execute('drop view if exists ' + schemaname + '.' + viewname + ' cascade;');
-  }
-
+  plv8.execute("select xt.js_init();");
   plv8.execute("alter table xt.orm disable trigger orm_did_change;");
   plv8.execute("delete from xt.orm where orm_json ~ '\"isSystem\":true';");
   plv8.execute("alter table xt.orm enable trigger orm_did_change;");
diff --git a/enyo-client/database/source/wipe_views.sql b/enyo-client/database/source/wipe_views.sql
new file mode 100644 (file)
index 0000000..b921575
--- /dev/null
@@ -0,0 +1,16 @@
+do $$
+ /* Copyright (c) 1999-2014 by OpenMFG LLC, d/b/a xTuple.
+     See www.xm.ple.com/CPAL for the full text of the software license. */
+declare
+  sqlstring text;
+begin
+  select string_agg('drop view ' || t.oid::regclass || ';', ' ') into sqlstring
+    from pg_class t
+    join pg_namespace n on n.oid = relnamespace
+   where relkind = 'v'
+     and nspname in ('xm','sys', 'xt');
+  if length(sqlstring) > 0 then
+    execute sqlstring;
+  end if;
+end
+$$;
index fa626f8..6aa15db 100644 (file)
@@ -18,7 +18,7 @@ from (
   where aropen_cust_id = $1
   and aropen_open
   --and aropen_posted = false
-  group by aropen_id
+  group by aropen_id, aropen_cust_id, aropen_curr_id, aropen_amount
 ) unalloc;
 
 $$ language sql;
index ecd07aa..938c9d3 100644 (file)
@@ -1,4 +1,4 @@
-select xt.add_report_definition('XM.Invoice', 0, $${
+select xt.add_report_definition('XM.Invoice', 0, $${
   "settings": {
     "detailAttribute": "lineItems",
     "defaultFontSize": 12,
@@ -151,12 +151,31 @@ select xt.add_report_definition('XM.Invoice', 0, $${
     },
     {"element": "bandLine", "size": 2},
     {
+      "element": "band",
       "definition": [
-        {"attr": "subtotal", "label": true},
-        {"attr": "taxTotal", "label": true},
-        {"attr": "total", "label": true}
+        {"text": "_subtotal", "label": true, "width": 70, "align": "left"},
+        {"attr": "subtotal", "width": 100, "align": "right"}
       ],
-      "options": {"width": 525, "align": "right"}
+      "options": {"border": 0, "x": 360}
+    },
+    {
+      "element": "band",
+      "definition": [
+        {"text": "_taxTotal", "label": true, "width": 70, "align": "left"},
+        {"attr": "taxTotal", "width": 100, "align": "right"}
+      ],
+      "options": {"border": 0, "x": 360}
+    },
+    {
+      "element": "band",
+      "definition": [
+        {"text": "_total", "label": true, "width": 70, "align": "left"},
+        {"attr": "total", "width": 100, "align": "right"}
+      ],
+      "options": {"border": 0, "x": 360}
+    },
+    {
+      "definition": []
     }
   ],
   "pageFooterElements": [
index 56c2a22..fc5d4e3 100644 (file)
@@ -18,7 +18,8 @@ strict:true, trailing:true, white:true */
     "_fullListUrl": "Full List URL",
     "_generatingPrivateKey": "A new keypair will be generated for this OAUTH2 client. " +
       "The public key will be available in the future with this client. The private key " +
-      "is only available now as a one-time download.",
+      "is only available now as a one-time download. Note that this process can take up " +
+      "to a minute. Please wait until the key is downloaded.",
     "_logoURL": "Logo URL",
     "_maintainOauth2clients": "Maintain OAUTH2 Clients",
     "_oauth2": "OAUTH2",
index e26484e..c9d7759 100644 (file)
@@ -252,8 +252,10 @@ BEGIN
     IF (_r.quitem_createorder) THEN
 
       IF (_r.item_type IN ('M')) THEN
-        SELECT createWo( CAST(_r.quhead_number AS INTEGER), supply.itemsite_id, 1, (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
-                         _r.itemsite_leadtime, _r.quitem_scheddate, _r.quitem_memo, 'S', _soitemid, _r.quhead_prj_id ) INTO _orderId
+        SELECT createWo( CAST(_soNum AS INTEGER), supply.itemsite_id, 1,
+                         (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
+                         _r.itemsite_leadtime, _r.quitem_scheddate, _r.quitem_memo,
+                         'S', _soitemid, _r.quhead_prj_id ) INTO _orderId
         FROM itemsite sold, itemsite supply
         WHERE ((sold.itemsite_item_id=supply.itemsite_item_id)
          AND (supply.itemsite_warehous_id=_r.quitem_order_warehous_id)
@@ -268,7 +270,8 @@ BEGIN
            AND  (charass_target_id=_r.quitem_id));
 
       ELSIF ( (_r.item_type IN ('P', 'O')) AND (_r.itemsite_createsopr) ) THEN
-        SELECT createPr( CAST(_r.quhead_number AS INTEGER), _r.quitem_itemsite_id, (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
+        SELECT createPr( CAST(_soNum AS INTEGER), _r.quitem_itemsite_id,
+                         (_r.quitem_qtyord * _r.quitem_qty_invuomratio),
                          _r.quitem_scheddate, '', 'S', _soitemid ) INTO _orderId;
         _orderType := 'R';
         UPDATE pr SET pr_prj_id=_r.quhead_prj_id WHERE pr_id=_orderId;
index d52a6ea..31d3ac7 100644 (file)
@@ -15,7 +15,7 @@ BEGIN
   RETURN createPurchaseToSale(pCoitemId, pItemSourceId, pDropShip, NULL, NULL, NULL);
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
 
 CREATE OR REPLACE FUNCTION createPurchaseToSale(INTEGER, INTEGER, BOOLEAN, NUMERIC) RETURNS INTEGER AS $$
@@ -32,7 +32,7 @@ BEGIN
   RETURN createPurchaseToSale(pCoitemId, pItemSourceId, pDropShip, NULL, NULL, pPrice);
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
 
 CREATE OR REPLACE FUNCTION createPurchaseToSale(INTEGER, INTEGER, BOOLEAN, NUMERIC, DATE, NUMERIC) RETURNS INTEGER AS $$
@@ -51,7 +51,7 @@ BEGIN
   RETURN createPurchaseToSale(pCoitemId, pItemSourceId, pDropShip, pQty, pDueDate, pPrice, NULL);
 
 END;
-$$ LANGUAGE 'plpgsql';
+$$ LANGUAGE plpgsql;
 
 
 CREATE OR REPLACE FUNCTION createPurchaseToSale(INTEGER, INTEGER, BOOLEAN, NUMERIC, DATE, NUMERIC, INTEGER) RETURNS INTEGER AS $$
@@ -126,27 +126,27 @@ BEGIN
     FROM pohead
     WHERE ( (pohead_status = 'U')
       AND (pohead_vend_id = _i.itemsrc_vend_id)
-      AND (pohead_shiptoname = COALESCE(_s.cohead_shiptoname, _s.shipto_name, ''))
-      AND (pohead_shiptoaddress1 = COALESCE(_s.cohead_shiptoaddress1, _s.addr_line1, ''))
-      AND (pohead_shiptoaddress2 = COALESCE(_s.cohead_shiptoaddress2, _s.addr_line2, ''))
-      AND (pohead_shiptoaddress3 = COALESCE(_s.cohead_shiptoaddress3, _s.addr_line3, ''))
-      AND (pohead_shiptocity = COALESCE(_s.cohead_shiptocity, _s.addr_city, ''))
-      AND (pohead_shiptostate = COALESCE(_s.cohead_shiptostate, _s.addr_state, ''))
-      AND (pohead_shiptozipcode = COALESCE(_s.cohead_shiptozipcode, _s.addr_postalcode, ''))
-      AND (pohead_shiptocountry = COALESCE(_s.cohead_shiptocountry, _s.addr_country, ''))
+      AND (COALESCE(pohead_shiptoname, '') = COALESCE(_s.cohead_shiptoname, _s.shipto_name, ''))
+      AND (COALESCE(pohead_shiptoaddress1, '') = COALESCE(_s.cohead_shiptoaddress1, _s.addr_line1, ''))
+      AND (COALESCE(pohead_shiptoaddress2, '') = COALESCE(_s.cohead_shiptoaddress2, _s.addr_line2, ''))
+      AND (COALESCE(pohead_shiptoaddress3, '') = COALESCE(_s.cohead_shiptoaddress3, _s.addr_line3, ''))
+      AND (COALESCE(pohead_shiptocity, '') = COALESCE(_s.cohead_shiptocity, _s.addr_city, ''))
+      AND (COALESCE(pohead_shiptostate, '') = COALESCE(_s.cohead_shiptostate, _s.addr_state, ''))
+      AND (COALESCE(pohead_shiptozipcode, '') = COALESCE(_s.cohead_shiptozipcode, _s.addr_postalcode, ''))
+      AND (COALESCE(pohead_shiptocountry, '') = COALESCE(_s.cohead_shiptocountry, _s.addr_country, ''))
       AND ((pohead_id=pPoheadId) OR (pPoheadid IS NULL)) );
   ELSE
     SELECT COALESCE(pohead_id, -1) INTO _temp
     FROM pohead
     WHERE ( (pohead_status = 'U')
       AND (pohead_vend_id = _i.itemsrc_vend_id)
-      AND (pohead_shiptoaddress1 = COALESCE(_w.addr_line1, ''))
-      AND (pohead_shiptoaddress2 = COALESCE(_w.addr_line2, ''))
-      AND (pohead_shiptoaddress3 = COALESCE(_w.addr_line3, ''))
-      AND (pohead_shiptocity = COALESCE(_w.addr_city, ''))
-      AND (pohead_shiptostate = COALESCE(_w.addr_state, ''))
-      AND (pohead_shiptozipcode = COALESCE(_w.addr_postalcode, ''))
-      AND (pohead_shiptocountry = COALESCE(_w.addr_country, ''))
+      AND (COALESCE(pohead_shiptoaddress1, '') = COALESCE(_w.addr_line1, ''))
+      AND (COALESCE(pohead_shiptoaddress2, '') = COALESCE(_w.addr_line2, ''))
+      AND (COALESCE(pohead_shiptoaddress3, '') = COALESCE(_w.addr_line3, ''))
+      AND (COALESCE(pohead_shiptocity, '') = COALESCE(_w.addr_city, ''))
+      AND (COALESCE(pohead_shiptostate, '') = COALESCE(_w.addr_state, ''))
+      AND (COALESCE(pohead_shiptozipcode, '') = COALESCE(_w.addr_postalcode, ''))
+      AND (COALESCE(pohead_shiptocountry, '') = COALESCE(_w.addr_country, ''))
       AND ((pohead_id=pPoheadId) OR (pPoheadid IS NULL)) );
   END IF;
 
@@ -364,4 +364,4 @@ BEGIN
   RETURN _poitemid;
 
 END;
-$$ LANGUAGE 'plpgsql' VOLATILE;
+$$ LANGUAGE plpgsql VOLATILE;
index de1fc7c..c9c74c4 100644 (file)
@@ -1,9 +1,9 @@
 select xt.create_table('bankrecimport', 'public');
 select xt.add_column('bankrecimport','bankrecimport_id', 'SERIAL', 'PRIMARY KEY', 'public');
-select xt.add_column('bankrecimport','bankrecimport_reference', 'TEXT', 'NOT NULL', 'public');
-select xt.add_column('bankrecimport','bankrecimport_descrip', 'TEXT', 'NOT NULL', 'public');
-select xt.add_column('bankrecimport','bankrecimport_comment', 'TEXT', 'NOT NULL', 'public');
-select xt.add_column('bankrecimport','bankrecimport_debit_amount', 'NUMERIC', 'NOT NULL', 'public');
-select xt.add_column('bankrecimport','bankrecimport_credit_amount', 'NUMERIC', 'NOT NULL', 'public');
-select xt.add_column('bankrecimport','bankrecimport_effdate', 'DATE', 'NOT NULL', 'public');
-select xt.add_column('bankrecimport','bankrecimport_curr_rate', 'NUMERIC', 'NOT NULL', 'public');
+select xt.add_column('bankrecimport','bankrecimport_reference', 'TEXT', NULL, 'public');
+select xt.add_column('bankrecimport','bankrecimport_descrip', 'TEXT', NULL, 'public');
+select xt.add_column('bankrecimport','bankrecimport_comment', 'TEXT', NULL, 'public');
+select xt.add_column('bankrecimport','bankrecimport_debit_amount', 'NUMERIC', NULL, 'public');
+select xt.add_column('bankrecimport','bankrecimport_credit_amount', 'NUMERIC', NULL, 'public');
+select xt.add_column('bankrecimport','bankrecimport_effdate', 'DATE', NULL, 'public');
+select xt.add_column('bankrecimport','bankrecimport_curr_rate', 'NUMERIC', NULL, 'public');
index 28a6f08..b8b5bf4 100644 (file)
@@ -31,18 +31,11 @@ SELECT   coitem_id AS id, coitem_cohead_id AS altId,
                      (currtobase(cohead_curr_id, coitem_price, cohead_orderdate) / coitem_price_invuomratio), 2) AS baseextpricebalance,
          round((coitem_qtyord * coitem_qty_invuomratio) *
                      (coitem_unitcost / coitem_price_invuomratio), 2) AS extcost,
-         (round((coitem_qtyord * coitem_qty_invuomratio) *
-                     (currtobase(cohead_curr_id, coitem_price, cohead_orderdate) / coitem_price_invuomratio), 2) -
-          round((coitem_qtyord * coitem_qty_invuomratio) *
-                     (coitem_unitcost / coitem_price_invuomratio), 2)) AS margin,
-         CASE WHEN (coitem_price > 0.0) THEN
-           (round((coitem_qtyord * coitem_qty_invuomratio) *
-                       (currtobase(cohead_curr_id, coitem_price, cohead_orderdate) / coitem_price_invuomratio), 2) -
-            round((coitem_qtyord * coitem_qty_invuomratio) *
-                       (coitem_unitcost / coitem_price_invuomratio), 2)) /
-            round((coitem_qtyord * coitem_qty_invuomratio) *
-                       (currtobase(cohead_curr_id, coitem_price, cohead_orderdate) / coitem_price_invuomratio), 2)
-              ELSE 0.0
+         CASE WHEN (coitem_price = 0.0) THEN 0.0
+              ELSE ROUND(coitem_qtyord * coitem_qty_invuomratio * (coitem_price - coitem_unitcost) / coitem_price_invuomratio,2)
+         END AS margin,
+         CASE WHEN (coitem_price = 0.0) THEN 0.0
+              ELSE ((coitem_price - coitem_unitcost) / coitem_price)
          END AS marginpercent,
          curr_abbr AS currAbbr,
 -- TODO - not needed, remove? (very slow)
index e083ee8..4ddcdd6 100644 (file)
@@ -103,6 +103,15 @@ var async = require("async"),
       },
       fetchSuccess = function (model, result) {
         var sendExtensions = function (res, extensions) {
+          var filteredExtensions;
+          if (req.query.extensions) {
+            // the user is requesting to only see a certain set of extensions
+            filteredExtensions = JSON.parse(req.query.extensions);
+            extensions = extensions.filter(function (ext) {
+              return _.contains(filteredExtensions, ext.name);
+            });
+          }
+
           extensions.sort(function (ext1, ext2) {
             if (ext1.loadOrder !== ext2.loadOrder) {
               return ext1.loadOrder - ext2.loadOrder;
index 28e5504..fea2dc7 100644 (file)
@@ -21,6 +21,9 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     function (req, res, next) {
       var pathName = "/app";
       if (req && req.session && !req.session.oauth2 && req.session.passport && req.session.passport.user && req.session.passport.user.organization) {
+        if (req.body.extensions) {
+          pathName = pathName + "?extensions=" + req.body.extensions;
+        }
         if (req.body.hash && req.body.hash.charAt(0) === "#") {
           pathName = pathName + req.body.hash;
         }
index b4c69d5..16858d8 100644 (file)
@@ -7,8 +7,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
 (function () {
   "use strict";
 
-  var ursa = require("ursa"),
-    exec = require("child_process").exec,
+  var exec = require("child_process").exec,
     forge = require("node-forge"),
     spawn = require("child_process").spawn,
     async = require("async"),
@@ -29,10 +28,7 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
         res.send({isError: true, error: err});
       },
       genKey = function (model, result) {
-        /**
-          * This is REALLY slow in pure javascript. ursa is much faster.
-          * @See: https://github.com/digitalbazaar/forge/issues/125
-        forge.pki.rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
+        forge.pki.rsa.generateKeyPair({bits: 2048, workers: -1}, function (err, keypair) {
           if (err) {
             res.send({isError: true, message: "Error generating keypair: " + err.message, error: err});
             return;
@@ -40,16 +36,6 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
 
           fetchSuccess(model, result, keypair);
         });
-        */
-
-        // Use ursa for the key gen and then convert to forge's format.
-        var keypair = ursa.generatePrivateKey();
-        var keys = {
-          privateKey: forge.pki.privateKeyFromPem(keypair.toPrivatePem().toString()),
-          publicKey: forge.pki.publicKeyFromPem(keypair.toPublicPem().toString())
-        };
-
-        fetchSuccess(model, result, keys);
       },
       sendP12 = function (keys) {
         // It's possible and much easier to generate the p12 file without a
index 8feddec..3762709 100644 (file)
       "version": "2.3.3",
       "from": "underscore.string@~2.3.3"
     },
-    "ursa": {
-      "version": "0.8.0",
-      "from": "ursa@0.8.x"
-    },
     "winston": {
       "version": "0.7.3",
       "from": "winston@0.7.x",
       }
     },
     "xtuple-linguist": {
-      "version": "0.1.0",
+      "version": "0.1.1",
       "from": "xtuple-linguist@0.1.x"
     },
     "xtuple-query": {
index fe76483..88d940f 100644 (file)
@@ -43,7 +43,6 @@
     "underscore": "1.4.x",
     "winston": "0.7.x",
     "underscore.string": "~2.3.3",
-    "ursa": "0.8.x",
     "xtuple-linguist": "0.1.x",
     "jquery": "~2.1.1"
   },
index c0446c0..8ae4296 100644 (file)
@@ -89,7 +89,8 @@ var  async = require('async'),
               baseName.indexOf('distribution') >= 0,
             registerExtension: isExtension,
             runJsInit: !isFoundation && !isLibOrm,
-            wipeViews: isApplicationCore && spec.wipeViews,
+            wipeViews: isFoundation && spec.wipeViews,
+            wipeOrms: isApplicationCore && spec.wipeViews,
             extensionLocation: isCoreExtension ? "/core-extensions" :
               isPublicExtension ? "/xtuple-extensions" :
               isPrivateExtension ? "/private-extensions" :
index 90f6030..44ed46a 100644 (file)
@@ -56,6 +56,19 @@ regexp:true, undef:true, strict:true, trailing:true, white:true */
     }
 
     if (options.wipeViews) {
+      // If we want to pre-emptively wipe out the views, the best place to do it
+      // is at the start of the core application code
+      fs.readFile(path.join(__dirname, "../../../enyo-client/database/source/wipe_views.sql"),
+          function (err, wipeSql) {
+        if (err) {
+          callback(err);
+          return;
+        }
+        extensionSql = wipeSql + extensionSql;
+        callback(null, extensionSql);
+      });
+
+    } else if (options.wipeOrms) {
       // If we want to pre-emptively wipe out the views, the best place to do it
       // is at the start of the core application code
       fs.readFile(path.join(__dirname, "../../../enyo-client/database/source/delete_system_orms.sql"),
index e674090..0a43b8e 100644 (file)
@@ -864,9 +864,9 @@ TODO deferred to later sprint:
         @description When currency or invoice date is changed outstanding credit should be
           recalculated.
       */
-      it.skip("When currency or invoice date is changed outstanding credit should be recalculated",
+      it.("When currency or invoice date is changed outstanding credit should be recalculated",
           function (done) {
-        // frustratingly nondeterministic
+
         this.timeout(9000);
         var outstandingCreditChanged = function () {
           if (invoiceModel.get("outstandingCredit")) {